/* Various sequence classes.  This is -*- C++ -*- code.
   Copyright (C) 1992 Per Bothner.

This file is part of Q.

Q is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

Q is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#ifndef GENMAP_H
/*#pragma once*/
#pragma interface
#define GENMAP_H
#include "types.h"
#include <newtype.h>
#include "gennum.h"

#define InfiniteLength ((size_t)(-1)) // Should be ULONG_MAX?
#define UnknownLength ((size_t)(-2))

inline int KnownLength(size_t len) { return len < UnknownLength; }

class GenFile; class MapFile; class BinOp; class MemoSeq;
class Generator;

class SubSeq : public GenSeq {
  public:
    GenSeq *seq;
    index_t start, end;
    SubSeq(GenSeq *q, index_t st, index_t e);
    virtual GenSeq *subseq(index_t start, index_t end);
    virtual size_t length();
    virtual Root * index(index_t i);

    virtual int sizeof_file() const;
    virtual void open(GenFile*, OpenFlags flags=0);
};

class CharSubSeq : public CharSeq {
    CharSeq *seq;
    index_t start, end;
  public:
    CharSubSeq(CharSeq *q, index_t st, index_t e);
    virtual GenSeq *subseq(index_t start, index_t end);
    virtual size_t length();
    virtual Root * index(index_t i);
};

class AList : public GenSeq {
    DECLARE_MEMBERS(AList)
  public:
    MARK((gcpointer(car), gcpointer(cdr)))
    Root *car;
    Root *cdr;
    AList(Root *first, Root *rest) { car = first; cdr = rest; }
    virtual Root * index(index_t index);
    virtual size_t length();
    virtual void printBare(ostream&) const;
    virtual int null() { return 0; }
    virtual void printon(ostream &) const;
    virtual int sizeof_file() const;
    virtual void open(GenFile*, OpenFlags flags=0);
};

class ConsPair : public AList { // Same as AList, but updatable
    DECLARE_MEMBERS(ConsPair)
  public:
    ConsPair(Root *first, Root *rest) : AList(first, rest) { }
//    virtual Root * index(index_t index);
};

class OArray : public GenSeq {
 public:
    size_t len;
    Root **first;
    OArray(size_t l, Root**f);
    virtual size_t length() { return len; }
    virtual Root * index(index_t i);
    virtual GenSeq *subseq(index_t start, index_t end);
    Root ** start_addr() const { return first; }
    inline size_t leng() const { return len; }
};

class IndexedSeq : public GenSeq {
  public:
    GenSeq *base;
    GenSeq *indexes;
    ArgDesc args;
    IndexedSeq(GenSeq *b, GenSeq *i, ArgDesc& a);
    virtual size_t length();
    virtual Root * index(index_t i);
    virtual void assign(Root *new_value);
};

#if 0
class IndexedCharSeq : public IndexedSeq { // or: public CharSeq
};
#endif

class Vector : public GenSeq {
    DECLARE_MEMBERS(Vector)
  public:
    MARK(({ int i = len; Root**ptr=start_addr();
	    while (--i >= 0) gcpointer(*ptr++);}))
    /*const*/ size_t len;
    Vector(size_t l) : len(l) { }
    Root ** start_addr() const { return (Root**)(this+1); }
    // Root * data[len};
    virtual size_t length() { return len; }
    virtual Root * index(index_t i);
    virtual void printon(ostream &) const;
    inline size_t leng() const { return len; }
    virtual void dumpPtr(CFile *cf) const;
    virtual void assign(Root *new_value);
};

class VectorV : public Vector { // Same as Vector, but updatable
    DECLARE_MEMBERS(VectorV)
    VectorV(size_t l) : Vector(l) { }
//    virtual Root * index(index_t i);
    virtual void set_at(index_t index, Root *new_value);
    virtual void assign(Root *new_value);
};

extern Vector * NewVector(size_t size);
extern VectorV * NewVectorV(size_t size);
extern Vector * NewVector(size_t size, Root **vals);
extern Root *Copy2Vector(GenSeq* inits, long length, Root* fill);

class BitVector : public GenSeq {
  public:
    const size_t len;
    BitVector(size_t l) : len(l) { }
    fix_unsigned * start_addr() const { return (fix_unsigned*)(this+1); }
    // fix_unsigned data[ceil(len/BN_DIGIT_LEN)]};
    virtual size_t length() { return len; }
    size_t nwords();
    virtual Root * index(index_t i);
    virtual void printon(ostream &) const;
    static BitVector* New(size_t size);
};

struct dimension_descriptor {
    size_t dimension;
    long stride;
};

#if 0
class DArray : public GenSeq {
  public:
    Vector *_base;
    short _rank; short _flags;
    long _offset;
    struct dimension_descriptor _dimensions[0]; // Actually: rank

    virtual size_t length() { return dimensions[0].dimension; }
};

class DVector : public GenSeq { // Displaced Vector
  public:
    /*const*/ size_t len;
    Vector *_base;
    size_t _offset; // first element in _base
    size_t fill_pointer;
    int adjustable() { ? }
};

#endif

struct DimInfo {
    index_t stride;
    size_t length;
};

#define ArrayIsAdjustable 1
class MArray : public GenSeq {
  public:
    GenArray *_base;
    fix_int _offset;
    unsigned short misc_flags;
    const short _rank;
//    size_t *lengths;
//    index_t *strides;
    DimInfo dim[0]; // Actually: dim[_rank]
    static MArray* New(int d, GenArray *b, long offset,
		      size_t *st = NULL, index_t*st = NULL);
    static MArray* New(int d, GenArray *b, long offset, DimInfo *);
    MArray(int d, GenArray *b, long offset, size_t *ls=NULL, index_t *st=NULL);
    MArray(int d, GenArray *b, long offset, DimInfo *d);
    virtual int rank() const { return _rank; }
    virtual size_t length() { return dim[0].length; }
    virtual Root * index(index_t i);
    virtual void set_at(index_t index, Root *new_value);
    virtual void printon(ostream &) const;
    virtual void printBare(ostream&) const;
    virtual size_t dimension(int axis) { return dim[axis].length; }
    virtual Root* row_major_index(fix_int ind);
    virtual void assign(Root *new_value);
};

extern size_t CalculateSize(int rank, DimInfo *dims);
extern void AssignArray(MArray *m, int level, index_t offset,
			Root *new_value, int diff_len_ok);

class GenRecur : public GenSeq {
    DECLARE_MEMBERS(GenRecur)
  public:
    Type *elType;
    void *first;
    size_t len;
    inline Type* el_type() const { return elType; }
    virtual void stepper(void* _old, void *_new, int count = 1) const = 0;
    virtual size_t length() { return len; }
    virtual Root *index(index_t i);
//    virtual GenSeq *subseq(int drop, size_t length);
//    virtual GenFile * open(long flags=0)const;
};

class Range : public GenRecur {
    DECLARE_MEMBERS(Range)
  public:
    int step;
    virtual void stepper(void* _old, void *_new, int count = 1) const;
    Range(void_int f) { first = IntToVoid(f); step = 1; len = InfiniteLength; }
    Range(void_int f, size_t l) { first = IntToVoid(f); step = 1; len = l; }
    Range(void_int f, int s, size_t l) {first= IntToVoid(f); step= s; len = l;}
    virtual Root * index(index_t i);
    virtual GenSeq *subseq(index_t start, index_t end);
    inline index_t ilower() const { return VoidToInt(first); }
    inline index_t istep() const { return step; }
    inline index_t iupper() const { return VoidToInt(first) + (len-1)*step; }
    virtual void printon(ostream&) const;
};

class Recurrence : public GenRecur {
  public:
    Root* initial;
    Functional* step_func;
    Recurrence(Root* i0, Functional* st);
    virtual void stepper(void* _old, void *_new, int count = 1) const;
    virtual GenSeq *subseq(index_t start, index_t end);
    virtual void printon(ostream &) const;
};

class GenRange : public GenRecur {
  public:
    const Root* initial;
    fix_int step;
    GenRange(const Root* i0, fix_int st);
    virtual void stepper(void* _old, void *_new, int count = 1) const;
    virtual GenSeq *subseq(index_t start, index_t end);
    virtual void printon(ostream&) const;
};

class ConstSeq : public GenSeq {
  public:
    Root *val;
    ConstSeq(Root *v) { val = v; }
    virtual size_t length() { return InfiniteLength; }
    virtual Root * index(index_t i) { return val; }
};

class WhileSeq : public GenSeq {
  public:
    GenSeq *elements;
    GenSeq *conds;
    size_t tested; // Initially 0
    size_t limit; // Initially InfiniteLength
    virtual size_t length();
    virtual Root * index(index_t i);
    WhileSeq(GenSeq *e, GenSeq *c) {
	elements = e; conds = c;
	tested = 0; limit = InfiniteLength; }
    virtual int sizeof_file() const;
    virtual void open(GenFile*, OpenFlags flags=0);
};

// Result of: 'SEQ while PRED' (when PRED is not a sequence).

class WhileSeqPred : public WhileSeq {
  public:
    ConstSeq pred_seq;
    Root *pred() { return pred_seq.val; }
    WhileSeqPred(GenSeq *e, Root *p) : pred_seq(p), WhileSeq(e, &pred_seq) { }
};

// Represents the unary operator: >= Y.

class GreaterEqualUnary : public Functional {
  public:
    Root *arg2;
    virtual Root *postfix(Root *arg1);
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
    GreaterEqualUnary(Root *a) : arg2(a) { }
};

// Represents the unary operator: <= Y.

class LessEqualUnary : public Functional {
  public:
    Root *arg2;
    virtual Root *postfix(Root *arg1);
    virtual void xapply(void* dst, Type* dstType, ArgDesc&);
    LessEqualUnary(Root *a) : arg2(a) { }
};

class UptoSeq : public WhileSeqPred {
  public:
    LessEqualUnary pred1;
    Root *upper() { return pred1.arg2; }
    UptoSeq(GenSeq *e, Root *limit) : pred1(limit), WhileSeqPred(e, &pred1) {}
};

class DowntoSeq : public WhileSeqPred {
  public:
    GreaterEqualUnary pred1;
    Root *upper() { return pred1.arg2; }
    DowntoSeq(GenSeq *e, Root *limit) : pred1(limit),WhileSeqPred(e,&pred1) {}
};

class UntilSeq : public WhileSeq {
  public:
    virtual Root * index(index_t i);
    UntilSeq(GenSeq *e, GenSeq *c) : WhileSeq(e, c) { }
    virtual void open(GenFile*, OpenFlags flags=0);
};

class WhereSeq : public GenSeq {
    // Invariants:
    // elements->(i) has been called for all i: 0<=i<next_to_try,
    // and the indexes of the selected ones entered into the indexes table.
    // elements->index(lookup(i)) is the i'the element of the result,
    // for i < upper_index.
    index_t *indexes;
    index_t& lookup(size_t i) { return indexes[i]; }
    size_t next_to_try;
    size_t allocated; // Allocated size of lookup.
    size_t upper_index;
    int eof_seen;
  public:
    GenSeq *elements;
    GenSeq *conds;
    virtual size_t length();
    virtual Root * index(index_t i);
    WhereSeq(GenSeq *e, GenSeq *c);
};

struct Clause; struct Function;
class MapSeq : public GenSeq {
    Clause *clause;
    Function* function;
    Root *env;
    Root** arg_list;
    int lCount, rCount, nCount;
    Symbol** names;
    signed char *arg_is_sequence; // For each arg: 1:seq; -1:scalar: 0:unknown
  public:
    MapSeq(Clause* cl, Function* fun, Root* en, ArgDesc& args);
    virtual Root * index(index_t i);
    virtual size_t length();
};

class BinOpSeq : public GenSeq {
  public:
    Root *left;
    Root *right;
    BinOp *op;
    char leftIsSeq;
    char rightIsSeq;
    BinOpSeq(BinOp *o, Root *l, Root *r, int lq, int rq)
      { op = o; left = l; right = r; leftIsSeq = lq; rightIsSeq = rq; }
    virtual size_t length();
    virtual Root * index(index_t i);
//    virtual GenSeq *subseq(int drop, size_t length);
//    virtual GenFile * open(long flags=0) const;
};

class Cyclic : public GenSeq {
  GenSeq *_finite_part, *_cycle_part;
public:
  Cyclic(GenSeq *f, GenSeq *c) 
  : _finite_part(f), _cycle_part(c) {}
  virtual size_t _cycle_length(int);
  virtual size_t length();
  virtual Root * index(index_t i);
  virtual GenSeq *subseq(index_t start, index_t end);
  inline finite_length() { return _finite_part->length(); }
  inline cycle_length() { return _cycle_part->length(); }
  inline GenSeq* finite_part() { return _finite_part; }
  inline GenSeq* cycle_part() { return _cycle_part; }
};

extern RecordType* GetMemoSeqType();
extern fix_int Coerce2Fix(Root *val);
const StringC * Coerce2String(Root *arg);
extern GenSeq *Coerce2Sequence(Root *arg);

extern Vector NullSequence;
extern GenRange IndexSequence;

inline StringC ** StringsPtr(StringList *s)
{ return (StringC**)s->start_addr(); }
inline size_t StringsCount(StringList *s) { return s->leng(); }
inline size_t StringsLen(StringList *s) { return s->leng(); }

extern void PrintQuotedString(const char *str, int len, ostream&);
extern void PrintQuotedInterior(const char *str, int len, ostream&);

// Coerce 'arg' to a string, returning a (char*)pointing to its characters.
// If lenp is non-NULL, set it to the strings length.
// If stringp is non-NULL, optionally set it to a StringC
// that equals the result.
// *stringp is set to NULL if the resulting string is generated
// by "printing" arg.  In that case, the caller is reponsible
// for deleting the result when done.
extern char* Force2String(Root* arg, size_t *lenp, const StringC **stringp);

#endif /*GENMAP_H*/
