diff options
author | Rodrigo Arias Mallo <rodarima@gmail.com> | 2024-12-10 22:30:12 +0100 |
---|---|---|
committer | Rodrigo Arias Mallo <rodarima@gmail.com> | 2024-12-10 22:30:12 +0100 |
commit | 429d5f88b94ff28416cbfc6420b6389fa284df97 (patch) | |
tree | fb6fdaf7731de1ef396f98b748c56f3149801c84 /lout/container.cc |
Import RTFL 0.1.1v0.1.1
Diffstat (limited to 'lout/container.cc')
-rw-r--r-- | lout/container.cc | 813 |
1 files changed, 813 insertions, 0 deletions
diff --git a/lout/container.cc b/lout/container.cc new file mode 100644 index 0000000..9ed14d8 --- /dev/null +++ b/lout/container.cc @@ -0,0 +1,813 @@ +/* + * RTFL (originally part of dillo) + * + * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version; with the following exception: + * + * The copyright holders of RTFL give you permission to link this file + * statically or dynamically against all versions of the graphviz + * library, which are published by AT&T Corp. under one of the following + * licenses: + * + * - Common Public License version 1.0 as published by International + * Business Machines Corporation (IBM), or + * - Eclipse Public License version 1.0 as published by the Eclipse + * Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define PRINTF(fmt, ...) +//#define PRINTF printf + +#include "container.hh" +#include "misc.hh" +#include "debug.hh" + +namespace lout { + +using namespace object; + +namespace container { + +namespace untyped { + +// ------------- +// Iterator +// ------------- + +Iterator::Iterator() +{ + impl = NULL; +} + +Iterator::Iterator(const Iterator &it2) +{ + impl = it2.impl; + if (impl) + impl->ref(); +} + +Iterator::Iterator(Iterator &it2) +{ + impl = it2.impl; + if (impl) + impl->ref(); +} + +Iterator &Iterator::operator=(const Iterator &it2) +{ + if (impl) + impl->unref(); + impl = it2.impl; + if (impl) + impl->ref(); + return *this; +} + +Iterator &Iterator::operator=(Iterator &it2) +{ + if (impl) + impl->unref(); + impl = it2.impl; + if (impl) + impl->ref(); + return *this; +} + +Iterator::~Iterator() +{ + if (impl) + impl->unref(); +} + +// ---------------- +// Collection +// ---------------- + +void Collection::intoStringBuffer(misc::StringBuffer *sb) +{ + sb->append("{ "); + bool first = true; + for (Iterator it = iterator(); it.hasNext(); ) { + if (!first) + sb->append(", "); + it.getNext()->intoStringBuffer(sb); + first = false; + } + sb->append(" }"); +} + +// ------------ +// Vector +// ------------ + +Vector::Vector(int initSize, bool ownerOfObjects) +{ + DBG_OBJ_CREATE ("lout::container::untyped::Vector"); + + numAlloc = initSize == 0 ? 1 : initSize; + this->ownerOfObjects = ownerOfObjects; + numElements = 0; + array = (Object**)malloc(numAlloc * sizeof(Object*)); +} + +Vector::~Vector() +{ + clear(); + free(array); + + DBG_OBJ_DELETE (); +} + +int Vector::size () +{ + return numElements; +} + +void Vector::put(Object *newElement, int newPos) +{ + if (newPos == -1) + newPos = numElements; + + // Old entry is overwritten. + if (newPos < numElements) { + if (ownerOfObjects && array[newPos]) + delete array[newPos]; + } + + // Allocated memory has to be increased. + if (newPos >= numAlloc) { + while (newPos >= numAlloc) + numAlloc *= 2; + array = (Object**)realloc(array, numAlloc * sizeof(Object*)); + } + + // Insert NULL's into possible gap before new position. + for (int i = numElements; i < newPos; i++) + array[i] = NULL; + + if (newPos >= numElements) + numElements = newPos + 1; + + array[newPos] = newElement; +} + +void Vector::clear() +{ + if (ownerOfObjects) { + for (int i = 0; i < numElements; i++) + if (array[i]) + delete array[i]; + } + + numElements = 0; +} + +void Vector::insert(Object *newElement, int pos) +{ + if (pos >= numElements) + put(newElement, pos); + else { + numElements++; + + // Allocated memory has to be increased. + if (numElements >= numAlloc) { + numAlloc *= 2; + array = (Object**)realloc(array, numAlloc * sizeof(Object*)); + } + + for (int i = numElements - 1; i > pos; i--) + array[i] = array[i - 1]; + + array[pos] = newElement; + } +} + +void Vector::remove(int pos) +{ + if (ownerOfObjects && array[pos]) + delete array[pos]; + + for (int i = pos + 1; i < numElements; i++) + array[i - 1] = array[i]; + + numElements--; +} + +/** + * Sort the elements in the vector. Assumes that all elements are Comparable's. + */ +void Vector::sort(Comparator *comparator) +{ + Comparator::compareFunComparator = comparator; + qsort (array, numElements, sizeof(Object*), Comparator::compareFun); +} + +/** + * \brief Use binary search to find an element in a sorted vector. + * + * If "mustExist" is true, only exact matches are found; otherwise, -1 + * is returned. If it is false, the position of the next greater + * element is returned, or, if the key is the greatest element, the + * size of the array. (This is the value which can be used for + * insertion; see insertSortet()). + */ +int Vector::bsearch(Object *key, bool mustExist, int start, int end, + Comparator *comparator) +{ + // The case !mustExist is not handled by bsearch(3), so here is a + // new implementation. + + DBG_OBJ_MSGF ("container", 0, + "<b>bsearch</b> (<i>key</i>, %s, %d, %d, <i>comparator</i>) " + "[size is %d]", + mustExist ? "true" : "false", start, end, size ()); + DBG_OBJ_MSG_START (); + + int result = -123; // Compiler happiness: GCC 4.7 does not handle this? + + if (start > end) { + DBG_OBJ_MSG ("container", 1, "empty"); + result = mustExist ? -1 : start; + } else { + int low = start, high = end; + bool found = false; + + while (!found) { + int index = (low + high) / 2; + int c = comparator->compare (key, array[index]); + DBG_OBJ_MSGF ("container", 1, + "searching within %d and %d; compare key with #%d => %d", + low, high, index, c); + if (c == 0) { + found = true; + result = index; + } else { + if (low >= high) { + if (mustExist) { + found = true; + result = -1; + } else { + found = true; + result = c > 0 ? index + 1 : index; + } + } + + if (c < 0) + high = index - 1; + else + low = index + 1; + } + } + } + + DBG_OBJ_MSGF ("container", 1, "result = %d", result); + DBG_OBJ_MSG_END (); + return result; +} + +Object *Vector::VectorIterator::getNext() +{ + if (index < vector->numElements - 1) + index++; + + return index < vector->numElements ? vector->array[index] : NULL; +} + +bool Vector::VectorIterator::hasNext() +{ + return index < vector->numElements - 1; +} + +Collection0::AbstractIterator* Vector::createIterator() +{ + return new VectorIterator(this); +} + +// ------------ +// List +// ------------ + +List::List(bool ownerOfObjects) +{ + this->ownerOfObjects = ownerOfObjects; + first = last = NULL; + numElements = 0; +} + +List::~List() +{ + clear(); +} + +int List::size () +{ + return numElements; +} + +bool List::equals(Object *other) +{ + List *otherList = (List*)other; + Node *node1 = first, *node2 = otherList->first; + while (node1 != NULL && node2 != NULL ) { + if (!node1->object->equals (node2->object)) + return false; + node1 = node1->next; + node2 = node2->next; + } + return node1 == NULL && node2 == NULL; +} + +int List::hashValue() +{ + int h = 0; + for (Node *node = first; node; node = node->next) + h = h ^ node->object->hashValue (); + return h; +} + +void List::clear() +{ + while (first) { + if (ownerOfObjects && first->object) + delete first->object; + Node *next = first->next; + delete first; + first = next; + } + + last = NULL; + numElements = 0; +} + +void List::append(Object *element) +{ + Node *newLast = new Node; + newLast->next = NULL; + newLast->object = element; + + if (last) { + last->next = newLast; + last = newLast; + } else + first = last = newLast; + + numElements++; +} + +bool List::insertBefore(object::Object *beforeThis, object::Object *neew) +{ + Node *beforeCur, *cur; + + for (beforeCur = NULL, cur = first; cur; beforeCur = cur, cur = cur->next) { + if (cur->object == beforeThis) { + Node *newNode = new Node; + newNode->next = cur; + newNode->object = neew; + + if (beforeCur) + beforeCur->next = newNode; + else + first = newNode; + + numElements++; + return true; + } + } + + return false; +} + +bool List::remove0(Object *element, bool compare, bool doNotDeleteAtAll) +{ + Node *beforeCur, *cur; + + for (beforeCur = NULL, cur = first; cur; beforeCur = cur, cur = cur->next) { + if (compare ? + (cur->object && element->equals(cur->object)) : + element == cur->object) { + if (beforeCur) { + beforeCur->next = cur->next; + if (cur->next == NULL) + last = beforeCur; + } else { + first = cur->next; + if (first == NULL) + last = NULL; + } + + if (ownerOfObjects && cur->object && !doNotDeleteAtAll) + delete cur->object; + delete cur; + + numElements--; + return true; + } + } + + return false; +} + +Object *List::ListIterator::getNext() +{ + Object *object; + + if (current) { + object = current->object; + current = current->next; + } else + object = NULL; + + return object; +} + +bool List::ListIterator::hasNext() +{ + return current != NULL; +} + +Collection0::AbstractIterator* List::createIterator() +{ + return new ListIterator(first); +} + + +// --------------- +// HashSet +// --------------- + +HashSet::HashSet(bool ownerOfObjects, int tableSize) +{ + this->ownerOfObjects = ownerOfObjects; + this->tableSize = tableSize; + + table = new Node*[tableSize]; + for (int i = 0; i < tableSize; i++) + table[i] = NULL; + + numElements = 0; +} + +HashSet::~HashSet() +{ + for (int i = 0; i < tableSize; i++) { + Node *n1 = table[i]; + while (n1) { + Node *n2 = n1->next; + + // It seems appropriate to call "clearNode(n1)" here instead + // of "delete n1->object", but since this is the destructor, + // the implementation of a sub class would not be called + // anymore. This is the reason why HashTable has an + // destructor. + if (ownerOfObjects) { + PRINTF ("- deleting object: %s\n", n1->object->toString()); + delete n1->object; + } + + delete n1; + n1 = n2; + } + } + + delete[] table; +} + +int HashSet::size () +{ + return numElements; +} + +HashSet::Node *HashSet::createNode() +{ + return new Node; +} + +void HashSet::clearNode(HashSet::Node *node) +{ + if (ownerOfObjects) { + PRINTF ("- deleting object: %s\n", node->object->toString()); + delete node->object; + } +} + +HashSet::Node *HashSet::findNode(Object *object) const +{ + int h = calcHashValue(object); + for (Node *node = table[h]; node; node = node->next) { + if (object->equals(node->object)) + return node; + } + + return NULL; +} + +HashSet::Node *HashSet::insertNode(Object *object) +{ + // Look whether object is already contained. + Node *node = findNode(object); + if (node) { + clearNode(node); + numElements--; + } else { + int h = calcHashValue(object); + node = createNode (); + node->next = table[h]; + table[h] = node; + numElements++; + } + + node->object = object; + return node; +} + + +void HashSet::put(Object *object) +{ + insertNode (object); +} + +bool HashSet::contains(Object *object) const +{ + int h = calcHashValue(object); + for (Node *n = table[h]; n; n = n->next) { + if (object->equals(n->object)) + return true; + } + + return false; +} + +bool HashSet::remove(Object *object) +{ + int h = calcHashValue(object); + Node *last, *cur; + + for (last = NULL, cur = table[h]; cur; last = cur, cur = cur->next) { + if (object->equals(cur->object)) { + if (last) + last->next = cur->next; + else + table[h] = cur->next; + + clearNode (cur); + delete cur; + numElements--; + + return true; + } + } + + return false; + + // TODO for HashTable: also remove value. +} + +// For historical reasons: this method once existed under the name +// "getKey" in HashTable. It could be used to get the real object from +// the table, but it was dangerous, because a change of this object +// would also change the hash value, and so confuse the table. + +/*Object *HashSet::getReference (Object *object) +{ + int h = calcHashValue(object); + for (Node *n = table[h]; n; n = n->next) { + if (object->equals(n->object)) + return n->object; + } + + return NULL; +}*/ + +HashSet::HashSetIterator::HashSetIterator(HashSet *set) +{ + this->set = set; + node = NULL; + pos = -1; + gotoNext(); +} + +void HashSet::HashSetIterator::gotoNext() +{ + if (node) + node = node->next; + + while (node == NULL) { + if (pos >= set->tableSize - 1) + return; + pos++; + node = set->table[pos]; + } +} + + +Object *HashSet::HashSetIterator::getNext() +{ + Object *result; + if (node) + result = node->object; + else + result = NULL; + + gotoNext(); + return result; +} + +bool HashSet::HashSetIterator::hasNext() +{ + return node != NULL; +} + +Collection0::AbstractIterator* HashSet::createIterator() +{ + return new HashSetIterator(this); +} + +// --------------- +// HashTable +// --------------- + +HashTable::HashTable(bool ownerOfKeys, bool ownerOfValues, int tableSize) : + HashSet (ownerOfKeys, tableSize) +{ + this->ownerOfValues = ownerOfValues; +} + +HashTable::~HashTable() +{ + // See comment in the destructor of HashSet. + for (int i = 0; i < tableSize; i++) { + for (Node *n = table[i]; n; n = n->next) { + if (ownerOfValues) { + Object *value = ((KeyValuePair*)n)->value; + if (value) { + PRINTF ("- deleting value: %s\n", value->toString()); + delete value; + } + } + } + } +} + +HashSet::Node *HashTable::createNode() +{ + return new KeyValuePair; +} + +void HashTable::clearNode(HashSet::Node *node) +{ + HashSet::clearNode (node); + if (ownerOfValues) { + Object *value = ((KeyValuePair*)node)->value; + if (value) { + PRINTF ("- deleting value: %s\n", value->toString()); + delete value; + } + } +} + +void HashTable::intoStringBuffer(misc::StringBuffer *sb) +{ + sb->append("{ "); + + bool first = true; + for (int i = 0; i < tableSize; i++) { + for (Node *node = table[i]; node; node = node->next) { + if (!first) + sb->append(", "); + node->object->intoStringBuffer(sb); + + sb->append(" => "); + + Object *value = ((KeyValuePair*)node)->value; + if (value) + value->intoStringBuffer(sb); + else + sb->append ("null"); + + first = false; + } + } + + sb->append(" }"); +} + +void HashTable::put(Object *key, Object *value) +{ + KeyValuePair *node = (KeyValuePair*)insertNode(key); + node->value = value; +} + +Object *HashTable::get(Object *key) const +{ + Node *node = findNode(key); + if (node) + return ((KeyValuePair*)node)->value; + else + return NULL; +} + +// ----------- +// Stack +// ----------- + +Stack::Stack (bool ownerOfObjects) +{ + this->ownerOfObjects = ownerOfObjects; + bottom = top = NULL; + numElements = 0; +} + +Stack::~Stack() +{ + while (top) + pop (); +} + +int Stack::size () +{ + return numElements; +} + +void Stack::push (object::Object *object) +{ + Node *newTop = new Node (); + newTop->object = object; + newTop->prev = top; + + top = newTop; + if (bottom == NULL) + bottom = top; + + numElements++; +} + +void Stack::pushUnder (object::Object *object) +{ + Node *newBottom = new Node (); + newBottom->object = object; + newBottom->prev = NULL; + if (bottom != NULL) + bottom->prev = newBottom; + + bottom = newBottom; + if (top == NULL) + top = bottom; + + numElements++; +} + +void Stack::pop () +{ + Node *newTop = top->prev; + + if (ownerOfObjects) + delete top->object; + delete top; + + top = newTop; + if (top == NULL) + bottom = NULL; + + numElements--; +} + +Object *Stack::StackIterator::getNext() +{ + Object *object; + + if (current) { + object = current->object; + current = current->prev; + } else + object = NULL; + + return object; +} + +bool Stack::StackIterator::hasNext() +{ + return current != NULL; +} + +Collection0::AbstractIterator* Stack::createIterator() +{ + return new StackIterator(top); +} + +} // namespace untyped + +} // namespace container + +} // namespace lout |