From e33e19d0587146859d48a134ec9fd94e7b7ba5cd Mon Sep 17 00:00:00 2001 From: "FWoltermann@gmail.com" Date: Thu, 8 Dec 2011 14:53:40 +0000 Subject: Initial upload --- FoundationEx/ArrayList.cpp | 724 ++++++++++++++++++++++++++++++++++++++++++ FoundationEx/ArrayList.h | 181 +++++++++++ FoundationEx/Dictionary.h | 101 ++++++ FoundationEx/Dictionary.inl | 260 +++++++++++++++ FoundationEx/List.h | 107 +++++++ FoundationEx/List.inl | 445 ++++++++++++++++++++++++++ FoundationEx/MemDebug.cpp | 212 +++++++++++++ FoundationEx/MemDebug.h | 91 ++++++ FoundationEx/Text.cpp | 751 ++++++++++++++++++++++++++++++++++++++++++++ FoundationEx/Text.h | 193 ++++++++++++ FoundationEx/ThreadSync.h | 57 ++++ 11 files changed, 3122 insertions(+) create mode 100644 FoundationEx/ArrayList.cpp create mode 100644 FoundationEx/ArrayList.h create mode 100644 FoundationEx/Dictionary.h create mode 100644 FoundationEx/Dictionary.inl create mode 100644 FoundationEx/List.h create mode 100644 FoundationEx/List.inl create mode 100644 FoundationEx/MemDebug.cpp create mode 100644 FoundationEx/MemDebug.h create mode 100644 FoundationEx/Text.cpp create mode 100644 FoundationEx/Text.h create mode 100644 FoundationEx/ThreadSync.h (limited to 'FoundationEx') diff --git a/FoundationEx/ArrayList.cpp b/FoundationEx/ArrayList.cpp new file mode 100644 index 0000000..86fcbc3 --- /dev/null +++ b/FoundationEx/ArrayList.cpp @@ -0,0 +1,724 @@ +/* Project FoundationEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: FoundationEx + FILE: ArrayList.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Implementation of the untyped ArrayList class +*/ + +#include "MemDebug.h" +#include "ArrayList.h" + +// +-------------------------------------------------------------------+ + +void Print(const char* fmt, ...); + +// +-------------------------------------------------------------------+ + +ArrayList::ArrayList(const ArrayList& l) + : items(l.items), extent(l.extent) +{ +#ifdef MEM_DEBUG + array = new(__FILE__,__LINE__) DWORD[extent]; +#else + array = new DWORD[extent]; +#endif + + memcpy(array, l.array, extent*sizeof(DWORD)); +} + +void ArrayList::clear() +{ + delete [] array; + items = 0; + extent = 0; + array = 0; +} + +// +-------------------------------------------------------------------+ + +bool ArrayList::check(int& index) const +{ + if (index < 0) { + Print("Bounds error in ArrayList(%08x) index=%d min=0\n", (int)this, index); + index = 0; + } + + else if (index >= items) { + Print("Bounds error in ArrayList(%08x) index=%d max=%d\n", (int)this,index, items-1); + index = items-1; + } + + return (index >= 0 && index < items); +} + +// +-------------------------------------------------------------------+ + +DWORD ArrayList::operator[](int index) const +{ + if (check(index)) + return array[index]; + return 0; +} + +DWORD& ArrayList::operator[](int index) +{ + if (check(index)) + return array[index]; + + return array[0]; +} + +DWORD ArrayList::at(int index) const +{ + if (check(index)) + return array[index]; + return 0; +} + +DWORD& ArrayList::at(int index) +{ + if (check(index)) + return array[index]; + + return array[0]; +} + +// +-------------------------------------------------------------------+ + +void ArrayList::resize(int newsize) +{ + if (newsize > extent) { + extent = 16 * (newsize/16 + 1); + +#ifdef MEM_DEBUG + DWORD* v = new(__FILE__,__LINE__) DWORD[extent]; +#else + DWORD* v = new DWORD[extent]; +#endif + + for (int i = 0; i < items; i++) + v[i] = array[i]; + + for (; i < extent; i++) + v[i] = 0; + + delete [] array; + array = v; + } +} + +// +-------------------------------------------------------------------+ + +void ArrayList::append(DWORD item) +{ + if (items+1 > extent) + resize(items+1); + + array[items++] = item; +} + +void ArrayList::append(const ArrayList& list) +{ + if (&list != this && list.items > 0) { + int need = items + list.items; + if (need > extent) + resize(need); + + for (int i = 0; i < list.items; i++) + array[items++] = list.array[i]; + } +} + +// +-------------------------------------------------------------------+ + +void ArrayList::insert(DWORD item, int index) +{ + if (index >= 0 && index <= items) { + if (items+1 > extent) + resize(items+1); + + // slide right: + for (int i = items; i > index; i--) + array[i] = array[i-1]; + + array[index] = item; + items++; + } +} + +// +-------------------------------------------------------------------+ + +void ArrayList::insertSort(DWORD item) +{ + for (int i = 0; i < items; i++) { + if (item < array[i]) + break; + } + + insert(item, i); +} + +// +-------------------------------------------------------------------+ + +void ArrayList::remove(DWORD item) +{ + if (items < 1) + return; + + for (int i = 0; i < items; i++) { + if (array[i] == item) { + removeIndex(i); + return; + } + } +} + +// +-------------------------------------------------------------------+ + +void ArrayList::removeIndex(int index) +{ + if (items < 1 || !check(index)) + return; + + // slide left: + for (int i = index; i < items-1; i++) + array[i] = array[i+1]; + + // blank out the hole we just created: + array[items-1] = 0; + + items--; +} + +// +-------------------------------------------------------------------+ + +bool ArrayList::contains(DWORD val) const +{ + for (int i = 0; i < items; i++) { + if (array[i] == val) + return true; + } + + return false; +} + +// +-------------------------------------------------------------------+ + +int ArrayList::count(DWORD val) const +{ + int c = 0; + + for (int i = 0; i < items; i++) { + if (array[i] == val) + c++; + } + + return c; +} + +// +-------------------------------------------------------------------+ + +int ArrayList::index(DWORD val) const +{ + for (int i = 0; i < items; i++) { + if (array[i] == val) + return i; + } + + return -1; +} + +// +-------------------------------------------------------------------+ + +void ArrayList::swap(DWORD* a, int i, int j) +{ + if (i >= 0 && i < items && j >= 0 && j < items && i != j) { + DWORD t = a[i]; + a[i] = a[j]; + a[j] = t; + } +} + +void ArrayList::qsort(DWORD* a, int lo0, int hi0) +{ + int lo = lo0; + int hi = hi0; + + // zero or one element list, nothing to do: + if (lo >= hi) { + return; + } + + // two element list, swap if needed: + else if (lo == hi-1) { + if (a[hi] < a[lo]) { + swap(a, lo, hi); + } + return; + } + + // pick a pivot, and move it out of the way: + int mid = (lo+hi)/2; + DWORD pivot = a[mid]; + a[mid] = a[hi]; + a[hi] = pivot; + + while (lo < hi) { + while ((a[lo] <= pivot) && lo < hi) lo++; + while ((pivot <= a[hi]) && lo < hi) hi--; + + if (lo < hi) { + swap(a, lo, hi); + } + } + + // Put the pivot into its final location: + a[hi0] = a[hi]; + a[hi] = pivot; + + qsort(a, lo0, lo-1); + qsort(a, hi+1, hi0); +} + +void ArrayList::sort() +{ + if (items < 2) + return; + + qsort(array, 0, items-1); +} + +void ArrayList::shuffle() +{ + if (items < 3) + return; + + for (int s = 0; s < 5; s++) { + for (int i = 0; i < items; i++) { + int j = (rand()>>4) % items; + swap(array, i, j); + } + } +} + + +// +===================================================================+ + +DWORD ArrayListIter::value() +{ + if (list && step >= 0 && step < list->items) + return list->array[step]; + + return 0; +} + +// +-------------------------------------------------------------------+ + +void ArrayListIter::removeItem() +{ + if (list && step >= 0 && step < list->items) + list->removeIndex(step--); +} + +// +-------------------------------------------------------------------+ + +DWORD ArrayListIter::next() +{ + if (list && step >= -1 && step < list->items-1) + return list->array[++step]; + + return 0; +} + +DWORD ArrayListIter::prev() +{ + if (list && step > 0 && step < list->items) + return list->array[--step]; + + return 0; +} + +// +-------------------------------------------------------------------+ + +void ArrayListIter::attach(ArrayList& l) +{ + list = &l; + step = -1; +} + +// +-------------------------------------------------------------------+ + +int ArrayListIter::size() +{ + if (!list) return 0; + return list->items; +} + +// +-------------------------------------------------------------------+ + +ArrayList& ArrayListIter::container() +{ + return *list; +} + + + + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +FloatList::FloatList(const FloatList& l) + : items(l.items), extent(l.extent) +{ +#ifdef MEM_DEBUG + array = new(__FILE__,__LINE__) float[extent]; +#else + array = new float[extent]; +#endif + + memcpy(array, l.array, extent*sizeof(float)); +} + +void FloatList::clear() +{ + delete [] array; + items = 0; + extent = 0; + array = 0; +} + +// +-------------------------------------------------------------------+ + +bool FloatList::check(int& index) const +{ + if (index < 0) { + Print("Bounds error in FloatList(%08x) index=%d min=0\n", (int)this, index); + index = 0; + } + + else if (index >= items) { + Print("Bounds error in FloatList(%08x) index=%d max=%d\n", (int)this,index, items-1); + index = items-1; + } + + return (index >= 0 && index < items); +} + +// +-------------------------------------------------------------------+ + +float FloatList::operator[](int index) const +{ + if (check(index)) + return array[index]; + return 0; +} + +float& FloatList::operator[](int index) +{ + if (check(index)) + return array[index]; + + return array[0]; +} + +float FloatList::at(int index) const +{ + if (check(index)) + return array[index]; + return 0; +} + +float& FloatList::at(int index) +{ + if (check(index)) + return array[index]; + + return array[0]; +} + +// +-------------------------------------------------------------------+ + +void FloatList::resize(int newsize) +{ + if (newsize > extent) { + extent = 16 * (newsize/16 + 1); + +#ifdef MEM_DEBUG + float* v = new(__FILE__,__LINE__) float[extent]; +#else + float* v = new float[extent]; +#endif + + for (int i = 0; i < items; i++) + v[i] = array[i]; + + for (; i < extent; i++) + v[i] = 0; + + delete [] array; + array = v; + } +} + +// +-------------------------------------------------------------------+ + +void FloatList::append(float item) +{ + if (items+1 > extent) + resize(items+1); + + array[items++] = item; +} + +void FloatList::append(const FloatList& list) +{ + if (&list != this && list.items > 0) { + int need = items + list.items; + if (need > extent) + resize(need); + + for (int i = 0; i < list.items; i++) + array[items++] = list.array[i]; + } +} + +// +-------------------------------------------------------------------+ + +void FloatList::insert(float item, int index) +{ + if (index >= 0 && index <= items) { + if (items+1 > extent) + resize(items+1); + + // slide right: + for (int i = items; i > index; i--) + array[i] = array[i-1]; + + array[index] = item; + items++; + } +} + +// +-------------------------------------------------------------------+ + +void FloatList::insertSort(float item) +{ + for (int i = 0; i < items; i++) { + if (item < array[i]) + break; + } + + insert(item, i); +} + +// +-------------------------------------------------------------------+ + +void FloatList::remove(float item) +{ + if (items < 1) + return; + + for (int i = 0; i < items; i++) { + if (array[i] == item) { + removeIndex(i); + return; + } + } +} + +// +-------------------------------------------------------------------+ + +void FloatList::removeIndex(int index) +{ + if (items < 1 || !check(index)) + return; + + // slide left: + for (int i = index; i < items-1; i++) + array[i] = array[i+1]; + + // blank out the hole we just created: + array[items-1] = 0; + + items--; +} + +// +-------------------------------------------------------------------+ + +bool FloatList::contains(float val) const +{ + for (int i = 0; i < items; i++) { + if (array[i] == val) + return true; + } + + return false; +} + +// +-------------------------------------------------------------------+ + +int FloatList::count(float val) const +{ + int c = 0; + + for (int i = 0; i < items; i++) { + if (array[i] == val) + c++; + } + + return c; +} + +// +-------------------------------------------------------------------+ + +int FloatList::index(float val) const +{ + for (int i = 0; i < items; i++) { + if (array[i] == val) + return i; + } + + return -1; +} + +// +-------------------------------------------------------------------+ + +void FloatList::swap(float* a, int i, int j) +{ + if (i >= 0 && i < items && j >= 0 && j < items && i != j) { + float t = a[i]; + a[i] = a[j]; + a[j] = t; + } +} + +void FloatList::qsort(float* a, int lo0, int hi0) +{ + int lo = lo0; + int hi = hi0; + + // zero or one element list, nothing to do: + if (lo >= hi) { + return; + } + + // two element list, swap if needed: + else if (lo == hi-1) { + if (a[hi] < a[lo]) { + swap(a, lo, hi); + } + return; + } + + // pick a pivot, and move it out of the way: + int mid = (lo+hi)/2; + float pivot = a[mid]; + a[mid] = a[hi]; + a[hi] = pivot; + + while (lo < hi) { + while ((a[lo] <= pivot) && lo < hi) lo++; + while ((pivot <= a[hi]) && lo < hi) hi--; + + if (lo < hi) { + swap(a, lo, hi); + } + } + + // Put the pivot into its final location: + a[hi0] = a[hi]; + a[hi] = pivot; + + qsort(a, lo0, lo-1); + qsort(a, hi+1, hi0); +} + +void FloatList::sort() +{ + if (items < 2) + return; + + qsort(array, 0, items-1); +} + +void FloatList::shuffle() +{ + if (items < 3) + return; + + for (int s = 0; s < 5; s++) { + for (int i = 0; i < items; i++) { + int j = (rand()>>4) % items; + swap(array, i, j); + } + } +} + + +// +===================================================================+ + +float FloatListIter::value() +{ + if (list && step >= 0 && step < list->items) + return list->array[step]; + + return 0; +} + +// +-------------------------------------------------------------------+ + +void FloatListIter::removeItem() +{ + if (list && step >= 0 && step < list->items) + list->removeIndex(step--); +} + +// +-------------------------------------------------------------------+ + +float FloatListIter::next() +{ + if (list && step >= -1 && step < list->items-1) + return list->array[++step]; + + return 0; +} + +float FloatListIter::prev() +{ + if (list && step > 0 && step < list->items) + return list->array[--step]; + + return 0; +} + +// +-------------------------------------------------------------------+ + +void FloatListIter::attach(FloatList& l) +{ + list = &l; + step = -1; +} + +// +-------------------------------------------------------------------+ + +int FloatListIter::size() +{ + if (!list) return 0; + return list->items; +} + +// +-------------------------------------------------------------------+ + +FloatList& FloatListIter::container() +{ + return *list; +} + diff --git a/FoundationEx/ArrayList.h b/FoundationEx/ArrayList.h new file mode 100644 index 0000000..6917d9b --- /dev/null +++ b/FoundationEx/ArrayList.h @@ -0,0 +1,181 @@ +/* Project FoundationEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: FoundationEx + FILE: ArrayList.h + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Simple untyped array list +*/ + +#ifndef ArrayList_h +#define ArrayList_h + +#ifdef WIN32 +#include +#include +#endif + +// +-------------------------------------------------------------------+ + +class ArrayList +{ +public: + ArrayList() : items(0), extent(0), array(0) { } + ArrayList(const ArrayList& l); + ~ArrayList() { delete [] array; } + + DWORD operator[](int i) const; + DWORD& operator[](int i); + DWORD at(int i) const; + DWORD& at(int i); + + void append(const ArrayList& list); + void append(const DWORD val); + void insert(const DWORD val, int index=0); + void insertSort(DWORD val); + + DWORD first() const { return operator[](0); } + DWORD last() const { return operator[](items-1); } + void remove(DWORD val); + void removeIndex(int index); + + void clear(); + + int size() const { return items; } + bool isEmpty() const { return !items; } + + bool contains(DWORD val) const; + int count(DWORD val) const; + int index(DWORD val) const; + + void sort(); + void shuffle(); + +private: + void qsort(DWORD* a, int lo, int hi); + void swap(DWORD* a, int i, int j); + void resize(int newsize); + bool check(int& index) const; + + int items; + int extent; + DWORD* array; + + friend class ArrayListIter; +}; + +// +-------------------------------------------------------------------+ + +class ArrayListIter +{ +public: + ArrayListIter() : list(0), step(-1) { } + ArrayListIter(const ArrayListIter& i) : list(i.list), step(i.step) { } + ArrayListIter(ArrayList& l) : list(&l), step(-1) { } + + int operator++() { return next() != 0; } + int operator--() { return prev() != 0; } + + void reset() { step = -1; } + DWORD next(); + DWORD prev(); + DWORD value(); + void removeItem(); + + void attach(ArrayList& l); + ArrayList& container(); + int size(); + int index() { return step; } + +private: + ArrayList* list; + int step; +}; + + +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ +// +-------------------------------------------------------------------+ + +class FloatList +{ +public: + FloatList() : items(0), extent(0), array(0) { } + FloatList(const FloatList& l); + ~FloatList() { delete [] array; } + + float operator[](int i) const; + float& operator[](int i); + float at(int i) const; + float& at(int i); + + void append(const FloatList& list); + void append(const float val); + void insert(const float val, int index=0); + void insertSort(float val); + + float first() const { return operator[](0); } + float last() const { return operator[](items-1); } + void remove(float val); + void removeIndex(int index); + + void clear(); + + int size() const { return items; } + bool isEmpty() const { return !items; } + + bool contains(float val) const; + int count(float val) const; + int index(float val) const; + + void sort(); + void shuffle(); + +private: + void qsort(float* a, int lo, int hi); + void swap(float* a, int i, int j); + void resize(int newsize); + bool check(int& index) const; + + int items; + int extent; + float* array; + + friend class FloatListIter; +}; + +// +-------------------------------------------------------------------+ + +class FloatListIter +{ +public: + FloatListIter() : list(0), step(-1) { } + FloatListIter(const FloatListIter& i) : list(i.list), step(i.step) { } + FloatListIter(FloatList& l) : list(&l), step(-1) { } + + int operator++() { return next() != 0; } + int operator--() { return prev() != 0; } + + void reset() { step = -1; } + float next(); + float prev(); + float value(); + void removeItem(); + + void attach(FloatList& l); + FloatList& container(); + int size(); + int index() { return step; } + +private: + FloatList* list; + int step; +}; + +#endif ArrayList_h + diff --git a/FoundationEx/Dictionary.h b/FoundationEx/Dictionary.h new file mode 100644 index 0000000..26ffd2e --- /dev/null +++ b/FoundationEx/Dictionary.h @@ -0,0 +1,101 @@ +/* Project FoundationEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: FoundationEx + FILE: Dictionary.h + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Declaration of the Dictionary class +*/ + +#ifndef Dictionary_h +#define Dictionary_h + +#include "Text.h" + +// +-------------------------------------------------------------------+ + +template class Dictionary; +template class DictionaryIter; +template class DictionaryCell; + +// +-------------------------------------------------------------------+ + +template class Dictionary +{ +public: + Dictionary(); + ~Dictionary(); + + T& operator[](const Text& key); + + void insert(const Text& key, const T& val); + void remove(const Text& key); + + void clear(); + + int size() const { return items; } + int isEmpty() const { return !items; } + + int contains(const Text& key) const; + T find(const Text& key, T defval) const; + +private: + void init(); + + int items; + + typedef DictionaryCell* PTR; + PTR table[256]; + + friend class DictionaryIter; +}; + +// +-------------------------------------------------------------------+ + +template class DictionaryIter +{ +public: + DictionaryIter(Dictionary& l); + ~DictionaryIter(); + + int operator++(); // prefix + + void reset(); + void forth(); + + Text key() const; + T value() const; + + void attach(Dictionary& l); + Dictionary& container(); + +private: + Dictionary* dict; + DictionaryCell* here; + int chain; +}; + +// +-------------------------------------------------------------------+ + +template class DictionaryCell +{ +public: + DictionaryCell(const Text& k) : key(k), value( ), next(0) { } + DictionaryCell(const Text& k, const T& v) : key(k), value(v), next(0) { } + ~DictionaryCell() { } + + Text key; + T value; + DictionaryCell* next; +}; + +// +-------------------------------------------------------------------+ + +#include "Dictionary.inl" +#endif Dictionary_h + diff --git a/FoundationEx/Dictionary.inl b/FoundationEx/Dictionary.inl new file mode 100644 index 0000000..98cdd05 --- /dev/null +++ b/FoundationEx/Dictionary.inl @@ -0,0 +1,260 @@ +/* Project FoundationEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: FoundationEx + FILE: Dictionary.inl + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Implementation of the Dictionary class +*/ + +#ifndef NDEBUG +#define DICT_CHECK(a, b) if ((a) == 0) throw b; +#else +#define DICT_CHECK(a, b) +#endif + +const int CHAINS = 256; + +// +-------------------------------------------------------------------+ + +template Dictionary::Dictionary() + : items(0) +{ init(); } + +template Dictionary::~Dictionary() +{ clear(); } + +// +-------------------------------------------------------------------+ + +template +void Dictionary::init() +{ + items = 0; + memset(table, 0, CHAINS*sizeof(PTR)); +} + +template +void Dictionary::clear() +{ + for (int i = 0; i < CHAINS; i++) { + DictionaryCell* link = table[i]; + + while (link) { + DictionaryCell* n = link->next; + delete link; + link = n; + } + } + + init(); +} + +// +-------------------------------------------------------------------+ + +template +T& Dictionary::operator[](const Text& key) +{ + int idx = key.hash() % CHAINS; + DictionaryCell* cell = table[idx]; + + if (cell == 0) { // empty chain + items++; + +#ifdef MEM_DEBUG + cell = new(__FILE__,__LINE__) DictionaryCell(key); +#else + cell = new DictionaryCell(key); +#endif + + table[idx] = cell; + + return cell->value; + } + else { // search for key + while (cell->next && cell->key != key) + cell = cell->next; + + if (cell->key != key) { // not found in chain + items++; + +#ifdef MEM_DEBUG + cell->next = new(__FILE__,__LINE__) DictionaryCell(key); +#else + cell->next = new DictionaryCell(key); +#endif + + return cell->next->value; + } + else { // found: return it! + return cell->value; + } + } +} + +// +-------------------------------------------------------------------+ + +template +void Dictionary::insert(const Text& key, const T& val) +{ + T& value = operator[](key); + value = val; +} + +// +-------------------------------------------------------------------+ + +template +void Dictionary::remove(const Text& key) +{ + int idx = key.hash() % CHAINS; + DictionaryCell* cell = table[idx]; + + if (cell == 0) { // empty chain + return; + } + else { // search for key + while (cell->next && cell->key != key) + cell = cell->next; + + if (cell->key != key) { // not found in chain + return; + } + else { // found: remove it! + if (table[idx] == cell) { + table[idx] = cell->next; + delete cell; + } + else { + DictionaryCell* p = table[idx]; + while (p->next != cell) + p = p->next; + p->next = cell->next; + delete cell; + } + } + } +} + +// +-------------------------------------------------------------------+ + +template +int Dictionary::contains(const Text& key) const +{ + int idx = key.hash() % CHAINS; + DictionaryCell* cell = table[idx]; + + if (cell != 0) { + while (cell->next && cell->key != key) + cell = cell->next; + + if (cell->key == key) + return 1; + } + + return 0; +} + +// +-------------------------------------------------------------------+ + +template +T Dictionary::find(const Text& key, T defval) const +{ + int idx = key.hash() % CHAINS; + DictionaryCell* cell = table[idx]; + + if (cell != 0) { + while (cell->next && cell->key != key) + cell = cell->next; + + if (cell->key == key) + return cell->value; + } + + return defval; +} + +// +-------------------------------------------------------------------+ + +template DictionaryIter::DictionaryIter(Dictionary& d) + : dict(&d), chain(0), here(0) +{ } + +template DictionaryIter::~DictionaryIter() +{ } + +// +-------------------------------------------------------------------+ + +template +void DictionaryIter::reset() +{ + chain = 0; + here = 0; +} + +// +-------------------------------------------------------------------+ + +template +Text DictionaryIter::key() const +{ + return here->key; +} + +template +T DictionaryIter::value() const +{ + return here->value; +} + +// +-------------------------------------------------------------------+ + +template +int DictionaryIter::operator++() +{ + forth(); + int more = chain < CHAINS; + return more; +} + +// +-------------------------------------------------------------------+ + +template +void DictionaryIter::forth() +{ + if (here) { + here = here->next; + if (!here) // off the end of this chain + chain++; + } + + if (!here) { + while (!dict->table[chain] && chain < CHAINS) + chain++; + + if (chain < CHAINS) + here = dict->table[chain]; + else + here = 0; + } +} + +// +-------------------------------------------------------------------+ + +template +void DictionaryIter::attach(Dictionary& d) +{ + dict = &d; + reset(); +} + +// +-------------------------------------------------------------------+ + +template +Dictionary& DictionaryIter::container() +{ + return *dict; +} + diff --git a/FoundationEx/List.h b/FoundationEx/List.h new file mode 100644 index 0000000..1460cf4 --- /dev/null +++ b/FoundationEx/List.h @@ -0,0 +1,107 @@ +/* Project FoundationEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: FoundationEx + FILE: List.h + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Declaration of the List class template +*/ + +#ifndef List_h +#define List_h + +// +-------------------------------------------------------------------+ + +template class List; +template class ListIter; + +// +-------------------------------------------------------------------+ + +template class List +{ +public: + List() : items(0), extent(0), array(0) { } + List(const List& l); + ~List() { delete [] array; } + + T*& operator[](int i); + T* operator[](int i) const; + T*& at(int i); + T* at(int i) const; + + void append(List& list); + void append(const T* val); + void insert(const T* val, int index=0); + void insertSort(const T* val); + + T* first() const { return operator[](0); } + T* last() const { return operator[](items-1); } + T* remove(const T* val); + T* removeIndex(int index); + + void clear(); + void destroy(); + + int size() const { return items; } + bool isEmpty() const { return !items; } + + bool contains(const T* val) const; + int count(const T* val) const; + int index(const T* val) const; + T* find(const T* val) const; + + void sort(); + void shuffle(); + +private: + typedef T* PTR; + void qsort(T** a, int lo, int hi); + void resize(int newsize); + bool check(int& index) const; + void swap(T** a, int i, int j); + + int items; + int extent; + PTR* array; + + friend class ListIter; +}; + +// +-------------------------------------------------------------------+ + +template class ListIter +{ +public: + ListIter() : list(0), step(-1) { } + ListIter(const ListIter& i) : list(i.list), step(i.step) { } + ListIter(List& l) : list(&l), step(-1) { } + + int operator++() { return next() != 0; } + int operator--() { return prev() != 0; } + T* operator->() { return value(); } + T& operator* () { return *value(); } + + void reset() { step = -1; } + T* next(); + T* prev(); + T* value(); + T* removeItem(); + + void attach(List& l); + List& container(); + int size(); + int index() { return step; } + +private: + List* list; + int step; +}; + +#include "List.inl" +#endif List_h + diff --git a/FoundationEx/List.inl b/FoundationEx/List.inl new file mode 100644 index 0000000..841e690 --- /dev/null +++ b/FoundationEx/List.inl @@ -0,0 +1,445 @@ +/* Project FoundationEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: FoundationEx + FILE: List.inl + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Implementation of the List class template +*/ + +// +-------------------------------------------------------------------+ + +void Print(const char* fmt, ...); + +// +-------------------------------------------------------------------+ + +template +List::List(const List& l) + : items(l.items), extent(l.extent) +{ +#ifdef MEM_DEBUG + array = new(__FILE__,__LINE__) PTR[extent]; +#else + array = new PTR[extent]; +#endif + + for (int i = 0; i < extent; i++) + array[i] = l.array[i]; +} + +template +void List::clear() +{ + delete [] array; + items = 0; + extent = 0; + array = 0; +} + +template +void List::destroy() +{ + if (items) { + items = 0; // prevent dangerous re-entrancy + + for (int i = 0; i < extent; i++) + delete array[i]; + + delete [] array; + items = 0; + extent = 0; + array = 0; + } +} + +// +-------------------------------------------------------------------+ + +template +bool List::check(int& index) const +{ + if (index < 0) { + Print("Bounds error in List(%08x) T=%s index=%d min=0\n", (int)this, T::TYPENAME(), index); + index = 0; + } + + else if (index >= items) { + Print("Bounds error in List(%08x) T=%s index=%d max=%d\n", (int)this, T::TYPENAME(), index, items-1); + index = items-1; + } + + return (index >= 0 && index < items); +} + +// +-------------------------------------------------------------------+ + +template +T*& List::operator[](int index) +{ + if (check(index)) + return array[index]; + + if (!array || !extent) + resize(1); + + return array[0]; +} + +template +T* List::operator[](int index) const +{ + if (check(index)) + return array[index]; + return 0; +} + +template +T*& List::at(int index) +{ + if (check(index)) + return array[index]; + + if (!array || !extent) + resize(1); + + return array[0]; +} + +template +T* List::at(int index) const +{ + if (check(index)) + return array[index]; + return 0; +} + +// +-------------------------------------------------------------------+ + +template +void List::resize(int newsize) +{ + if (newsize > extent) { + extent = 16 * (newsize/16 + 1); + +#ifdef MEM_DEBUG + T** v = new(__FILE__,__LINE__) PTR[extent]; +#else + T** v = new PTR[extent]; +#endif + + for (int i = 0; i < items; i++) + v[i] = array[i]; + + for (; i < extent; i++) + v[i] = 0; + + delete [] array; + array = v; + } +} + +// +-------------------------------------------------------------------+ + +template +void List::append(const T* item) +{ + if (item) { + if (items+1 > extent) resize(items+1); + array[items++] = (T*)item; + } +} + +template +void List::append(List& list) +{ + if (&list != this && list.items > 0) { + int need = items + list.items; + if (need > extent) resize(need); + + for (int i = 0; i < list.items; i++) + array[items++] = list.array[i]; + } +} + +// +-------------------------------------------------------------------+ + +template +void List::insert(const T* item, int index) +{ + if (item && index >= 0 && index <= items) { + if (items+1 > extent) resize(items+1); + + // slide right: + for (int i = items; i > index; i--) + array[i] = array[i-1]; + + array[index] = (T*)item; + items++; + } +} + +// +-------------------------------------------------------------------+ + +template +void List::insertSort(const T* item) +{ + if (item) { + for (int i = 0; i < items; i++) { + if (*item < *array[i]) + break; + } + + insert(item, i); + } +} + +// +-------------------------------------------------------------------+ + +template +T* List::remove(const T* val) +{ + if (items == 0 || val == 0) + return 0; + + for (int i = 0; i < items; i++) { + if (array[i] == val) { + return removeIndex(i); + } + } + + return 0; +} + +// +-------------------------------------------------------------------+ + +template +T* List::removeIndex(int index) +{ + if (!check(index)) + return 0; + + T* tmp = array[index]; + array[index] = 0; + + // slide left: + for (int i = index; i < items-1; i++) + array[i] = array[i+1]; + + // blank out the hole we just created: + array[items-1] = 0; + + items--; + return tmp; +} + +// +-------------------------------------------------------------------+ + +template +bool List::contains(const T* val) const +{ + if (val) { + for (int i = 0; i < items; i++) { + if (array[i] && ((*array[i])==(*val))) + return true; + } + } + + return false; +} + +// +-------------------------------------------------------------------+ + +template +int List::count(const T* val) const +{ + int c = 0; + + if (val) { + for (int i = 0; i < items; i++) { + if (array[i] && ((*array[i])==(*val))) + c++; + } + } + + return c; +} + +// +-------------------------------------------------------------------+ + +template +int List::index(const T* val) const +{ + if (val) { + for (int i = 0; i < items; i++) { + if (array[i] && ((*array[i])==(*val))) + return i; + } + } + + return -1; +} + +// +-------------------------------------------------------------------+ + +template +T* List::find(const T* val) const +{ + if (val) { + for (int i = 0; i < items; i++) { + if (array[i] && ((*array[i])==(*val))) + return array[i]; + } + } + + return 0; +} + +// +-------------------------------------------------------------------+ + +template +void List::swap(T** a, int i, int j) +{ + if (i >= 0 && i < items && j >= 0 && j < items && i != j) { + T* t = a[i]; + a[i] = a[j]; + a[j] = t; + } +} + +template +void List::qsort(T** a, int lo0, int hi0) +{ + int lo = lo0; + int hi = hi0; + + // zero or one element list, nothing to do: + if (lo >= hi) { + return; + } + + // two element list, swap if needed: + else if (lo == hi-1) { + if (*a[hi] < *a[lo]) { + swap(a, lo, hi); + } + return; + } + + // pick a pivot, and move it out of the way: + int mid = (lo+hi)/2; + T* pivot = a[mid]; + a[mid] = a[hi]; + a[hi] = pivot; + + while (lo < hi) { + while ((*a[lo] <= *pivot) && lo < hi) lo++; + while ((*pivot <= *a[hi]) && lo < hi) hi--; + + if (lo < hi) { + swap(a, lo, hi); + } + } + + // Put the pivot into its final location: + a[hi0] = a[hi]; + a[hi] = pivot; + + qsort(a, lo0, lo-1); + qsort(a, hi+1, hi0); +} + +template +void List::sort() +{ + if (items < 2) + return; + + qsort(array, 0, items-1); +} + +template +void List::shuffle() +{ + if (items < 3) + return; + + for (int s = 0; s < 5; s++) { + for (int i = 0; i < items; i++) { + int j = (rand()>>4) % items; + swap(array, i, j); + } + } +} + +// +===================================================================+ + +template +T* ListIter::value() +{ + if (list && step >= 0 && step < list->items) + return list->array[step]; + + return 0; +} + +// +-------------------------------------------------------------------+ + +template +T* ListIter::removeItem() +{ + if (list && step >= 0 && step < list->items) + return list->removeIndex(step--); + + return 0; +} + +// +-------------------------------------------------------------------+ + +template +T* ListIter::next() +{ + if (list && step >= -1 && step < list->items-1) + return list->array[++step]; + + return 0; +} + +template +T* ListIter::prev() +{ + if (list && step > 0 && step < list->items) + return list->array[--step]; + + return 0; +} + +// +-------------------------------------------------------------------+ + +template +void ListIter::attach(List& l) +{ + list = &l; + step = -1; +} + +// +-------------------------------------------------------------------+ + +template +int ListIter::size() +{ + if (!list) return 0; + return list->items; +} + +// +-------------------------------------------------------------------+ + +template +List& ListIter::container() +{ + return *list; +} + diff --git a/FoundationEx/MemDebug.cpp b/FoundationEx/MemDebug.cpp new file mode 100644 index 0000000..ce8a63c --- /dev/null +++ b/FoundationEx/MemDebug.cpp @@ -0,0 +1,212 @@ +/* Project nGen + John DiCamillo + Copyright © 1997-2001. All Rights Reserved. + + SUBSYSTEM: foundation + FILE: MemDebug.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Memory Debugging class +*/ + +#include "MemDebug.h" + +#include +#include +#include +#include + +// +--------------------------------------------------------------------+ + +static Memory::LEVEL mem_chk_level = Memory::PERIODIC; + +#ifdef _DEBUG +static _CrtMemState mem_chk_p1, + mem_chk_p2; +#endif + +static HANDLE mem_log_file = 0; + +// +--------------------------------------------------------------------+ + +#ifdef _DEBUG +#define CrtSetDebugField(a) _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) +#define CrtClrDebugField(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) +#endif + +static void heapdump() +{ + _HEAPINFO hinfo; + int heapstatus; + DWORD used = 0; + DWORD avail = 0; + char report[256]; + + hinfo._pentry = NULL; + while ((heapstatus = _heapwalk( &hinfo )) == _HEAPOK) { + sprintf(report, "%6s block at %Fp of size %4.4X\n", + ( hinfo._useflag == _USEDENTRY ? "USED" : "FREE" ), + hinfo._pentry, hinfo._size); + + _RPT0(_CRT_WARN, report); + + if (hinfo._useflag == _USEDENTRY) + used += hinfo._size; + else + avail += hinfo._size; + } + + sprintf(report, "------\nUsed Blocks: %d\nAvail Blocks: %d\nTotal Blocks: %d\n", used, avail, used+avail); + _RPT0(_CRT_WARN, report); + + switch (heapstatus) { + case _HEAPEMPTY: + _RPT0(_CRT_WARN, "OK - empty heap\n" ); + break; + case _HEAPEND: + _RPT0(_CRT_WARN, "OK - end of heap\n" ); + break; + case _HEAPBADPTR: + _RPT0(_CRT_WARN, "ERROR - bad pointer to heap\n" ); + break; + case _HEAPBADBEGIN: + _RPT0(_CRT_WARN, "ERROR - bad start of heap\n" ); + break; + case _HEAPBADNODE: + _RPT0(_CRT_WARN, "ERROR - bad node in heap\n" ); + break; + } +} + +// +--------------------------------------------------------------------+ + +void +Memory::OpenLog(const char* filename) +{ +#ifdef _DEBUG + if (!filename || !strlen(filename)) + filename = "memdbg.txt"; + + mem_log_file = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); + + if (mem_log_file) { + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, mem_log_file); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_ERROR, mem_log_file); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_ASSERT, mem_log_file); + } + + _CrtMemCheckpoint(&mem_chk_p1); +#endif +} + +// +--------------------------------------------------------------------+ + +void +Memory::CloseLog() +{ +#ifdef _DEBUG + if (mem_log_file) { + CloseHandle(mem_log_file); + mem_log_file = 0; + + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT); + } +#endif +} + +// +--------------------------------------------------------------------+ + +void +Memory::Check() +{ +#ifdef _DEBUG + if (! _CrtCheckMemory()) { + _RPT0(_CRT_ERROR, "\n\nMemory Check Failed.\n"); + heapdump(); + Checkpoint(); + _asm { int 3 } + exit(1111); + } +#endif +} + +// +--------------------------------------------------------------------+ + +void +Memory::Checkpoint() +{ +#ifdef _DEBUG + if (mem_chk_level < PERIODIC) return; + + _RPT0(_CRT_WARN, "\n\nMemory Checkpoint:\n" + "--------------------------------------------------\n"); + + _CrtMemState s; + _CrtMemCheckpoint(&mem_chk_p2); + _CrtMemDifference(&s, &mem_chk_p1, &mem_chk_p2); + _CrtMemDumpStatistics(&s); + + memcpy(&mem_chk_p1, &mem_chk_p2, sizeof(mem_chk_p1)); +#endif +} + +// +--------------------------------------------------------------------+ + +void +Memory::Stats() +{ +#ifdef _DEBUG + if (mem_chk_level < PERIODIC) return; + + _RPT0(_CRT_WARN, "\n\nMemory Stats:\n" + "--------------------------------------------------\n"); + + _CrtMemState s; + _CrtMemCheckpoint(&s); + _CrtMemDumpStatistics(&s); +#endif +} + +// +--------------------------------------------------------------------+ + +void +Memory::DumpLeaks() +{ +#ifdef _DEBUG + _RPT0(_CRT_WARN, "\n\nMemory Dump Leaks:\n" + "--------------------------------------------------\n"); + _CrtDumpMemoryLeaks(); +#endif +} + +// +--------------------------------------------------------------------+ + +void +Memory::SetLevel(LEVEL l) +{ +#ifdef _DEBUG + mem_chk_level = l; + + _CrtSetDbgFlag(0); + + switch (mem_chk_level) { + case MAXIMAL: CrtSetDebugField(_CRTDBG_CHECK_ALWAYS_DF); + case PERIODIC: CrtSetDebugField(_CRTDBG_DELAY_FREE_MEM_DF); + case LEAKS: CrtSetDebugField(_CRTDBG_LEAK_CHECK_DF); + case OFF: + default: break; + } +#endif +} + diff --git a/FoundationEx/MemDebug.h b/FoundationEx/MemDebug.h new file mode 100644 index 0000000..fcfea5b --- /dev/null +++ b/FoundationEx/MemDebug.h @@ -0,0 +1,91 @@ +/* Project FoundationEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: FoundationEx + FILE: MemDebug.h + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Memory Debugging class +*/ + + +#ifndef MemDebug_h +#define MemDebug_h + +// +--------------------------------------------------------------------+ + +#ifdef WIN32 +#include +#include +#endif + +#ifdef FOUNDATION_USE_MFC + +#ifndef _DEBUG + +inline void* __cdecl operator new(unsigned int s, const char*, int) { return ::operator new(s); } +inline void __cdecl operator delete(void* p, const char*, int) { ::operator delete(p); } + +#else + +void* __cdecl operator new(unsigned int s, const char*, int); +void __cdecl operator delete(void* p, const char*, int); + +#endif + +#else + +// +// MEMORY DEBUGGING NOT SUPPORTED UNDER MFC +// + +// +--------------------------------------------------------------------+ + +class Memory +{ +public: + enum LEVEL { OFF, LEAKS, PERIODIC, MAXIMAL }; + + static void OpenLog(const char* filename=0); + static void CloseLog(); + + static void Check(); + static void Checkpoint(); + static void Stats(); + static void DumpLeaks(); + + static void SetLevel(LEVEL l); +}; + +// +--------------------------------------------------------------------+ + +#ifndef _DEBUG + +inline void* __cdecl operator new(unsigned int s, const char*, int) { return ::operator new(s); } +inline void __cdecl operator delete(void* p, const char*, int) { ::operator delete(p); } + +#else +/*_CRTIMP*/ +void* __cdecl operator new(unsigned int, int, const char*, int); + +inline void* __cdecl operator new(unsigned int s, const char* f, int l) + { return ::operator new(s, 1, f, l); } + +inline void* __cdecl operator new(unsigned int s) + { return ::operator new(s, 1, __FILE__, __LINE__); } + +inline void __cdecl operator delete(void* p, const char*, int) + { ::operator delete(p); } + +#endif _DEBUG + +// +--------------------------------------------------------------------+ + +#endif FOUNDATION_USE_MFC + +#endif MemDebug_h + diff --git a/FoundationEx/Text.cpp b/FoundationEx/Text.cpp new file mode 100644 index 0000000..5f832ea --- /dev/null +++ b/FoundationEx/Text.cpp @@ -0,0 +1,751 @@ +/* Project FoundationEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: FoundationEx + FILE: text.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Implementation of the Text class +*/ + +#include "MemDebug.h" +#include "Text.h" +#include "stdio.h" +#include + +// +-------------------------------------------------------------------+ +// SPECIAL TEXT REP FOR NULL STRINGS +// This is used only by the default constructor for the Text object, +// to prevent extra rep allocation when constructing empty strings. + +TextRep TextRep::nullrep; + +TextRep::TextRep() + : ref(1234567), data(0), length(0), hash(0), sensitive(true) +{ +#ifdef MEM_DEBUG + data = new(__FILE__,__LINE__) char[4]; +#else + data = new char[4]; +#endif + + if (data) + ZeroMemory(data, 4); +} + +// +-------------------------------------------------------------------+ + +ThreadSync TextRep::sync; + + +TextRep::TextRep(const char* s) + : ref(1), length(0), sensitive(true) +{ + if (s) length = ::strlen(s); + +#ifdef MEM_DEBUG + data = new(__FILE__,__LINE__) char[length+1]; +#else + data = new char[length+1]; +#endif + + if (data) { + if (s) ::strcpy(data, s); + else data[length] = '\0'; + + dohash(); + } +} + +TextRep::TextRep(const char* s, int len) + : ref(1), length(len), sensitive(true) +{ + if (length < 0) length = 0; + +#ifdef MEM_DEBUG + data = new(__FILE__,__LINE__) char[length+1]; +#else + data = new char[length+1]; +#endif + + if (data) { + ::CopyMemory(data, s, length); + data[length] = '\0'; + dohash(); + } +} + +TextRep::TextRep(char c, int len) + : ref(1), length(len), sensitive(true) +{ + if (length < 0) length = 0; + +#ifdef MEM_DEBUG + data = new(__FILE__,__LINE__) char[length+1]; +#else + data = new char[length+1]; +#endif + + if (data) { + ::FillMemory(data, length, c); + data[length] = '\0'; + dohash(); + } +} + +TextRep::TextRep(const TextRep* rep) + : ref(1) +{ + length = rep->length; + +#ifdef MEM_DEBUG + data = new(__FILE__,__LINE__) char[length+1]; +#else + data = new char[length+1]; +#endif + + hash = rep->hash; + sensitive = rep->sensitive; + + if (data) + ::strcpy(data, rep->data); +} + +TextRep::~TextRep() +{ + delete[] data; +} + +void +TextRep::addref() +{ + sync.acquire(); + ref++; + sync.release(); +} + +long +TextRep::deref() +{ + sync.acquire(); + long r = --ref; + sync.release(); + return r; +} + +inline static void mash(unsigned& hash, unsigned chars) +{ + hash = (chars ^ ((hash << 5) | (hash >> (8*sizeof(unsigned) - 5)))); +} + +void +TextRep::dohash() +{ + unsigned hv = (unsigned)length; // Mix in the string length. + unsigned i = length*sizeof(char)/sizeof(unsigned); + const unsigned* p = (const unsigned*)data; + + while (i--) + mash(hv, *p++); // XOR in the characters. + + // XOR in any remaining characters: + i = length*sizeof(char)%sizeof(unsigned); + if (i) { + unsigned h = 0; + const char* c = (const char*)p; + while (i--) + h = ((h << 8*sizeof(char)) | *c++); + mash(hv, h); + } + + hash = hv; +} + +// +-------------------------------------------------------------------+ + +Text::Text() +{ + rep = &TextRep::nullrep; + rep->addref(); + sym = rep->data; +} + +Text::Text(char c) +{ + char buf[2]; buf[0] = c; buf[1] = '\0'; + +#ifdef MEM_DEBUG + rep = new(__FILE__,__LINE__) TextRep(buf); +#else + rep = new TextRep(buf); +#endif + + if (!rep) { + rep = &TextRep::nullrep; + rep->addref(); + } + + sym = rep->data; +} + +Text::Text(const char* s) +{ +#ifdef MEM_DEBUG + rep = new(__FILE__,__LINE__) TextRep(s); +#else + rep = new TextRep(s); +#endif + + if (!rep) { + rep = &TextRep::nullrep; + rep->addref(); + } + + sym = rep->data; +} + +Text::Text(const char* s, int len) +{ +#ifdef MEM_DEBUG + rep = new(__FILE__,__LINE__) TextRep(s, len); +#else + rep = new TextRep(s, len); +#endif + + if (!rep) { + rep = &TextRep::nullrep; + rep->addref(); + } + + sym = rep->data; +} + +Text::Text(char c, int len) +{ +#ifdef MEM_DEBUG + rep = new(__FILE__,__LINE__) TextRep(c, len); +#else + rep = new TextRep(c, len); +#endif + + if (!rep) { + rep = &TextRep::nullrep; + rep->addref(); + } + + sym = rep->data; +} + +Text::Text(const Text& s) +{ + rep = s.rep; + rep->addref(); + sym = rep->data; +} + +Text::~Text() +{ + if (rep->deref() == 0) delete rep; + + rep = &TextRep::nullrep; + sym = rep->data; +} + +Text& +Text::operator=(const char* s) +{ + if (rep->deref() == 0) delete rep; +#ifdef MEM_DEBUG + rep = new(__FILE__,__LINE__) TextRep(s); +#else + rep = new TextRep(s); +#endif + + if (!rep) + rep = &TextRep::nullrep; + sym = rep->data; + return *this; +} + +Text& +Text::operator=(const Text& s) +{ + s.rep->addref(); + if (rep->deref() == 0) delete rep; + rep = s.rep; + sym = rep->data; + return *this; +} + +Text +Text::operator+(char c) +{ +#ifdef MEM_DEBUG + char* buf = new(__FILE__,__LINE__) char[rep->length + 2]; +#else + char* buf = new char[rep->length + 2]; +#endif + + if (buf) { + ::strcpy(buf, sym); + buf[rep->length] = c; + buf[rep->length+1] = '\0'; + Text retval(buf); + delete [] buf; + return retval; + } + + else { + return *this; + } +} + +Text +Text::operator+(const char* s) +{ +#ifdef MEM_DEBUG + char* buf = new(__FILE__,__LINE__) char[::strlen(s) + rep->length + 1]; +#else + char* buf = new char[::strlen(s) + rep->length + 1]; +#endif + + if (buf) { + ::strcpy(buf, sym); + ::strcat(buf, s); + Text retval(buf); + delete [] buf; + return retval; + } + + else { + return *this; + } +} + +Text +Text::operator+(const Text& s) +{ +#ifdef MEM_DEBUG + char* buf = new(__FILE__,__LINE__) char[s.rep->length + rep->length + 1]; +#else + char* buf = new char[s.rep->length + rep->length + 1]; +#endif + + if (buf) { + ::strcpy(buf, sym); + ::strcat(buf, s.sym); + Text retval(buf); + delete [] buf; + return retval; + } + + else { + return *this; + } +} + +bool +Text::isSensitive() const +{ + return rep->sensitive; +} + +void +Text::setSensitive(bool s) +{ + rep->sensitive = s; +} + +Text& +Text::append(char c) +{ +#ifdef MEM_DEBUG + char* buf = new(__FILE__,__LINE__) char[rep->length + 2]; +#else + char* buf = new char[rep->length + 2]; +#endif + + if (buf) { + ::strcpy(buf, sym); + buf[rep->length] = c; + buf[rep->length+1] = '\0'; + if (rep->deref() == 0) delete rep; + +#ifdef MEM_DEBUG + rep = new(__FILE__,__LINE__) TextRep(buf); +#else + rep = new TextRep(buf); +#endif + + if (!rep) + rep = &TextRep::nullrep; + + sym = rep->data; + delete [] buf; + } + + return *this; +} + +Text& +Text::append(const char* s) +{ +#ifdef MEM_DEBUG + char* buf = new(__FILE__,__LINE__) char[::strlen(s) + rep->length + 1]; +#else + char* buf = new char[::strlen(s) + rep->length + 1]; +#endif + + if (buf) { + ::strcpy(buf, sym); + ::strcat(buf, s); + if (rep->deref() == 0) delete rep; + +#ifdef MEM_DEBUG + rep = new(__FILE__,__LINE__) TextRep(buf); +#else + rep = new TextRep(buf); +#endif + + if (!rep) + rep = &TextRep::nullrep; + + sym = rep->data; + delete [] buf; + } + + return *this; +} + +Text& +Text::append(const Text& s) +{ +#ifdef MEM_DEBUG + char* buf = new(__FILE__,__LINE__) char[s.rep->length + rep->length + 1]; +#else + char* buf = new char[s.rep->length + rep->length + 1]; +#endif + + if (buf) { + int lenA = rep->length; + int lenB = s.rep->length; + + CopyMemory(buf, sym, lenA); + CopyMemory(buf + lenA, s.sym, lenB); + buf[lenA + lenB] = 0; + + if (rep->deref() == 0) delete rep; + +#ifdef MEM_DEBUG + rep = new(__FILE__,__LINE__) TextRep(buf, lenA + lenB); +#else + rep = new TextRep(buf); +#endif + + if (!rep) + rep = &TextRep::nullrep; + + sym = rep->data; + delete [] buf; + } + + return *this; +} + +void +Text::clone() +{ + if (rep->ref > 1) { + rep->deref(); + +#ifdef MEM_DEBUG + TextRep* t = new(__FILE__,__LINE__) TextRep(rep); +#else + TextRep* t = new TextRep(rep); +#endif + + rep = t; + + if (!rep) + rep = &TextRep::nullrep; + + sym = rep->data; + } +} + +char +Text::operator[](int index) const +{ + if (index < (int) rep->length) + return sym[index]; + else + throw "BOUNDS ERROR"; + + return '\0'; +} + +char +Text::operator()(int index) const +{ + return sym[index]; +} + +char& +Text::operator[](int index) +{ + if (index < (int) rep->length) { + clone(); + return (char&) sym[index]; + } + else + throw "BOUNDS ERROR"; + + return (char&) sym[0]; +} + +char& +Text::operator()(int index) +{ + clone(); + return (char&) sym[index]; +} + +Text +Text::operator()(int start, int len) const +{ + if (start > rep->length || len <= 0) + return Text(); + + if (start + len > rep->length) + len = rep->length - start; + +#ifdef MEM_DEBUG + char* buf = new(__FILE__,__LINE__) char[len+1]; +#else + char* buf = new char[len+1]; +#endif + + if (buf) { + ::strncpy(buf, sym+start, len); + buf[len] = '\0'; + + Text retval(buf); + delete [] buf; + return retval; + } + + return Text(); +} + +bool +Text::contains(char c) const +{ + if (rep->length > 0) { + if (!rep->sensitive) { + char alt = c; + if (islower(alt)) alt = toupper(alt); + else if (isupper(alt)) alt = tolower(alt); + + if (strchr(rep->data, alt) != 0) + return true; + } + + if (strchr(rep->data, c) != 0) + return true; + } + + return false; +} + +bool +Text::contains(const char* pattern) const +{ + if (rep->length > 0 && pattern && *pattern) { + if (rep->sensitive) { + if (strstr(rep->data, pattern) != 0) + return true; + } + else { + Text smash1(*this); + smash1.toLower(); + Text smash2(pattern); + smash2.toLower(); + + if (strstr(smash1.data(), smash2.data()) != 0) + return true; + } + } + + return false; +} + +bool +Text::containsAnyOf(const char* charSet) const +{ + if (rep->length > 0 && charSet && *charSet) { + if (rep->sensitive) { + if (strpbrk(rep->data, charSet) != 0) + return true; + } + else { + Text smash1(*this); + smash1.toLower(); + Text smash2(charSet); + smash2.toLower(); + + if (strpbrk(smash1.data(), smash2.data()) != 0) + return true; + } + } + + return false; +} + +int +Text::indexOf(char c) const +{ + if (rep->length > 0) { + if (!rep->sensitive) { + char alt = c; + if (islower(alt)) alt = toupper(alt); + else if (isupper(alt)) alt = tolower(alt); + + const char* p = strchr(rep->data, alt); + + if (p) + return (p - rep->data); + } + + const char* p = strchr(rep->data, c); + + if (p) + return (p - rep->data); + } + + return -1; +} + +int +Text::indexOf(const char* pattern) const +{ + if (rep->length > 0 && pattern && *pattern) { + if (rep->sensitive) { + const char* p = strstr(rep->data, pattern); + if (p) return (p - rep->data); + } + else { + Text smash1(*this); + smash1.toLower(); + Text smash2(pattern); + smash2.toLower(); + + const char* p = strstr(smash1.data(), smash2.data()); + if (p) return (p - smash1.data()); + } + } + + return -1; +} + +void +Text::toLower() +{ + clone(); + size_t n = rep->length; + char* p = (char*) sym; + while (n--) { + *p = tolower((unsigned char)*p); + p++; + } + + rep->dohash(); +} + +void +Text::toUpper() +{ + clone(); + size_t n = rep->length; + char* p = (char*) sym; + while ( n-- ) { + *p = toupper((unsigned char)*p); + p++; + } + + rep->dohash(); +} + +Text +Text::substring(int start, int length) +{ + Text result; + + if (start >= 0 && start < (int) rep->length && length > 0) { + if (start + length > (int) rep->length) + length = (int) rep->length - start; + + const char* s = sym + start; + +#ifdef MEM_DEBUG + result.rep = new(__FILE__,__LINE__) TextRep(s, length); +#else + result.rep = new TextRep(s, length); +#endif + + if (!result.rep) + result.rep = &TextRep::nullrep; + + result.sym = result.rep->data; + } + + return result; +} + +Text +Text::trim() +{ + Text result; + + if (rep->length) { + const char* p = sym; + const char* q = sym + rep->length-1; + + while (p && *p && isspace(*p)) p++; + while (q>p && *q && isspace(*q)) q--; + + result = substring(p-sym, q-p+1); + } + + return result; +} + +Text +Text::replace(const char* pattern, const char* substitution) +{ + Text result; + + if (rep->length && pattern && *pattern) { + int index = 0; + int skip = strlen(pattern); + do { + const char* p = strstr(rep->data + index, pattern); + if (p) { + int len = (p - rep->data + index); + result.append(substring(index, len)); + result.append(substitution); + index += len + skip; + } + else if (index < rep->length) { + result.append(substring(index, rep->length-index)); + index = -1; + } + } + while (index >= 0 && index < rep->length); + } + + return result; +} diff --git a/FoundationEx/Text.h b/FoundationEx/Text.h new file mode 100644 index 0000000..cb037ef --- /dev/null +++ b/FoundationEx/Text.h @@ -0,0 +1,193 @@ +/* Project FoundationEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: FoundationEx + FILE: Text.h + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Declaration of the Text class +*/ + +#ifndef Text_h +#define Text_h + +#include +#include +#include "ThreadSync.h" + +// +-------------------------------------------------------------------+ + +class TextRep +{ + friend class Text; + +public: + TextRep(); + ~TextRep(); + +private: + TextRep(const char* s); + TextRep(const char* s, int len); + TextRep(char c, int len); + TextRep(const TextRep* rep); + + void addref(); + long deref(); + + void dohash(); + + char* data; + long ref; + int length; + unsigned hash; + bool sensitive; + + static ThreadSync sync; + static TextRep nullrep; +}; + +// +-------------------------------------------------------------------+ + +class Text +{ +public: + static const char* TYPENAME() { return "Text"; } + + Text(); + Text(char c); + Text(const char* s); + Text(const char* s, int len); + Text(char c, int len); + Text(const Text& s); + ~Text(); + + // case sensitivity + bool isSensitive() const; + void setSensitive(bool s); + + // comparison + int compare(const char* s) const; + int compare(const Text& s) const; + + // assignment + Text& operator=(const char* s); + Text& operator=(const Text& s); + + // catenation + Text& append(char c); + Text& append(const char* s); + Text& append(const Text& s); + + Text operator+(char c); + Text operator+(const char* s); + Text operator+(const Text& s); + + Text& operator+=(char c) { return append(c); } + Text& operator+=(const char* s) { return append(s); } + Text& operator+=(const Text& s) { return append(s); } + + // indexing + char operator[](int index) const; + char operator()(int index) const; + char& operator[](int index); + char& operator()(int index); + + Text operator()(int start, int len) const; + + // access + int length() const { return rep->length; } + unsigned hash() const { return rep->hash; } + + const char* data() const { return sym; } + operator const char* () const { return sym; } + + bool contains(char c) const; + bool contains(const char* s) const; + + bool containsAnyOf(const char* charSet) const; + + int indexOf(char c) const; + int indexOf(const char* s) const; + + // mutation + void toLower(); + void toUpper(); + + // substring + Text substring(int start, int length); + Text trim(); + Text replace(const char* pattern, const char* substitution); + +private: + void clone(); + + const char* sym; + TextRep* rep; +}; + +// +-------------------------------------------------------------------+ + +inline int Text::compare(const char* s) const +{ + if (rep->sensitive) + return strcmp(sym, s); + else + return stricmp(sym, s); +} + +inline int Text::compare(const Text& s) const +{ + if (rep->sensitive && s.rep->sensitive) + return strcmp(sym, s.sym); + else + return stricmp(sym, s.sym); +} + +// +-------------------------------------------------------------------+ + +inline int operator==(const Text& l, const Text& r) { + return (l.length() == r.length()) && (l.compare(r) == 0); } +inline int operator!=(const Text& l, const Text& r) { return l.compare(r) != 0; } +inline int operator< (const Text& l, const Text& r) { return l.compare(r) < 0; } +inline int operator<=(const Text& l, const Text& r) { return l.compare(r) <= 0; } +inline int operator> (const Text& l, const Text& r) { return l.compare(r) > 0; } +inline int operator>=(const Text& l, const Text& r) { return l.compare(r) >= 0; } + +inline int operator==(const char* l, const Text& r) { return r.compare(l) == 0; } +inline int operator!=(const char* l, const Text& r) { return r.compare(l) != 0; } +inline int operator< (const char* l, const Text& r) { return r.compare(l) < 0; } +inline int operator<=(const char* l, const Text& r) { return r.compare(l) <= 0; } +inline int operator> (const char* l, const Text& r) { return r.compare(l) > 0; } +inline int operator>=(const char* l, const Text& r) { return r.compare(l) >= 0; } + +inline int operator==( char* l, const Text& r) { return r.compare(l) == 0; } +inline int operator!=( char* l, const Text& r) { return r.compare(l) != 0; } +inline int operator< ( char* l, const Text& r) { return r.compare(l) < 0; } +inline int operator<=( char* l, const Text& r) { return r.compare(l) <= 0; } +inline int operator> ( char* l, const Text& r) { return r.compare(l) > 0; } +inline int operator>=( char* l, const Text& r) { return r.compare(l) >= 0; } + +inline int operator==(const Text& l, const char* r) { return l.compare(r) == 0; } +inline int operator!=(const Text& l, const char* r) { return l.compare(r) != 0; } +inline int operator< (const Text& l, const char* r) { return l.compare(r) < 0; } +inline int operator<=(const Text& l, const char* r) { return l.compare(r) <= 0; } +inline int operator> (const Text& l, const char* r) { return l.compare(r) > 0; } +inline int operator>=(const Text& l, const char* r) { return l.compare(r) >= 0; } + +inline int operator==(const Text& l, char* r) { return l.compare(r) == 0; } +inline int operator!=(const Text& l, char* r) { return l.compare(r) != 0; } +inline int operator< (const Text& l, char* r) { return l.compare(r) < 0; } +inline int operator<=(const Text& l, char* r) { return l.compare(r) <= 0; } +inline int operator> (const Text& l, char* r) { return l.compare(r) > 0; } +inline int operator>=(const Text& l, char* r) { return l.compare(r) >= 0; } + +inline Text operator+(const char* l, const Text& r) { return Text(l) + r; } +inline Text operator+( char* l, const Text& r) { return Text(l) + r; } + +// +-------------------------------------------------------------------+ + +#endif Text_h diff --git a/FoundationEx/ThreadSync.h b/FoundationEx/ThreadSync.h new file mode 100644 index 0000000..274bb7f --- /dev/null +++ b/FoundationEx/ThreadSync.h @@ -0,0 +1,57 @@ +/* Project nGen + John DiCamillo + Copyright © 1997-2001. All Rights Reserved. + + SUBSYSTEM: foundation + FILE: ThreadSync.h + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Declaration of the ThreadSync class +*/ + +#ifndef ThreadSync_h +#define ThreadSync_h + +#include + +// +-------------------------------------------------------------------+ + +class ThreadSync +{ +#if defined(_MT) // MULTITHREADED: WITH SYNC ------------ + CRITICAL_SECTION sync; + +public: + ThreadSync() { ::InitializeCriticalSection(&sync); } + ~ThreadSync() { ::DeleteCriticalSection(&sync); } + + void acquire() { ::EnterCriticalSection(&sync); } + void release() { ::LeaveCriticalSection(&sync); } + +#else // SINGLE THREADED: NO SYNC ------------ + +public: + ThreadSync() { } + ~ThreadSync() { } + + void acquire() { } + void release() { } + +#endif +}; + +// +-------------------------------------------------------------------+ + +class AutoThreadSync +{ +public: + AutoThreadSync(ThreadSync& s) : sync(s) { sync.acquire(); } + ~AutoThreadSync() { sync.release(); } +private: + ThreadSync& sync; +}; + +#endif ThreadSync_h -- cgit v1.1