summaryrefslogtreecommitdiffhomepage
path: root/FoundationEx/include
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2024-03-12 01:08:39 +0100
committerAki <please@ignore.pl>2024-03-12 01:08:39 +0100
commitf43d32d6d2cc7ecd04f4f06f20d5a6fc2c87c9ae (patch)
tree0f82962432f9cd4fae60dd37c8935c1bc28f29e5 /FoundationEx/include
parent2914a714cebae7f30d47362dfe50c39cb6621163 (diff)
downloadstarshatter-f43d32d6d2cc7ecd04f4f06f20d5a6fc2c87c9ae.zip
starshatter-f43d32d6d2cc7ecd04f4f06f20d5a6fc2c87c9ae.tar.gz
starshatter-f43d32d6d2cc7ecd04f4f06f20d5a6fc2c87c9ae.tar.bz2
Another reorganization change that diverts me from crying unable to get rid off singleton madness
Diffstat (limited to 'FoundationEx/include')
-rw-r--r--FoundationEx/include/Dictionary.h100
-rw-r--r--FoundationEx/include/Dictionary.inl.h246
-rw-r--r--FoundationEx/include/List.h106
-rw-r--r--FoundationEx/include/List.inl.h432
-rw-r--r--FoundationEx/include/Reader.h70
-rw-r--r--FoundationEx/include/Text.h211
-rw-r--r--FoundationEx/include/Utils.h18
7 files changed, 1183 insertions, 0 deletions
diff --git a/FoundationEx/include/Dictionary.h b/FoundationEx/include/Dictionary.h
new file mode 100644
index 0000000..bcb30ed
--- /dev/null
+++ b/FoundationEx/include/Dictionary.h
@@ -0,0 +1,100 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Declaration of the Dictionary class
+*/
+
+#ifndef Dictionary_h
+#define Dictionary_h
+
+#include "Text.h"
+
+// +-------------------------------------------------------------------+
+
+template <class T> class Dictionary;
+template <class T> class DictionaryIter;
+template <class T> class DictionaryCell;
+
+// +-------------------------------------------------------------------+
+
+template <class T> 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<T>* PTR;
+ PTR table[256];
+
+ friend class DictionaryIter<T>;
+};
+
+// +-------------------------------------------------------------------+
+
+template <class T> class DictionaryIter
+{
+public:
+ DictionaryIter(Dictionary<T>& l);
+ ~DictionaryIter();
+
+ int operator++(); // prefix
+
+ void reset();
+ void forth();
+
+ Text key() const;
+ T value() const;
+
+ void attach(Dictionary<T>& l);
+ Dictionary<T>& container();
+
+private:
+ Dictionary<T>* dict;
+ DictionaryCell<T>* here;
+ int chain;
+};
+
+// +-------------------------------------------------------------------+
+
+template <class T> 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<T>* next;
+};
+
+// +-------------------------------------------------------------------+
+
+#include "Dictionary.inl.h"
+#endif // Dictionary_h
+
diff --git a/FoundationEx/include/Dictionary.inl.h b/FoundationEx/include/Dictionary.inl.h
new file mode 100644
index 0000000..cd58679
--- /dev/null
+++ b/FoundationEx/include/Dictionary.inl.h
@@ -0,0 +1,246 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+
+ 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 <class T> Dictionary<T>::Dictionary()
+ : items(0)
+{ init(); }
+
+template <class T> Dictionary<T>::~Dictionary()
+{ clear(); }
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+void Dictionary<T>::init()
+{
+ items = 0;
+ memset(table, 0, CHAINS*sizeof(PTR));
+}
+
+template <class T>
+void Dictionary<T>::clear()
+{
+ for (int i = 0; i < CHAINS; i++) {
+ DictionaryCell<T>* link = table[i];
+
+ while (link) {
+ DictionaryCell<T>* n = link->next;
+ delete link;
+ link = n;
+ }
+ }
+
+ init();
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+T& Dictionary<T>::operator[](const Text& key)
+{
+ int idx = key.hash() % CHAINS;
+ DictionaryCell<T>* cell = table[idx];
+
+ if (cell == 0) { // empty chain
+ items++;
+ cell = new DictionaryCell<T>(key);
+ 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++;
+ cell->next = new DictionaryCell<T>(key);
+ return cell->next->value;
+ }
+ else { // found: return it!
+ return cell->value;
+ }
+ }
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+void Dictionary<T>::insert(const Text& key, const T& val)
+{
+ T& value = operator[](key);
+ value = val;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+void Dictionary<T>::remove(const Text& key)
+{
+ int idx = key.hash() % CHAINS;
+ DictionaryCell<T>* 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<T>* p = table[idx];
+ while (p->next != cell)
+ p = p->next;
+ p->next = cell->next;
+ delete cell;
+ }
+ }
+ }
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+int Dictionary<T>::contains(const Text& key) const
+{
+ int idx = key.hash() % CHAINS;
+ DictionaryCell<T>* cell = table[idx];
+
+ if (cell != 0) {
+ while (cell->next && cell->key != key)
+ cell = cell->next;
+
+ if (cell->key == key)
+ return 1;
+ }
+
+ return 0;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+T Dictionary<T>::find(const Text& key, T defval) const
+{
+ int idx = key.hash() % CHAINS;
+ DictionaryCell<T>* 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 <class T> DictionaryIter<T>::DictionaryIter(Dictionary<T>& d)
+ : dict(&d), chain(0), here(0)
+{ }
+
+template <class T> DictionaryIter<T>::~DictionaryIter()
+{ }
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+void DictionaryIter<T>::reset()
+{
+ chain = 0;
+ here = 0;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+Text DictionaryIter<T>::key() const
+{
+ return here->key;
+}
+
+template <class T>
+T DictionaryIter<T>::value() const
+{
+ return here->value;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+int DictionaryIter<T>::operator++()
+{
+ forth();
+ int more = chain < CHAINS;
+ return more;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+void DictionaryIter<T>::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 <class T>
+void DictionaryIter<T>::attach(Dictionary<T>& d)
+{
+ dict = &d;
+ reset();
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+Dictionary<T>& DictionaryIter<T>::container()
+{
+ return *dict;
+}
+
diff --git a/FoundationEx/include/List.h b/FoundationEx/include/List.h
new file mode 100644
index 0000000..54dfcb1
--- /dev/null
+++ b/FoundationEx/include/List.h
@@ -0,0 +1,106 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Declaration of the List class template
+*/
+
+#ifndef List_h
+#define List_h
+
+// +-------------------------------------------------------------------+
+
+template <class T> class List;
+template <class T> class ListIter;
+
+// +-------------------------------------------------------------------+
+
+template <class T> class List
+{
+public:
+ List() : items(0), extent(0), array(0) { }
+ List(const List<T>& 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<T>& 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<T>;
+};
+
+// +-------------------------------------------------------------------+
+
+template <class T> class ListIter
+{
+public:
+ ListIter() : list(0), step(-1) { }
+ ListIter(const ListIter<T>& i) : list(i.list), step(i.step) { }
+ ListIter(List<T>& 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<T>& l);
+ List<T>& container();
+ int size();
+ int index() { return step; }
+
+private:
+ List<T>* list;
+ int step;
+};
+
+#include "List.inl.h"
+#endif // List_h
+
diff --git a/FoundationEx/include/List.inl.h b/FoundationEx/include/List.inl.h
new file mode 100644
index 0000000..9ccb796
--- /dev/null
+++ b/FoundationEx/include/List.inl.h
@@ -0,0 +1,432 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Implementation of the List class template
+*/
+
+#include <stdlib.h>
+
+#include "Utils.h"
+
+
+template <class T>
+List<T>::List(const List<T>& l)
+ : items(l.items), extent(l.extent)
+{
+ array = new PTR[extent];
+ for (int i = 0; i < extent; i++)
+ array[i] = l.array[i];
+}
+
+template <class T>
+void List<T>::clear()
+{
+ delete [] array;
+ items = 0;
+ extent = 0;
+ array = 0;
+}
+
+template <class T>
+void List<T>::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 <class T>
+bool List<T>::check(int& index) const
+{
+ if (index < 0) {
+ Print("Bounds error in List(%08p) T=%s index=%d min=0\n", this, T::TYPENAME(), index);
+ index = 0;
+ }
+
+ else if (index >= items) {
+ Print("Bounds error in List(%08p) T=%s index=%d max=%d\n", this, T::TYPENAME(), index, items-1);
+ index = items-1;
+ }
+
+ return (index >= 0 && index < items);
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+T*& List<T>::operator[](int index)
+{
+ if (check(index))
+ return array[index];
+
+ if (!array || !extent)
+ resize(1);
+
+ return array[0];
+}
+
+template <class T>
+T* List<T>::operator[](int index) const
+{
+ if (check(index))
+ return array[index];
+ return 0;
+}
+
+template <class T>
+T*& List<T>::at(int index)
+{
+ if (check(index))
+ return array[index];
+
+ if (!array || !extent)
+ resize(1);
+
+ return array[0];
+}
+
+template <class T>
+T* List<T>::at(int index) const
+{
+ if (check(index))
+ return array[index];
+ return 0;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+void List<T>::resize(int newsize)
+{
+ if (newsize > extent) {
+ extent = 16 * (newsize/16 + 1);
+ T** v = new PTR[extent];
+ int i;
+ for (i = 0; i < items; i++)
+ v[i] = array[i];
+
+ for (; i < extent; i++)
+ v[i] = 0;
+
+ delete [] array;
+ array = v;
+ }
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+void List<T>::append(const T* item)
+{
+ if (item) {
+ if (items+1 > extent) resize(items+1);
+ array[items++] = (T*)item;
+ }
+}
+
+template <class T>
+void List<T>::append(List<T>& 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 <class T>
+void List<T>::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 <class T>
+void List<T>::insertSort(const T* item)
+{
+ if (item) {
+ int i;
+ for (i = 0; i < items; i++) {
+ if (*item < *array[i])
+ break;
+ }
+
+ insert(item, i);
+ }
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+T* List<T>::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 <class T>
+T* List<T>::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 <class T>
+bool List<T>::contains(const T* val) const
+{
+ if (val) {
+ if (index(val) != -1)
+ return true;
+ }
+
+ return false;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+int List<T>::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 <class T>
+int List<T>::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 <class T>
+T* List<T>::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 <class T>
+void List<T>::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 <class T>
+void List<T>::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 <class T>
+void List<T>::sort()
+{
+ if (items < 2)
+ return;
+
+ qsort(array, 0, items-1);
+}
+
+template <class T>
+void List<T>::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 <class T>
+T* ListIter<T>::value()
+{
+ if (list && step >= 0 && step < list->items)
+ return list->array[step];
+
+ return 0;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+T* ListIter<T>::removeItem()
+{
+ if (list && step >= 0 && step < list->items)
+ return list->removeIndex(step--);
+
+ return 0;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+T* ListIter<T>::next()
+{
+ if (list && step >= -1 && step < list->items-1)
+ return list->array[++step];
+
+ return 0;
+}
+
+template <class T>
+T* ListIter<T>::prev()
+{
+ if (list && step > 0 && step < list->items)
+ return list->array[--step];
+
+ return 0;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+void ListIter<T>::attach(List<T>& l)
+{
+ list = &l;
+ step = -1;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+int ListIter<T>::size()
+{
+ if (!list) return 0;
+ return list->items;
+}
+
+// +-------------------------------------------------------------------+
+
+template <class T>
+List<T>& ListIter<T>::container()
+{
+ return *list;
+}
+
diff --git a/FoundationEx/include/Reader.h b/FoundationEx/include/Reader.h
new file mode 100644
index 0000000..ed6aebc
--- /dev/null
+++ b/FoundationEx/include/Reader.h
@@ -0,0 +1,70 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Declaration of the Reader class
+*/
+
+#ifndef Reader_h
+#define Reader_h
+
+#include "Text.h"
+
+
+class Reader
+{
+public:
+ Reader() { }
+ virtual ~Reader() { }
+
+ virtual Text more() = 0;
+};
+
+
+class ConsoleReader : public Reader
+{
+public:
+ virtual Text more() override;
+
+ void printPrimaryPrompt();
+ void fillInputBuffer();
+
+private:
+ char buffer[1000];
+ char* p;
+};
+
+
+class FileReader : public Reader
+{
+public:
+ FileReader(const char* fname);
+ virtual Text more() override;
+
+private:
+ Text filename;
+ int done;
+};
+
+
+class BlockReader : public Reader
+{
+public:
+ BlockReader(const char* block);
+ BlockReader(const char* block, int len);
+ virtual Text more();
+
+private:
+ char* data;
+ int done;
+ int length;
+};
+
+
+#endif // Reader_h
diff --git a/FoundationEx/include/Text.h b/FoundationEx/include/Text.h
new file mode 100644
index 0000000..4cf5cc4
--- /dev/null
+++ b/FoundationEx/include/Text.h
@@ -0,0 +1,211 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Declaration of the Text class
+*/
+
+#ifndef Text_h
+#define Text_h
+
+#include <atomic>
+#include <cstring>
+#include <ostream>
+
+#ifndef _WIN32
+#include <strings.h>
+#endif
+
+// +-------------------------------------------------------------------+
+
+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;
+ std::atomic<long> ref;
+ int length;
+ unsigned hash;
+ bool sensitive;
+
+ 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();
+
+ friend std::ostream& operator<<(std::ostream& out, const Text& 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 empty() const;
+
+ 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);
+ Text concat(const char* tail) const;
+ static Text format(const char* fmt, ...);
+
+private:
+ void clone();
+
+ const char* sym;
+ TextRep* rep;
+};
+
+// +-------------------------------------------------------------------+
+
+inline int Text::compare(const char* s) const
+{
+ if (rep->sensitive)
+ return strcmp(sym, s);
+ else
+#ifdef _WIN32
+ return _stricmp(sym, s);
+#else
+ return strcasecmp(sym, s);
+#endif
+}
+
+inline int Text::compare(const Text& s) const
+{
+ if (rep->sensitive && s.rep->sensitive)
+ return strcmp(sym, s.sym);
+ else
+#ifdef _WIN32
+ return _stricmp(sym, s.sym);
+#else
+ return strcasecmp(sym, s.sym);
+#endif
+}
+
+// +-------------------------------------------------------------------+
+
+inline std::ostream& operator<<(std::ostream& out, const Text& text) {
+ out << text.data(); return out; }
+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/include/Utils.h b/FoundationEx/include/Utils.h
new file mode 100644
index 0000000..731bc01
--- /dev/null
+++ b/FoundationEx/include/Utils.h
@@ -0,0 +1,18 @@
+/* Starshatter: The Open Source Project
+ Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors
+ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors
+ Copyright (c) 1997-2006, Destroyer Studios LLC.
+*/
+
+#ifndef Utils_h
+#define Utils_h
+
+#include <stdio.h>
+
+
+void AssignErrLog(FILE * out);
+int CloseErrLog();
+void Print(const char* fmt, ...);
+
+
+#endif // Utils_h