Objectively 1.0.0
Ultra-lightweight object oriented framework for GNU C.
Dictionary.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 "Dictionary.h"
29#include "Hash.h"
30#include "MutableArray.h"
31#include "MutableDictionary.h"
32#include "MutableString.h"
33
34#define _Class _Dictionary
35
36#pragma mark - Object
37
41static Object *copy(const Object *self) {
42
43 const Dictionary *this = (Dictionary *) self;
44
46
47 return (Object *) that;
48}
49
53static void dealloc(Object *self) {
54
55 Dictionary *this = (Dictionary *) self;
56
57 for (size_t i = 0; i < this->capacity; i++) {
58 release(this->elements[i]);
59 }
60
61 free(this->elements);
62
63 super(Object, self, dealloc);
64}
65
69static void description_enumerator(const Dictionary *dict, ident obj, ident key, ident data) {
70
72
73 String *objDesc = $((Object *) obj, description);
74 String *keyDesc = $((Object *) key, description);
75
76 $(desc, appendFormat, "%s: %s, ", keyDesc->chars, objDesc->chars);
77
78 release(objDesc);
79 release(keyDesc);
80}
81
85static String *description(const Object *self) {
86
87 const Dictionary *this = (Dictionary *) self;
88
90
91 $(desc, appendCharacters, "{");
92
94
95 $(desc, appendCharacters, "}");
96
97 return (String *) desc;
98}
99
103static int hash(const Object *self) {
104
105 const Dictionary *this = (Dictionary *) self;
106
107 int hash = HashForInteger(HASH_SEED, this->count);
108
109 for (size_t i = 0; i < this->capacity; i++) {
110 if (this->elements[i]) {
111 hash = HashForObject(hash, this->elements[i]);
112 }
113 }
114
115 return hash;
116}
117
121static _Bool isEqual(const Object *self, const Object *other) {
122
123 if (super(Object, self, isEqual, other)) {
124 return true;
125 }
126
127 if (other && $(other, isKindOfClass, _Dictionary())) {
128
129 const Dictionary *this = (Dictionary *) self;
130 const Dictionary *that = (Dictionary *) other;
131
132 if (this->count == that->count) {
133
134 Array *keys = $(this, allKeys);
135
136 for (size_t i = 0; i < keys->count; i++) {
137 const ident key = $(keys, objectAtIndex, i);
138
139 const Object *thisObject = $(this, objectForKey, key);
140 const Object *thatObject = $(that, objectForKey, key);
141
142 if ($(thisObject, isEqual, thatObject) == false) {
143 release(keys);
144 return false;
145 }
146 }
147
148 release(keys);
149 return true;
150 }
151 }
152
153 return false;
154}
155
156#pragma mark - Dictionary
157
161static void allKeys_enumerator(const Dictionary *dict, ident obj, ident key, ident data) {
162 $((MutableArray *) data, addObject, key);
163}
164
169static Array *allKeys(const Dictionary *self) {
170
172
174
175 return (Array *) keys;
176}
177
181static void allObjects_enumerator(const Dictionary *dict, ident obj, ident key, ident data) {
183}
184
189static Array *allObjects(const Dictionary *self) {
190
192
194
195 return (Array *) objects;
196}
197
202static _Bool containsKey(const Dictionary *self, const ident key) {
203 return $(self, objectForKey, key) != NULL;
204}
205
210static _Bool containsKeyPath(const Dictionary *self, const char *path) {
211 return $(self, objectForKeyPath, path) != NULL;
212}
213
219
221}
222
228
229 Dictionary *dict = (Dictionary *) $((Object *) alloc(Dictionary), init);
230 if (dict) {
231
232 va_list args;
233 va_start(args, obj);
234
235 while (obj) {
236 ident key = va_arg(args, ident);
237
239
240 obj = va_arg(args, ident);
241 }
242
243 va_end(args);
244 }
245
246 return dict;
247}
248
253static void enumerateObjectsAndKeys(const Dictionary *self, DictionaryEnumerator enumerator,
254 ident data) {
255
256 assert(enumerator);
257
258 for (size_t i = 0; i < self->capacity; i++) {
259
260 Array *array = self->elements[i];
261 if (array) {
262
263 for (size_t j = 0; j < array->count; j += 2) {
264
265 ident key = $(array, objectAtIndex, j);
266 ident obj = $(array, objectAtIndex, j + 1);
267
268 enumerator(self, obj, key, data);
269 }
270 }
271 }
272}
273
279
280 assert(predicate);
281
283
284 for (size_t i = 0; i < self->capacity; i++) {
285
286 Array *array = self->elements[i];
287 if (array) {
288
289 for (size_t j = 0; j < array->count; j += 2) {
290
291 ident key = $(array, objectAtIndex, j);
292 ident obj = $(array, objectAtIndex, j + 1);
293
294 if (predicate(obj, key, data)) {
296 }
297 }
298 }
299 }
300
301 return (Dictionary *) dictionary;
302}
303
309
310 self = (Dictionary *) super(Object, self, init);
311 if (self) {
312 if (dictionary) {
313
314 self->capacity = dictionary->capacity;
315
316 self->elements = calloc(self->capacity, sizeof(ident));
317 assert(self->elements);
318
319 for (size_t i = 0; i < dictionary->capacity; i++) {
320
321 Array *array = dictionary->elements[i];
322 if (array) {
323 self->elements[i] = $((Object *) array, copy);
324 }
325 }
326
327 self->count = dictionary->count;
328 }
329 }
330
331 return self;
332}
333
339
340 self = (Dictionary *) super(Object, self, init);
341 if (self) {
342
343 va_list args;
344 va_start(args, self);
345
346 while (true) {
347
348 ident obj = va_arg(args, ident);
349 if (obj) {
350
351 ident key = va_arg(args, ident);
353 } else {
354 break;
355 }
356 }
357
358 va_end(args);
359 }
360
361 return self;
362}
363
369
371 if (copy) {
373 }
374
375 return copy;
376}
377
382static ident objectForKey(const Dictionary *self, const ident key) {
383
384 if (self->capacity == 0) {
385 return NULL;
386 }
387
388 const size_t bin = HashForObject(HASH_SEED, key) % self->capacity;
389
390 Array *array = self->elements[bin];
391 if (array) {
392
393 const ssize_t index = $(array, indexOfObject, key);
394 if (index > -1 && (index & 1) == 0) {
395 return $(array, objectAtIndex, index + 1);
396 }
397 }
398
399 return NULL;
400}
401
406static ident objectForKeyPath(const Dictionary *self, const char *path) {
407
408 assert(path);
409
410 String *key = str(path);
411
412 ident obj = $(self, objectForKey, key);
413
414 release(key);
415
416 return obj;
417}
418
419#pragma mark - Class lifecycle
420
424static void initialize(Class *clazz) {
425
426 ((ObjectInterface *) clazz->interface)->copy = copy;
427 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
428 ((ObjectInterface *) clazz->interface)->description = description;
429 ((ObjectInterface *) clazz->interface)->hash = hash;
430 ((ObjectInterface *) clazz->interface)->isEqual = isEqual;
431
432 ((DictionaryInterface *) clazz->interface)->allKeys = allKeys;
433 ((DictionaryInterface *) clazz->interface)->allObjects = allObjects;
434 ((DictionaryInterface *) clazz->interface)->containsKey = containsKey;
435 ((DictionaryInterface *) clazz->interface)->containsKeyPath = containsKeyPath;
436 ((DictionaryInterface *) clazz->interface)->dictionaryWithDictionary = dictionaryWithDictionary;
437 ((DictionaryInterface *) clazz->interface)->dictionaryWithObjectsAndKeys = dictionaryWithObjectsAndKeys;
438 ((DictionaryInterface *) clazz->interface)->enumerateObjectsAndKeys = enumerateObjectsAndKeys;
439 ((DictionaryInterface *) clazz->interface)->filterObjectsAndKeys = filterObjectsAndKeys;
440 ((DictionaryInterface *) clazz->interface)->initWithDictionary = initWithDictionary;
441 ((DictionaryInterface *) clazz->interface)->initWithObjectsAndKeys = initWithObjectsAndKeys;
442 ((DictionaryInterface *) clazz->interface)->mutableCopy = mutableCopy;
443 ((DictionaryInterface *) clazz->interface)->objectForKey = objectForKey;
444 ((DictionaryInterface *) clazz->interface)->objectForKeyPath = objectForKeyPath;
445}
446
452 static Class *clazz;
453 static Once once;
454
455 do_once(&once, {
456 clazz = _initialize(&(const ClassDef) {
457 .name = "Dictionary",
458 .superclass = _Object(),
459 .instanceSize = sizeof(Dictionary),
460 .interfaceOffset = offsetof(Dictionary, interface),
461 .interfaceSize = sizeof(DictionaryInterface),
463 });
464 });
465
466 return clazz;
467}
468
469#undef _Class
470
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition: Class.c:196
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition: Class.c:91
#define obj
#define alloc(type)
Allocate and initialize and instance of type.
Definition: Class.h:159
#define super(type, obj, method,...)
static void description_enumerator(const Dictionary *dict, ident obj, ident key, ident data)
A DictionaryEnumerator for description.
Definition: Dictionary.c:69
static void allKeys_enumerator(const Dictionary *dict, ident obj, ident key, ident data)
DictionaryEnumerator for allKeys.
Definition: Dictionary.c:161
static void allObjects_enumerator(const Dictionary *dict, ident obj, ident key, ident data)
DictionaryEnumerator for allObjects.
Definition: Dictionary.c:181
static void initialize(Class *clazz)
Definition: Dictionary.c:424
Immutable key-value stores.
void(* DictionaryEnumerator)(const Dictionary *dictionary, ident obj, ident key, ident data)
A function type for Dictionary enumeration (iteration).
Definition: Dictionary.h:44
_Bool(* DictionaryPredicate)(ident obj, ident key, ident data)
A function pointer for Dictionary filtering.
Definition: Dictionary.h:53
int HashForInteger(int hash, const long integer)
Accumulates the hash value of integer into hash.
Definition: Hash.c:62
int HashForObject(int hash, const ident obj)
Accumulates the hash value of object into hash.
Definition: Hash.c:66
Utilities for calculating hash values.
#define HASH_SEED
The hash seed value.
Definition: Hash.h:37
Mutable arrays.
Mutable key-value stores.
Mutable UTF-8 strings.
void * ident
The identity type, similar to Objective-C id.
Definition: Types.h:49
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
Immutable arrays.
Definition: Array.h:56
MutableArray * mutableCopy(const Array *self)
Definition: Array.c:381
ssize_t indexOfObject(const Array *self, const ident obj)
Definition: Array.c:271
ident objectAtIndex(const Array *self, int index)
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
Condition * init(Condition *self)
Initializes this Condition.
Definition: Condition.c:67
Immutable key-value stores.
Definition: Dictionary.h:60
MutableDictionary * mutableCopy(const Dictionary *self)
Definition: Dictionary.c:368
Class * _Dictionary(void)
The Dictionary archetype.
Definition: Dictionary.c:451
Array * allObjects(const Dictionary *self)
Definition: Dictionary.c:189
Dictionary * dictionaryWithObjectsAndKeys(ident obj,...)
Returns a new Dictionary containing pairs from the given arguments.
Definition: Dictionary.c:227
Dictionary * initWithDictionary(Dictionary *self, const Dictionary *dictionary)
Initializes this Dictionary to contain elements of dictionary.
Definition: Dictionary.c:308
ident objectForKeyPath(const Dictionary *self, const char *path)
Definition: Dictionary.c:406
Dicionary * filterObjectsAndKeys(const Dictionary *self, DictionaryPredicate predicate, ident data)
Creates a new Dictionary with pairs that pass the filter function.
Definition: Dictionary.c:278
size_t count
The count of elements.
Definition: Dictionary.h:82
Array * allKeys(const Dictionary *self)
Definition: Dictionary.c:169
_Bool containsKeyPath(const Dictionary *self, const char *path)
Definition: Dictionary.c:210
_Bool containsKey(const Dictionary *self, const ident key)
Definition: Dictionary.c:202
Dictionary * dictionaryWithDictionary(const Dictionary *dictionary)
Returns a new Dictionary containing all pairs from dictionary.
Definition: Dictionary.c:218
ident objectForKey(const Dictionary *self, const ident key)
Definition: Dictionary.c:382
Dictionary * initWithObjectsAndKeys(Dictionary *self,...)
Initializes this Dictionary with the NULL-terminated list of Objects and keys.
Definition: Dictionary.c:338
void enumerateObjectsAndKeys(const Dictionary *self, DictionaryEnumerator enumerator, ident data)
Enumerate the pairs of this Dictionary with the given function.
Definition: Dictionary.c:253
Mutable arrays.
Definition: MutableArray.h:40
void addObject(MutableArray *self, const ident obj)
Adds the specified Object to this MutableArray.
Definition: MutableArray.c:99
MutableArray * array(void)
Returns a new MutableArray.
Definition: MutableArray.c:153
MutableArray * initWithCapacity(MutableArray *self, size_t capacity)
Initializes this MutableArray with the specified capacity.
Definition: MutableArray.c:195
MutableData * data(void)
Returns a new MutableData.
Definition: MutableData.c:75
Mutable key-value stores.
void setObjectForKey(MutableDictionary *self, const ident obj, const ident key)
Sets a pair in this MutableDictionary.
MutableDictionary * dictionary(void)
Returns a new MutableDictionary.
void addEntriesFromDictionary(MutableDictionary *self, const Dictionary *dictionary)
Adds the key-value entries from dictionary to this MutableDictionary.
Mutable UTF-8 strings.
Definition: MutableString.h:40
void appendFormat(MutableString *self, const char *fmt,...)
Appends the specified formatted string.
Definition: MutableString.c:89
void appendCharacters(MutableString *self, const char *chars)
Appends the specified UTF-8 encoded C string.
Definition: MutableString.c:54
Object is the root Class of The Objectively Class hierarchy.
Definition: Object.h:46
Class * _Object(void)
The Object archetype.
Definition: Object.c:136
Object * copy(const Object *self)
Creates a shallow copy of this Object.
Definition: Array.c:40
_Bool isKindOfClass(const Object *self, const Class *clazz)
Tests for Class hierarchy membership.
Definition: Object.c:101
String * description(const Object *self)
Definition: Array.c:66
_Bool isEqual(const Object *self, const Object *other)
Tests equality of the other Object.
Definition: Array.c:96
int hash(const Object *self)
Definition: Array.c:80
void dealloc(Object *self)
Frees all resources held by this Object.
Definition: Array.c:50
Immutable UTF-8 strings.
Definition: String.h:69
char * chars
The backing null-terminated UTF-8 encoded character array.
Definition: String.h:85
OBJECTIVELY_EXPORT String * str(const char *fmt,...)
A convenience function for instantiating Strings.
Definition: String.c:739