// Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com // License for redistribution is by either the Artistic License // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. #ifndef ROOT_H #define ROOT_H #include #include #include #include #include "port.h" #include "rmem.h" #if IN_LLVM #include #endif #if __DMC__ #pragma once #endif typedef size_t hash_t; /* * Root of our class library. */ struct OutBuffer; // Can't include arraytypes.h here, need to declare these directly. template struct Array; typedef Array Files; typedef Array Strings; class RootObject { public: RootObject() { } virtual ~RootObject() { } virtual bool equals(RootObject *o); /** * Returns a hash code, useful for things like building hash tables of Objects. */ virtual hash_t hashCode(); /** * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj. * Useful for sorting Objects. */ virtual int compare(RootObject *obj); /** * Pretty-print an Object. Useful for debugging the old-fashioned way. */ virtual void print(); virtual char *toChars(); virtual void toBuffer(OutBuffer *buf); /** * Used as a replacement for dynamic_cast. Returns a unique number * defined by the library user. For Object, the return value is 0. */ virtual int dyncast(); /** * Marks pointers for garbage collector by calling mem.mark() for all pointers into heap. */ /*virtual*/ // not used, disable for now void mark(); }; class String : public RootObject { public: const char *str; // the string itself String(const char *str); ~String(); static hash_t calcHash(const char *str, size_t len); static hash_t calcHash(const char *str); hash_t hashCode(); size_t len(); bool equals(RootObject *obj); int compare(RootObject *obj); char *toChars(); void print(); void mark(); }; class FileName : public String { public: FileName(const char *str); hash_t hashCode(); bool equals(RootObject *obj); static int equals(const char *name1, const char *name2); int compare(RootObject *obj); static int compare(const char *name1, const char *name2); static int absolute(const char *name); static const char *ext(const char *); const char *ext(); static const char *removeExt(const char *str); static const char *name(const char *); const char *name(); static const char *path(const char *); static const char *replaceName(const char *path, const char *name); static const char *combine(const char *path, const char *name); static Strings *splitPath(const char *path); static const char *defaultExt(const char *name, const char *ext); static const char *forceExt(const char *name, const char *ext); static int equalsExt(const char *name, const char *ext); int equalsExt(const char *ext); void CopyTo(FileName *to); static const char *searchPath(Strings *path, const char *name, int cwd); static const char *safeSearchPath(Strings *path, const char *name); static int exists(const char *name); static void ensurePathExists(const char *path); static void ensurePathToNameExists(const char *name); static const char *canonicalName(const char *name); static void free(const char *str); }; class File : public RootObject { public: int ref; // != 0 if this is a reference to someone else's buffer unsigned char *buffer; // data for our file size_t len; // amount of data in buffer[] void *touchtime; // system time to use for file FileName *name; // name of our file File(const char *); File(const FileName *); ~File(); void mark(); char *toChars(); /* Read file, return !=0 if error */ int read(); /* Write file, either succeed or fail * with error message & exit. */ void readv(); /* Read file, return !=0 if error */ int mmread(); /* Write file, either succeed or fail * with error message & exit. */ void mmreadv(); /* Write file, return !=0 if error */ int write(); /* Write file, either succeed or fail * with error message & exit. */ void writev(); /* Return !=0 if file exists. * 0: file doesn't exist * 1: normal file * 2: directory */ /* Append to file, return !=0 if error */ int append(); /* Append to file, either succeed or fail * with error message & exit. */ void appendv(); /* Return !=0 if file exists. * 0: file doesn't exist * 1: normal file * 2: directory */ int exists(); /* Given wildcard filespec, return an array of * matching File's. */ static Files *match(char *); static Files *match(FileName *); // Compare file times. // Return <0 this < f // =0 this == f // >0 this > f int compareTime(File *f); // Read system file statistics void stat(); /* Set buffer */ void setbuffer(void *buffer, size_t len) { this->buffer = (unsigned char *)buffer; this->len = len; } void checkoffset(size_t offset, size_t nbytes); void remove(); // delete file }; struct OutBuffer { unsigned char *data; size_t offset; size_t size; int doindent; int level; int notlinehead; OutBuffer(); ~OutBuffer(); char *extractData(); void mark(); void reserve(size_t nbytes); void setsize(size_t size); void reset(); void write(const void *data, size_t nbytes); void writebstring(unsigned char *string); void writestring(const char *string); void prependstring(const char *string); void writenl(); // write newline void writeByte(unsigned b); void writebyte(unsigned b) { writeByte(b); } void writeUTF8(unsigned b); void prependbyte(unsigned b); void writewchar(unsigned w); void writeword(unsigned w); void writeUTF16(unsigned w); void write4(unsigned w); void write(OutBuffer *buf); void write(RootObject *obj); void fill0(size_t nbytes); void align(size_t size); void vprintf(const char *format, va_list args); void printf(const char *format, ...); void bracket(char left, char right); size_t bracket(size_t i, const char *left, size_t j, const char *right); void spread(size_t offset, size_t nbytes); size_t insert(size_t offset, const void *data, size_t nbytes); void remove(size_t offset, size_t nbytes); char *toChars(); char *extractString(); }; template struct Array { size_t dim; TYPE **data; private: size_t allocdim; #define SMALLARRAYCAP 1 TYPE *smallarray[SMALLARRAYCAP]; // inline storage for small arrays public: Array() { data = SMALLARRAYCAP ? &smallarray[0] : NULL; dim = 0; allocdim = SMALLARRAYCAP; } ~Array() { if (data != &smallarray[0]) mem.free(data); } void mark() { mem.mark(data); for (size_t u = 0; u < dim; u++) mem.mark(data[u]); // BUG: what if arrays of Object's? } char *toChars() { char **buf = (char **)malloc(dim * sizeof(char *)); assert(buf); size_t len = 2; for (size_t u = 0; u < dim; u++) { buf[u] = ((RootObject *)data[u])->toChars(); len += strlen(buf[u]) + 1; } char *str = (char *)mem.malloc(len); str[0] = '['; char *p = str + 1; for (size_t u = 0; u < dim; u++) { if (u) *p++ = ','; len = strlen(buf[u]); memcpy(p,buf[u],len); p += len; } *p++ = ']'; *p = 0; free(buf); return str; } void reserve(size_t nentries) { //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", (int)dim, (int)allocdim, (int)nentries); if (allocdim - dim < nentries) { if (allocdim == 0) { // Not properly initialized, someone memset it to zero if (nentries <= SMALLARRAYCAP) { allocdim = SMALLARRAYCAP; data = SMALLARRAYCAP ? &smallarray[0] : NULL; } else { allocdim = nentries; data = (TYPE **)mem.malloc(allocdim * sizeof(*data)); } } else if (allocdim == SMALLARRAYCAP) { allocdim = dim + nentries; data = (TYPE **)mem.malloc(allocdim * sizeof(*data)); memcpy(data, &smallarray[0], dim * sizeof(*data)); } else { allocdim = dim + nentries; data = (TYPE **)mem.realloc(data, allocdim * sizeof(*data)); } } } void setDim(size_t newdim) { if (dim < newdim) { reserve(newdim - dim); } dim = newdim; } void fixDim() { if (dim != allocdim) { if (allocdim >= SMALLARRAYCAP) { if (dim <= SMALLARRAYCAP) { memcpy(&smallarray[0], data, dim * sizeof(*data)); mem.free(data); } else data = (TYPE **)mem.realloc(data, dim * sizeof(*data)); } allocdim = dim; } } TYPE *pop() { return data[--dim]; } void shift(TYPE *ptr) { reserve(1); memmove(data + 1, data, dim * sizeof(*data)); data[0] = ptr; dim++; } void remove(size_t i) { if (dim - i - 1) memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0])); dim--; } void zero() { memset(data,0,dim * sizeof(data[0])); } TYPE *tos() { return dim ? data[dim - 1] : NULL; } void sort() { struct ArraySort { static int #if _WIN32 __cdecl #endif Array_sort_compare(const void *x, const void *y) { RootObject *ox = *(RootObject **)x; RootObject *oy = *(RootObject **)y; return ox->compare(oy); } }; if (dim) { qsort(data, dim, sizeof(RootObject *), &ArraySort::Array_sort_compare); } } TYPE **tdata() { return data; } TYPE*& operator[] (size_t index) { #ifdef DEBUG assert(index < dim); #endif return data[index]; } void insert(size_t index, TYPE *v) { reserve(1); memmove(data + index + 1, data + index, (dim - index) * sizeof(*data)); data[index] = v; dim++; } void insert(size_t index, Array *a) { if (a) { size_t d = a->dim; reserve(d); if (dim != index) memmove(data + index + d, data + index, (dim - index) * sizeof(*data)); memcpy(data + index, a->data, d * sizeof(*data)); dim += d; } } void append(Array *a) { insert(dim, a); } void push(TYPE *a) { reserve(1); data[dim++] = a; } Array *copy() { Array *a = new Array(); a->setDim(dim); memcpy(a->data, data, dim * sizeof(*data)); return a; } typedef int (*Array_apply_ft_t)(TYPE *, void *); int apply(Array_apply_ft_t fp, void *param) { for (size_t i = 0; i < dim; i++) { TYPE *e = (*this)[i]; if (e) { if (e->apply(fp, param)) return 1; } } return 0; } #if IN_LLVM // Define members and types like std::vector typedef size_t size_type; Array(const Array &a) : dim(0), data(0), allocdim(0) { setDim(a.dim); memcpy(data, a.data, dim * sizeof(*data)); } Array &operator=(Array &a) { setDim(a.dim); memcpy(data, a.data, dim * sizeof(*data)); return *this; } size_type size() { return static_cast(dim); } bool empty() { return dim == 0; } TYPE *front() { return data[0]; } TYPE *back() { return data[dim-1]; } void push_back(TYPE *a) { push(a); } void pop_back() { pop(); } typedef TYPE **iterator; typedef std::reverse_iterator reverse_iterator; iterator begin() { return static_cast(&data[0]); } iterator end() { return static_cast(&data[dim]); } reverse_iterator rbegin() { return reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } #endif }; // TODO: Remove (only used by disabled GC) class Bits : public RootObject { public: unsigned bitdim; unsigned allocdim; unsigned *data; Bits(); ~Bits(); void mark(); void resize(unsigned bitdim); void set(unsigned bitnum); void clear(unsigned bitnum); int test(unsigned bitnum); void set(); void clear(); void copy(Bits *from); Bits *clone(); void sub(Bits *b); }; #endif