Objectively
Ultra-lightweight object oriented framework for GNU C.
Loading...
Searching...
No Matches
Set.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include <assert.h>
25#include <stdarg.h>
26#include <stdlib.h>
27
28#include "Hash.h"
29#include "Set.h"
30#include "String.h"
31
32#define _Class _Set
33
34#define SET_DEFAULT_CAPACITY 64
35#define SET_GROW_FACTOR 2.0
36#define SET_MAX_LOAD 0.75f
37
38#pragma mark - Object
39
43static Object *copy(const Object *self) {
44
45 const Set *this = (Set *) self;
46
47 Set *that = $(alloc(Set), initWithCapacity, this->capacity);
48
49 $(that, addObjectsFromSet, this);
50
51 return (Object *) that;
52}
53
57static void dealloc(Object *self) {
58
59 Set *this = (Set *) self;
60
61 for (size_t i = 0; i < this->capacity; i++) {
62 release(this->elements[i]);
63 }
64
65 free(this->elements);
66
67 super(Object, self, dealloc);
68}
69
73static String *description(const Object *self) {
74
75 const Array *array = $((Set *) self, allObjects);
76
77 return $((Object *) array, description);
78}
79
83static int hash(const Object *self) {
84
85 const Set *this = (Set *) self;
86
87 int hash = HashForInteger(HASH_SEED, this->count);
88
89 for (size_t i = 0; i < this->capacity; i++) {
90 if (this->elements[i]) {
91 hash = HashForObject(hash, this->elements[i]);
92 }
93 }
94
95 return hash;
96}
97
101static bool isEqual(const Object *self, const Object *other) {
102
103 if (super(Object, self, isEqual, other)) {
104 return true;
105 }
106
107 if (other && (self->clazz == other->clazz)) {
108
109 const Set *this = (Set *) self;
110 const Set *that = (Set *) other;
111
112 if (this->count == that->count) {
113
114 Array *objects = $(this, allObjects);
115
116 for (size_t i = 0; i < objects->count; i++) {
117 const ident obj = $(objects, objectAtIndex, i);
118
119 if ($(that, containsObject, obj) == false) {
120 release(objects);
121 return false;
122 }
123 }
124
125 release(objects);
126 return true;
127 }
128 }
129
130 return false;
131}
132
133#pragma mark - Set
134
139static void addObject_resize(Set *set) {
140
141 if (set->capacity) {
142
143 const float load = set->count / (float) set->capacity;
144 if (load >= SET_MAX_LOAD) {
145
146 size_t capacity = set->capacity;
147 ident *elements = set->elements;
148
149 set->capacity = set->capacity * SET_GROW_FACTOR;
150 set->count = 0;
151
152 set->elements = calloc(set->capacity, sizeof(ident));
153 assert(set->elements);
154
155 for (size_t i = 0; i < capacity; i++) {
156
157 Array *array = elements[i];
158 if (array) {
160 release(array);
161 }
162 }
163
164 free(elements);
165 }
166 } else {
168 }
169}
170
175static void addObject(Set *self, const ident obj) {
176
177 addObject_resize(self);
178
179 const size_t bin = HashForObject(HASH_SEED, obj) % self->capacity;
180
181 Array *array = self->elements[bin];
182 if (array == NULL) {
183 array = self->elements[bin] = $(alloc(Array), init);
184 }
185
186 if ($((Array *) array, containsObject, obj) == false) {
187 $(array, addObject, obj);
188 self->count++;
189 }
190}
191
196 $((Set *) data, addObject, obj);
197}
198
203static void addObjectsFromArray(Set *self, const Array *array) {
204
205 if (array) {
207 }
208}
209
214 $((Set *) data, addObject, obj);
215}
216
221static void addObjectsFromSet(Set *self, const Set *set) {
222
223 if (set) {
225 }
226}
227
232 $((Array *) data, addObject, obj);
233}
234
239static Array *allObjects(const Set *self) {
240
241 Array *objects = $(alloc(Array), initWithCapacity, self->count);
242
243 $(self, enumerateObjects, allObjects_enumerator, objects);
244
245 return objects;
246}
247
252static bool containsObject(const Set *self, const ident obj) {
253
254 if (self->capacity) {
255 const size_t bin = HashForObject(HASH_SEED, obj) % self->capacity;
256
257 const Array *array = self->elements[bin];
258 if (array) {
259 return $(array, containsObject, obj);
260 }
261 }
262
263 return false;
264}
265
270static bool containsObjectMatching(const Set *self, Predicate predicate, ident data) {
271
272 assert(predicate);
273
274 for (size_t i = 0; i < self->capacity; i++) {
275
276 Array *array = self->elements[i];
277 if (array) {
278
279 for (size_t j = 0; j < array->count; j++) {
280 if (predicate($(array, objectAtIndex, j), data)) {
281 return true;
282 }
283 }
284 }
285 }
286
287 return false;
288}
289
294static void enumerateObjects(const Set *self, SetEnumerator enumerator, ident data) {
295
296 assert(enumerator);
297
298 for (size_t i = 0; i < self->capacity; i++) {
299
300 Array *array = self->elements[i];
301 if (array) {
302
303 for (size_t j = 0; j < array->count; j++) {
304 enumerator(self, $(array, objectAtIndex, j), data);
305 }
306 }
307 }
308}
309
314static void filter(Set *self, Predicate predicate, ident data) {
315
316 assert(predicate);
317
318 self->count = 0;
319
320 for (size_t i = 0; i < self->capacity; i++) {
321
322 Array *array = self->elements[i];
323 if (array) {
324
325 $(array, filter, predicate, data);
326
327 if (array->count == 0) {
328 release(array);
329 self->elements[i] = NULL;
330 } else {
331 self->count += array->count;
332 }
333 }
334 }
335}
336
341static Set *filteredSet(const Set *self, Predicate predicate, ident data) {
342
343 assert(predicate);
344
345 Set *set = $(alloc(Set), init);
346
347 for (size_t i = 0; i < self->capacity; i++) {
348
349 Array *array = self->elements[i];
350 if (array) {
351
352 for (size_t j = 0; j < array->count; j++) {
353 ident obj = $(array, objectAtIndex, j);
354
355 if (predicate(obj, data)) {
356 $(set, addObject, obj);
357 }
358 }
359 }
360 }
361
362 return set;
363}
364
369static Set *init(Set *self) {
370
371 return $(self, initWithCapacity, SET_DEFAULT_CAPACITY);
372}
373
378 $((Set *) data, addObject, obj);
379}
380
385static Set *initWithArray(Set *self, const Array *array) {
386
387 self = (Set *) super(Object, self, init);
388 if (self) {
389 if (array) {
391 }
392 }
393
394 return self;
395}
396
401static Set *initWithCapacity(Set *self, size_t capacity) {
402
403 self = (Set *) super(Object, self, init);
404 if (self) {
405
406 self->capacity = capacity;
407 if (self->capacity) {
408
409 self->elements = calloc(self->capacity, sizeof(ident));
410 assert(self->elements);
411 }
412 }
413
414 return self;
415}
416
421static Set *initWithObjects(Set *self, ...) {
422
423 self = (Set *) super(Object, self, init);
424 if (self) {
425
426 va_list args;
427 va_start(args, self);
428
429 while (true) {
430
431 ident obj = va_arg(args, ident);
432 if (obj) {
433 $(self, addObject, obj);
434 } else {
435 break;
436 }
437 }
438
439 va_end(args);
440 }
441
442 return self;
443}
444
449 $((Set *) data, addObject, obj);
450}
451
456static Set *initWithSet(Set *self, const Set *set) {
457
458 self = (Set *) super(Object, self, init);
459 if (self) {
460 if (set) {
462 }
463 }
464
465 return self;
466}
467
472static Set *mappedSet(const Set *self, Functor functor, ident data) {
473
474 assert(functor);
475
476 Set *set = $(alloc(Set), initWithCapacity, self->count);
477 assert(set);
478
479 for (size_t i = 0; i < self->capacity; i++) {
480
481 const Array *array = self->elements[i];
482 if (array) {
483
484 for (size_t j = 0; j < array->count; j++) {
485
486 ident obj = functor(array->elements[j], data);
487
488 $(set, addObject, obj);
489
490 release(obj);
491 }
492 }
493 }
494
495 return set;
496}
497
502static ident reduce(const Set *self, Reducer reducer, ident accumulator, ident data) {
503
504 assert(reducer);
505
506 for (size_t i = 0; i < self->capacity; i++) {
507
508 const Array *array = self->elements[i];
509 if (array) {
510
511 for (size_t j = 0; j < array->count; j++) {
512 accumulator = reducer(array->elements[j], accumulator, data);
513 }
514 }
515 }
516
517 return accumulator;
518}
519
524static void removeAllObjects(Set *self) {
525
526 for (size_t i = 0; i < self->capacity; i++) {
527
528 Array *array = self->elements[i];
529 if (array) {
530 release(array);
531 self->elements[i] = NULL;
532 }
533 }
534
535 self->count = 0;
536}
537
542static void removeObject(Set *self, const ident obj) {
543
544 if (self->capacity == 0) {
545 return;
546 }
547
548 const size_t bin = HashForObject(HASH_SEED, obj) % self->capacity;
549
550 Array *array = self->elements[bin];
551 if (array) {
552
553 const ssize_t index = $(array, indexOfObject, obj);
554 if (index > -1) {
555
556 $(array, removeObjectAtIndex, index);
557
558 if (((Array *) array)->count == 0) {
559 release(array);
560 self->elements[bin] = NULL;
561 }
562
563 self->count--;
564 }
565 }
566}
567
572static Set *set(void) {
573
574 return $(alloc(Set), init);
575}
576
581static Set *setWithArray(const Array *array) {
582
583 return $(alloc(Set), initWithArray, array);
584}
585
590static Set *setWithCapacity(size_t capacity) {
591
592 return $(alloc(Set), initWithCapacity, capacity);
593}
594
600
601 Set *set = (Set *) $((Object *) alloc(Set), init);
602 if (set) {
603
604 va_list args;
605 va_start(args, obj);
606
607 while (obj) {
608 $(set, addObject, obj);
609 obj = va_arg(args, ident);
610 }
611
612 va_end(args);
613 }
614
615 return set;
616}
617
622static Set *setWithSet(const Set *set) {
623
624 return $(alloc(Set), initWithSet, set);
625}
626
627#pragma mark - Class lifecycle
628
632static void initialize(Class *clazz) {
633
634 ((ObjectInterface *) clazz->interface)->copy = copy;
635 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
636 ((ObjectInterface *) clazz->interface)->description = description;
637 ((ObjectInterface *) clazz->interface)->hash = hash;
638 ((ObjectInterface *) clazz->interface)->isEqual = isEqual;
639
640 ((SetInterface *) clazz->interface)->addObject = addObject;
641 ((SetInterface *) clazz->interface)->addObjectsFromArray = addObjectsFromArray;
642 ((SetInterface *) clazz->interface)->addObjectsFromSet = addObjectsFromSet;
643 ((SetInterface *) clazz->interface)->allObjects = allObjects;
644 ((SetInterface *) clazz->interface)->containsObject = containsObject;
645 ((SetInterface *) clazz->interface)->containsObjectMatching = containsObjectMatching;
646 ((SetInterface *) clazz->interface)->enumerateObjects = enumerateObjects;
647 ((SetInterface *) clazz->interface)->filter = filter;
648 ((SetInterface *) clazz->interface)->filteredSet = filteredSet;
649 ((SetInterface *) clazz->interface)->init = init;
650 ((SetInterface *) clazz->interface)->initWithArray = initWithArray;
651 ((SetInterface *) clazz->interface)->initWithCapacity = initWithCapacity;
652 ((SetInterface *) clazz->interface)->initWithObjects = initWithObjects;
653 ((SetInterface *) clazz->interface)->initWithSet = initWithSet;
654 ((SetInterface *) clazz->interface)->mappedSet = mappedSet;
655 ((SetInterface *) clazz->interface)->reduce = reduce;
656 ((SetInterface *) clazz->interface)->removeAllObjects = removeAllObjects;
657 ((SetInterface *) clazz->interface)->removeObject = removeObject;
658 ((SetInterface *) clazz->interface)->set = set;
659 ((SetInterface *) clazz->interface)->setWithArray = setWithArray;
660 ((SetInterface *) clazz->interface)->setWithCapacity = setWithCapacity;
661 ((SetInterface *) clazz->interface)->setWithObjects = setWithObjects;
662 ((SetInterface *) clazz->interface)->setWithSet = setWithSet;
663}
664
669Class *_Set(void) {
670 static Class *clazz;
671 static Once once;
672
673 do_once(&once, {
674 clazz = _initialize(&(const ClassDef) {
675 .name = "Set",
676 .superclass = _Object(),
677 .instanceSize = sizeof(Set),
678 .interfaceOffset = offsetof(Set, interface),
679 .interfaceSize = sizeof(SetInterface),
681 });
682 });
683
684 return clazz;
685}
686
687#undef _Class
static void removeObjectAtIndex(Array *self, size_t index)
Definition Array.c:654
static ident objectAtIndex(const Array *self, size_t index)
Definition Array.c:578
static void enumerate(const Array *self, ArrayEnumerator enumerator, ident data)
Definition Array.c:334
static Array * array(void)
Definition Array.c:234
static ssize_t indexOfObject(const Array *self, const ident obj)
Definition Array.c:403
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition Class.c:195
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition Class.c:86
#define obj
#define alloc(type)
Allocate and initialize and instance of type.
Definition Class.h:176
#define super(type, obj, method,...)
static Data * data(void)
Definition Data.c:286
int HashForInteger(int hash, const long integer)
Accumulates the hash value of integer into hash.
Definition Hash.c:66
int HashForObject(int hash, const ident obj)
Accumulates the hash value of object into hash.
Definition Hash.c:72
Utilities for calculating hash values.
#define HASH_SEED
The hash seed value.
Definition Hash.h:37
Class * _Object(void)
Definition Object.c:136
static Set * mappedSet(const Set *self, Functor functor, ident data)
Definition Set.c:472
static Set * filteredSet(const Set *self, Predicate predicate, ident data)
Definition Set.c:341
static void initWithArray_enumerator(const Array *array, ident obj, ident data)
ArrayEnumerator for initWithArray.
Definition Set.c:377
static void addObjectsFromArray(Set *self, const Array *array)
Definition Set.c:203
static void allObjects_enumerator(const Set *set, ident obj, ident data)
SetEnumerator for allObjects.
Definition Set.c:231
static Set * initWithCapacity(Set *self, size_t capacity)
Definition Set.c:401
static void addObjectsFromSet(Set *self, const Set *set)
Definition Set.c:221
static bool containsObject(const Set *self, const ident obj)
Definition Set.c:252
static Array * allObjects(const Set *self)
Definition Set.c:239
static bool isEqual(const Object *self, const Object *other)
Definition Set.c:101
static Set * setWithObjects(ident obj,...)
Definition Set.c:599
static void filter(Set *self, Predicate predicate, ident data)
Definition Set.c:314
#define SET_MAX_LOAD
Definition Set.c:36
static void addObject(Set *self, const ident obj)
Definition Set.c:175
static String * description(const Object *self)
Definition Set.c:73
static Set * set(void)
Definition Set.c:572
static void addObjectsFromArray_enumerator(const Array *array, ident obj, ident data)
ArrayEnumerator for addObjectsFromArray.
Definition Set.c:195
#define SET_DEFAULT_CAPACITY
Definition Set.c:34
Class * _Set(void)
Definition Set.c:669
static ident reduce(const Set *self, Reducer reducer, ident accumulator, ident data)
Definition Set.c:502
static Set * setWithArray(const Array *array)
Definition Set.c:581
static void dealloc(Object *self)
Definition Set.c:57
static void removeObject(Set *self, const ident obj)
Definition Set.c:542
static Set * initWithObjects(Set *self,...)
Definition Set.c:421
#define SET_GROW_FACTOR
Definition Set.c:35
static Object * copy(const Object *self)
Definition Set.c:43
static void addObjectsFromSet_enumerator(const Set *set, ident obj, ident data)
SetEnumerator for addObjectsFromSet.
Definition Set.c:213
static void initialize(Class *clazz)
Definition Set.c:632
static void initWithSet_enumerator(const Set *set, ident obj, ident data)
SetEnumerator for initWithSet.
Definition Set.c:448
static Set * initWithSet(Set *self, const Set *set)
Definition Set.c:456
static Set * init(Set *self)
Definition Set.c:369
static Set * initWithArray(Set *self, const Array *array)
Definition Set.c:385
static void addObject_resize(Set *set)
A helper for resizing Sets as Objects are added to them.
Definition Set.c:139
static void removeAllObjects(Set *self)
Definition Set.c:524
static bool containsObjectMatching(const Set *self, Predicate predicate, ident data)
Definition Set.c:270
static Set * setWithSet(const Set *set)
Definition Set.c:622
static void enumerateObjects(const Set *self, SetEnumerator enumerator, ident data)
Definition Set.c:294
static Set * setWithCapacity(size_t capacity)
Definition Set.c:590
static int hash(const Object *self)
Definition Set.c:83
Sets.
void(* SetEnumerator)(const Set *set, ident obj, ident data)
A function pointer for Set enumeration (iteration).
Definition Set.h:48
UTF-8 strings.
void * ident
The identity type, similar to Objective-C id.
Definition Types.h:49
bool(* Predicate)(const ident obj, ident data)
The Predicate function type for filtering Objects.
Definition Types.h:111
ident(* Functor)(const ident obj, ident data)
The Functor function type for transforming Objects.
Definition Types.h:103
ident(* Reducer)(const ident obj, ident accumulator, ident data)
The Reducer function type for reducing collections.
Definition Types.h:127
long Once
The Once type.
Definition Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition Once.h:43
Arrays.
Definition Array.h:56
bool containsObject(const Array *self, const ident obj)
Definition Array.c:326
size_t count
The count of elements.
Definition Array.h:72
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition Class.h:41
The runtime representation of a Class.
Definition Class.h:95
ident interface
The interface of the Class.
Definition Class.h:105
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46
Class * clazz
Every instance of Object begins with a pointer to its Class.
Definition Object.h:55
int hash(const Object *self)
Definition Array.c:129
void dealloc(Object *self)
Frees all resources held by this Object.
Definition Array.c:99
Sets.
Definition Set.h:55
Set * setWithSet(const Set *set)
Returns a new Set with the contents of set.
Definition Set.c:622
size_t count
The count of elements.
Definition Set.h:77
Set * initWithObjects(Set *self,...)
Initializes this Set with the specified objects.
Definition Set.c:421
Set * init(Set *self)
Initializes this Set.
Definition Set.c:369
Set * mappedSet(const Set *self, Functor functor, ident data)
Transforms the elements in this Set by functor.
Definition Set.c:472
Set * initWithArray(Set *self, const Array *array)
Initializes this Set to contain the Objects in array.
Definition Set.c:385
Set * setWithCapacity(size_t capacity)
Returns a new Set with the given capacity.
Definition Set.c:590
Set * initWithSet(Set *self, const Set *set)
Initializes this Set to contain the Objects in set.
Definition Set.c:456
Set * setWithObjects(ident obj,...)
Returns a new Set containing the specified Objects.
Definition Set.c:599
Set * setWithArray(const Array *array)
Returns a new Set with the contents of array.
Definition Set.c:581
ident reduce(const Set *self, Reducer reducer, ident accumulator, ident data)
Definition Set.c:502
Set * initWithCapacity(Set *self, size_t capacity)
Initializes this Set with the specified capacity.
Definition Set.c:401
UTF-8 strings.
Definition String.h:69