Dillo v3.2.0-51-gcc3f4939
Loading...
Searching...
No Matches
container.cc
Go to the documentation of this file.
1/*
2 * Dillo Widget
3 *
4 * Copyright 2005-2007 Sebastian Geerken <sgeerken@dillo.org>
5 * Copyright 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define PRINTF(fmt, ...)
22//#define PRINTF printf
23
24#include "container.hh"
25#include "misc.hh"
26#include "debug.hh"
27
28namespace lout {
29
30using namespace object;
31
32namespace container {
33
34namespace untyped {
35
36// -------------
37// Iterator
38// -------------
39
41{
42 impl = NULL;
43}
44
46{
47 impl = it2.impl;
48 if (impl)
49 impl->ref();
50}
51
53{
54 impl = it2.impl;
55 if (impl)
56 impl->ref();
57}
58
60{
61 if (impl)
62 impl->unref();
63 impl = it2.impl;
64 if (impl)
65 impl->ref();
66 return *this;
67}
68
70{
71 if (impl)
72 impl->unref();
73 impl = it2.impl;
74 if (impl)
75 impl->ref();
76 return *this;
77}
78
80{
81 if (impl)
82 impl->unref();
83}
84
85// ----------------
86// Collection
87// ----------------
88
90{
91 sb->append("{ ");
92 bool first = true;
93 for (Iterator it = iterator(); it.hasNext(); ) {
94 if (!first)
95 sb->append(", ");
96 it.getNext()->intoStringBuffer(sb);
97 first = false;
98 }
99 sb->append(" }");
100}
101
102// ------------
103// Vector
104// ------------
105
106Vector::Vector(int initSize, bool ownerOfObjects)
107{
108 DBG_OBJ_CREATE ("lout::container::untyped::Vector");
109
110 numAlloc = initSize == 0 ? 1 : initSize;
111 this->ownerOfObjects = ownerOfObjects;
112 numElements = 0;
113 array = (Object**)malloc(numAlloc * sizeof(Object*));
114}
115
117{
118 clear();
119 free(array);
120
122}
123
125{
126 return numElements;
127}
128
129void Vector::put(Object *newElement, int newPos)
130{
131 if (newPos == -1)
132 newPos = numElements;
133
134 // Old entry is overwritten.
135 if (newPos < numElements) {
136 if (ownerOfObjects && array[newPos])
137 delete array[newPos];
138 }
139
140 // Allocated memory has to be increased.
141 if (newPos >= numAlloc) {
142 while (newPos >= numAlloc)
143 numAlloc *= 2;
144 void *vp = realloc(array, numAlloc * sizeof(Object*));
145 if (vp == NULL) {
146 perror("realloc failed");
147 exit(1);
148 }
149 array = (Object**)vp;
150 }
151
152 // Insert NULL's into possible gap before new position.
153 for (int i = numElements; i < newPos; i++)
154 array[i] = NULL;
155
156 if (newPos >= numElements)
157 numElements = newPos + 1;
158
159 array[newPos] = newElement;
160}
161
163{
164 if (ownerOfObjects) {
165 for (int i = 0; i < numElements; i++)
166 if (array[i])
167 delete array[i];
168 }
169
170 numElements = 0;
171}
172
173void Vector::insert(Object *newElement, int pos)
174{
175 if (pos >= numElements)
176 put(newElement, pos);
177 else {
178 numElements++;
179
180 if (numElements >= numAlloc) {
181 // Allocated memory has to be increased.
182 numAlloc *= 2;
183 void *vp = realloc(array, numAlloc * sizeof(Object*));
184 if (vp == NULL) {
185 perror("realloc failed");
186 exit(1);
187 }
188 array = (Object**)vp;
189 }
190
191 for (int i = numElements - 1; i > pos; i--)
192 array[i] = array[i - 1];
193
194 array[pos] = newElement;
195 }
196}
197
198void Vector::remove(int pos)
199{
200 if (ownerOfObjects && array[pos])
201 delete array[pos];
202
203 for (int i = pos + 1; i < numElements; i++)
204 array[i - 1] = array[i];
205
206 numElements--;
207}
208
212void Vector::sort(Comparator *comparator)
213{
216}
217
227int Vector::bsearch(Object *key, bool mustExist, int start, int end,
228 Comparator *comparator)
229{
230 // The case !mustExist is not handled by bsearch(3), so here is a
231 // new implementation.
232
233 DBG_OBJ_MSGF ("container", 0,
234 "<b>bsearch</b> (<i>key</i>, %s, %d, %d, <i>comparator</i>) "
235 "[size is %d]",
236 mustExist ? "true" : "false", start, end, size ());
238
239 int result = -123; // Compiler happiness: GCC 4.7 does not handle this?
240
241 if (start > end) {
242 DBG_OBJ_MSG ("container", 1, "empty");
243 result = mustExist ? -1 : start;
244 } else {
245 int low = start, high = end;
246 bool found = false;
247
248 while (!found) {
249 int index = (low + high) / 2;
250 int c = comparator->compare (key, array[index]);
251 DBG_OBJ_MSGF ("container", 1,
252 "searching within %d and %d; compare key with #%d => %d",
253 low, high, index, c);
254 if (c == 0) {
255 found = true;
256 result = index;
257 } else {
258 if (low >= high) {
259 if (mustExist) {
260 found = true;
261 result = -1;
262 } else {
263 found = true;
264 result = c > 0 ? index + 1 : index;
265 }
266 }
267
268 if (c < 0)
269 high = index - 1;
270 else
271 low = index + 1;
272 }
273 }
274 }
275
276 DBG_OBJ_MSGF ("container", 1, "result = %d", result);
278 return result;
279}
280
282{
283 if (index < vector->numElements - 1)
284 index++;
285
286 return index < vector->numElements ? vector->array[index] : NULL;
287}
288
290{
291 return index < vector->numElements - 1;
292}
293
298
299// ------------
300// List
301// ------------
302
304{
305 this->ownerOfObjects = ownerOfObjects;
306 first = last = NULL;
307 numElements = 0;
308}
309
311{
312 clear();
313}
314
316{
317 return numElements;
318}
319
321{
322 List *otherList = (List*)other;
323 Node *node1 = first, *node2 = otherList->first;
324 while (node1 != NULL && node2 != NULL ) {
325 if (!node1->object->equals (node2->object))
326 return false;
327 node1 = node1->next;
328 node2 = node2->next;
329 }
330 return node1 == NULL && node2 == NULL;
331}
332
334{
335 int h = 0;
336 for (Node *node = first; node; node = node->next)
337 h = h ^ node->object->hashValue ();
338 return h;
339}
340
342{
343 while (first) {
344 if (ownerOfObjects && first->object)
345 delete first->object;
346 Node *next = first->next;
347 delete first;
348 first = next;
349 }
350
351 last = NULL;
352 numElements = 0;
353}
354
355void List::append(Object *element)
356{
357 Node *newLast = new Node;
358 newLast->next = NULL;
359 newLast->object = element;
360
361 if (last) {
362 last->next = newLast;
363 last = newLast;
364 } else
365 first = last = newLast;
366
367 numElements++;
368}
369
371{
372 Node *beforeCur, *cur;
373
374 for (beforeCur = NULL, cur = first; cur; beforeCur = cur, cur = cur->next) {
375 if (cur->object == beforeThis) {
376 Node *newNode = new Node;
377 newNode->next = cur;
378 newNode->object = neew;
379
380 if (beforeCur)
381 beforeCur->next = newNode;
382 else
383 first = newNode;
384
385 numElements++;
386 return true;
387 }
388 }
389
390 return false;
391}
392
393bool List::remove0(Object *element, bool compare, bool doNotDeleteAtAll)
394{
395 Node *beforeCur, *cur;
396
397 for (beforeCur = NULL, cur = first; cur; beforeCur = cur, cur = cur->next) {
398 if (compare ?
399 (cur->object && element->equals(cur->object)) :
400 element == cur->object) {
401 if (beforeCur) {
402 beforeCur->next = cur->next;
403 if (cur->next == NULL)
404 last = beforeCur;
405 } else {
406 first = cur->next;
407 if (first == NULL)
408 last = NULL;
409 }
410
411 if (ownerOfObjects && cur->object && !doNotDeleteAtAll)
412 delete cur->object;
413 delete cur;
414
415 numElements--;
416 return true;
417 }
418 }
419
420 return false;
421}
422
424{
425 Object *object;
426
427 if (current) {
428 object = current->object;
429 current = current->next;
430 } else
431 object = NULL;
432
433 return object;
434}
435
437{
438 return current != NULL;
439}
440
445
446
447// ---------------
448// HashSet
449// ---------------
450
452{
453 this->ownerOfObjects = ownerOfObjects;
454 this->tableSize = tableSize;
455
456 table = new Node*[tableSize];
457 for (int i = 0; i < tableSize; i++)
458 table[i] = NULL;
459
460 numElements = 0;
461}
462
464{
465 for (int i = 0; i < tableSize; i++) {
466 Node *n1 = table[i];
467 while (n1) {
468 Node *n2 = n1->next;
469
470 // It seems appropriate to call "clearNode(n1)" here instead
471 // of "delete n1->object", but since this is the destructor,
472 // the implementation of a sub class would not be called
473 // anymore. This is the reason why HashTable has an
474 // destructor.
475 if (ownerOfObjects) {
476 PRINTF ("- deleting object: %s\n", n1->object->toString());
477 delete n1->object;
478 }
479
480 delete n1;
481 n1 = n2;
482 }
483 }
484
485 delete[] table;
486}
487
489{
490 return numElements;
491}
492
494{
495 return new Node;
496}
497
499{
500 if (ownerOfObjects) {
501 PRINTF ("- deleting object: %s\n", node->object->toString());
502 delete node->object;
503 }
504}
505
507{
508 int h = calcHashValue(object);
509 for (Node *node = table[h]; node; node = node->next) {
510 if (object->equals(node->object))
511 return node;
512 }
513
514 return NULL;
515}
516
518{
519 // Look whether object is already contained.
520 Node *node = findNode(object);
521 if (node) {
522 clearNode(node);
523 numElements--;
524 } else {
525 int h = calcHashValue(object);
526 node = createNode ();
527 node->next = table[h];
528 table[h] = node;
529 numElements++;
530 }
531
532 node->object = object;
533 return node;
534}
535
536
537void HashSet::put(Object *object)
538{
539 insertNode (object);
540}
541
542bool HashSet::contains(Object *object) const
543{
544 int h = calcHashValue(object);
545 for (Node *n = table[h]; n; n = n->next) {
546 if (object->equals(n->object))
547 return true;
548 }
549
550 return false;
551}
552
554{
555 int h = calcHashValue(object);
556 Node *last, *cur;
557
558 for (last = NULL, cur = table[h]; cur; last = cur, cur = cur->next) {
559 if (object->equals(cur->object)) {
560 if (last)
561 last->next = cur->next;
562 else
563 table[h] = cur->next;
564
565 clearNode (cur);
566 delete cur;
567 numElements--;
568
569 return true;
570 }
571 }
572
573 return false;
574
575 // TODO for HashTable: also remove value.
576}
577
578// For historical reasons: this method once existed under the name
579// "getKey" in HashTable. It could be used to get the real object from
580// the table, but it was dangerous, because a change of this object
581// would also change the hash value, and so confuse the table.
582
583/*Object *HashSet::getReference (Object *object)
584{
585 int h = calcHashValue(object);
586 for (Node *n = table[h]; n; n = n->next) {
587 if (object->equals(n->object))
588 return n->object;
589 }
590
591 return NULL;
592}*/
593
595{
596 this->set = set;
597 node = NULL;
598 pos = -1;
599 gotoNext();
600}
601
603{
604 if (node)
605 node = node->next;
606
607 while (node == NULL) {
608 if (pos >= set->tableSize - 1)
609 return;
610 pos++;
611 node = set->table[pos];
612 }
613}
614
615
617{
618 Object *result;
619 if (node)
620 result = node->object;
621 else
622 result = NULL;
623
624 gotoNext();
625 return result;
626}
627
629{
630 return node != NULL;
631}
632
637
638// ---------------
639// HashTable
640// ---------------
641
642HashTable::HashTable(bool ownerOfKeys, bool ownerOfValues, int tableSize) :
643 HashSet (ownerOfKeys, tableSize)
644{
645 this->ownerOfValues = ownerOfValues;
646}
647
649{
650 // See comment in the destructor of HashSet.
651 for (int i = 0; i < tableSize; i++) {
652 for (Node *n = table[i]; n; n = n->next) {
653 if (ownerOfValues) {
654 Object *value = ((KeyValuePair*)n)->value;
655 if (value) {
656 PRINTF ("- deleting value: %s\n", value->toString());
657 delete value;
658 }
659 }
660 }
661 }
662}
663
668
670{
671 HashSet::clearNode (node);
672 if (ownerOfValues) {
673 Object *value = ((KeyValuePair*)node)->value;
674 if (value) {
675 PRINTF ("- deleting value: %s\n", value->toString());
676 delete value;
677 }
678 }
679}
680
682{
683 sb->append("{ ");
684
685 bool first = true;
686 for (int i = 0; i < tableSize; i++) {
687 for (Node *node = table[i]; node; node = node->next) {
688 if (!first)
689 sb->append(", ");
690 node->object->intoStringBuffer(sb);
691
692 sb->append(" => ");
693
694 Object *value = ((KeyValuePair*)node)->value;
695 if (value)
696 value->intoStringBuffer(sb);
697 else
698 sb->append ("null");
699
700 first = false;
701 }
702 }
703
704 sb->append(" }");
705}
706
707void HashTable::put(Object *key, Object *value)
708{
709 KeyValuePair *node = (KeyValuePair*)insertNode(key);
710 node->value = value;
711}
712
714{
715 Node *node = findNode(key);
716 if (node)
717 return ((KeyValuePair*)node)->value;
718 else
719 return NULL;
720}
721
722// -----------
723// Stack
724// -----------
725
726Stack::Stack (bool ownerOfObjects)
727{
728 this->ownerOfObjects = ownerOfObjects;
729 bottom = top = NULL;
730 numElements = 0;
731}
732
734{
735 while (top)
736 pop ();
737}
738
740{
741 return numElements;
742}
743
745{
746 Node *newTop = new Node ();
747 newTop->object = object;
748 newTop->prev = top;
749
750 top = newTop;
751 if (bottom == NULL)
752 bottom = top;
753
754 numElements++;
755}
756
758{
759 Node *newBottom = new Node ();
760 newBottom->object = object;
761 newBottom->prev = NULL;
762 if (bottom != NULL)
763 bottom->prev = newBottom;
764
765 bottom = newBottom;
766 if (top == NULL)
767 top = bottom;
768
769 numElements++;
770}
771
773{
774 Node *newTop = top->prev;
775
776 if (ownerOfObjects)
777 delete top->object;
778 delete top;
779
780 top = newTop;
781 if (top == NULL)
782 bottom = NULL;
783
784 numElements--;
785}
786
788{
789 Object *object;
790
791 if (current) {
792 object = current->object;
794 } else
795 object = NULL;
796
797 return object;
798}
799
801{
802 return current != NULL;
803}
804
809
810} // namespace untyped
811
812} // namespace container
813
814} // namespace lout
The base class for all iterators, as created by container::untyped::Collection::createIterator.
Definition container.hh:64
void intoStringBuffer(misc::StringBuffer *sb)
Store a textual representation of the object in a misc::StringBuffer.
Definition container.cc:89
Node * insertNode(object::Object *object)
Definition container.cc:517
void put(object::Object *object)
Definition container.cc:537
bool remove(object::Object *key)
Definition container.cc:553
HashSet(bool ownerOfObjects, int tableSize=251)
Definition container.cc:451
bool contains(object::Object *key) const
Definition container.cc:542
virtual void clearNode(Node *node)
Definition container.cc:498
AbstractIterator * createIterator()
Definition container.cc:633
Node * findNode(object::Object *object) const
Definition container.cc:506
object::Object * get(object::Object *key) const
Definition container.cc:713
HashTable(bool ownerOfKeys, bool ownerOfValues, int tableSize=251)
Definition container.cc:642
void intoStringBuffer(misc::StringBuffer *sb)
Store a textual representation of the object in a misc::StringBuffer.
Definition container.cc:681
void put(object::Object *key, object::Object *value)
Definition container.cc:707
This is a small wrapper for AbstractIterator, which may be used directly, not as a pointer,...
Definition container.hh:87
Collection0::AbstractIterator * impl
Definition container.hh:91
Iterator & operator=(const Iterator &it2)
Definition container.cc:59
A single-linked list.
Definition container.hh:187
bool remove0(object::Object *element, bool compare, bool doNotDeleteAtAll)
Definition container.cc:393
bool equals(Object *other)
Returns, whether two objects are equal.
Definition container.cc:320
void append(object::Object *element)
Definition container.cc:355
AbstractIterator * createIterator()
Definition container.cc:441
bool insertBefore(object::Object *beforeThis, object::Object *neew)
Definition container.cc:370
List(bool ownerOfObjects)
Definition container.cc:303
int hashValue()
Return a hash value for the object.
Definition container.cc:333
void push(object::Object *object)
Definition container.cc:744
void pushUnder(object::Object *object)
Definition container.cc:757
AbstractIterator * createIterator()
Definition container.cc:805
Stack(bool ownerOfObjects)
Definition container.cc:726
void sort(object::Comparator *comparator=&object::standardComparator)
Sort the elements in the vector.
Definition container.cc:212
Vector(int initSize, bool ownerOfObjects)
Definition container.cc:106
void put(object::Object *newElement, int newPos=-1)
Definition container.cc:129
int bsearch(Object *key, bool mustExist, int start, int end, object::Comparator *comparator=&object::standardComparator)
Use binary search to find an element in a sorted vector.
Definition container.cc:227
AbstractIterator * createIterator()
Definition container.cc:294
void insert(object::Object *newElement, int pos)
Definition container.cc:173
A class for fast concatenation of a large number of strings.
Definition misc.hh:570
void append(const char *str)
Append a NUL-terminated string to the buffer, with copying.
Definition misc.hh:593
Used for other orders as the one defined by Comparable.
Definition object.hh:67
static int compareFun(const void *p1, const void *p2)
This static method may be used as compare function for qsort(3) and bsearch(3), for an array of Objec...
Definition object.cc:128
static Comparator * compareFunComparator
Definition object.hh:84
virtual int compare(Object *o1, Object *o2)=0
Compare two objects o1 and o2.
This is the base class for many other classes, which defines very common virtual methods.
Definition object.hh:25
virtual void intoStringBuffer(misc::StringBuffer *sb)
Store a textual representation of the object in a misc::StringBuffer.
Definition object.cc:96
const char * toString()
Use object::Object::intoStringBuffer to return a textual representation of the object.
Definition object.cc:82
virtual int hashValue()
Return a hash value for the object.
Definition object.cc:60
virtual bool equals(Object *other)
Returns, whether two objects are equal.
Definition object.cc:51
#define DBG_OBJ_DELETE()
#define DBG_OBJ_CREATE(klass)
#define DBG_OBJ_MSG_END()
#define DBG_OBJ_MSGF(aspect, prio, fmt,...)
#define DBG_OBJ_MSG(aspect, prio, msg)
#define DBG_OBJ_MSG_START()
#define PRINTF(...)
Definition textblock.hh:11