Objectively
Ultra-lightweight object oriented framework for GNU C.
Loading...
Searching...
No Matches
Data.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 <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include "Data.h"
30#include "Hash.h"
31
32#define _Class _Data
33
34#define DATA_BLOCK_SIZE 4096
35
36#pragma mark - Object
37
41static Object *copy(const Object *self) {
42
43 const Data *this = (const Data *) self;
44
45 Data *that = $(alloc(Data), initWithCapacity, this->capacity ?: this->length);
46 $(that, appendBytes, this->bytes, this->length);
47
48 return (Object *) that;
49}
50
54static void dealloc(Object *self) {
55
56 Data *this = (Data *) self;
57
58 if (this->destroy) {
59 if (this->bytes) {
60 this->destroy(this->bytes);
61 }
62 }
63
64 super(Object, self, dealloc);
65}
66
70static int hash(const Object *self) {
71
72 Data *this = (Data *) self;
73
74 int hash = HASH_SEED;
75 hash = HashForInteger(hash, this->length);
76
77 const Range range = { 0, this->length };
78 hash = HashForBytes(hash, this->bytes, range);
79
80 return hash;
81}
82
86static bool isEqual(const Object *self, const Object *other) {
87
88 if (super(Object, self, isEqual, other)) {
89 return true;
90 }
91
92 if (other && $(other, isKindOfClass, _Data())) {
93
94 const Data *this = (Data *) self;
95 const Data *that = (Data *) other;
96
97 if (this->length == that->length) {
98 if (this->length == 0) {
99 return true;
100 }
101
102 return memcmp(this->bytes, that->bytes, this->length) == 0;
103 }
104 }
105
106 return false;
107}
108
109#pragma mark - Data
110
115static Data *dataWithBytes(const uint8_t *bytes, size_t length) {
116
117 return $(alloc(Data), initWithBytes, bytes, length);
118}
119
124static Data *dataWithConstMemory(const ident mem, size_t length) {
125
126 return $(alloc(Data), initWithConstMemory, mem, length);
127}
128
133static Data *dataWithContentsOfFile(const char *path) {
134
135 return $(alloc(Data), initWithContentsOfFile, path);
136}
137
142static Data *dataWithMemory(ident mem, size_t length) {
143
144 return $(alloc(Data), initWithMemory, mem, length);
145}
146
151static Data *initWithBytes(Data *self, const uint8_t *bytes, size_t length) {
152
153 ident mem = NULL;
154 if (length) {
155 mem = malloc(length);
156 assert(mem);
157
158 memcpy(mem, bytes, length);
159 }
160
161 return $(self, initWithMemory, mem, length);
162}
163
168static Data *initWithConstMemory(Data *self, const ident mem, size_t length) {
169
170 self = (Data *) super(Object, self, init);
171 if (self) {
172 self->bytes = mem;
173 self->length = length;
174 self->capacity = length;
175 }
176
177 return self;
178}
179
184static Data *initWithContentsOfFile(Data *self, const char *path) {
185
186 assert(path);
187
188 FILE *file = fopen(path, "rb");
189 if (file) {
190 ident mem = NULL;
191
192 int err = fseek(file, 0, SEEK_END);
193 assert(err == 0);
194
195 const size_t length = ftell(file);
196 if (length) {
197
198 mem = malloc(length);
199 assert(mem);
200
201 err = fseek(file, 0, SEEK_SET);
202 assert(err == 0);
203
204 const size_t read = fread(mem, length, 1, file);
205 assert(read == 1);
206 }
207
208 fclose(file);
209 return $(self, initWithMemory, mem, length);
210 }
211
212 return release(self);
213}
214
219static Data *initWithMemory(Data *self, ident mem, size_t length) {
220
221 self = $(self, initWithConstMemory, mem, length);
222 if (self) {
223 self->destroy = free;
224 }
225
226 return self;
227}
228
233static bool writeToFile(const Data *self, const char *path) {
234
235 assert(path);
236
237 FILE *file = fopen(path, "w");
238 if (file) {
239
240 size_t count = 1;
241
242 if (self->length) {
243 count = fwrite(self->bytes, self->length, 1, file);
244 }
245
246 fclose(file);
247
248 if (count == 1) {
249 return true;
250 }
251 }
252
253 return false;
254}
255
256#pragma mark - Data mutation
257
262static void appendBytes(Data *self, const uint8_t *bytes, size_t length) {
263
264 const size_t oldLength = self->length;
265
266 $(self, setLength, self->length + length);
267
268 if (length) {
269 memcpy(self->bytes + oldLength, bytes, length);
270 }
271}
272
277static void appendData(Data *self, const Data *data) {
278
279 $(self, appendBytes, data->bytes, data->length);
280}
281
286static Data *data(void) {
287
288 return $(alloc(Data), init);
289}
290
295static Data *dataWithCapacity(size_t capacity) {
296
297 return $(alloc(Data), initWithCapacity, capacity);
298}
299
304static Data *init(Data *self) {
305
306 return $(self, initWithCapacity, 0);
307}
308
313static Data *initWithCapacity(Data *self, size_t capacity) {
314
315 self = (Data *) super(Object, self, init);
316 if (self) {
317
318 self->capacity = capacity;
319 if (self->capacity) {
320
321 self->bytes = calloc(capacity, sizeof(uint8_t));
322 assert(self->bytes);
323 }
324
325 self->destroy = free;
326 }
327
328 return self;
329}
330
335static Data *initWithData(Data *self, const Data *data) {
336
337 self = $(self, initWithCapacity, data->length);
338 if (self) {
339 $(self, appendData, data);
340 }
341
342 return self;
343}
344
349static void setLength(Data *self, size_t length) {
350
351 const size_t newCapacity = (length / _pageSize + 1) * _pageSize;
352 if (newCapacity > self->capacity) {
353
354 if (self->bytes == NULL) {
355 self->bytes = calloc(newCapacity, sizeof(uint8_t));
356 assert(self->bytes);
357 } else {
358 if (self->destroy != free) {
359 uint8_t *owned = malloc(newCapacity);
360 assert(owned);
361 memcpy(owned, self->bytes, self->length);
362 if (length > self->length) {
363 memset(owned + self->length, 0, length - self->length);
364 }
365 self->bytes = owned;
366 self->destroy = free;
367 } else {
368 self->bytes = realloc(self->bytes, newCapacity);
369 assert(self->bytes);
370 if (length > self->length) {
371 memset(self->bytes + self->length, 0, length - self->length);
372 }
373 }
374 }
375
376 self->capacity = newCapacity;
377 } else if (length > self->length) {
378 memset(self->bytes + self->length, 0, length - self->length);
379 }
380
381 self->length = length;
382}
383
384#pragma mark - Class lifecycle
385
389static void initialize(Class *clazz) {
390
391 ((ObjectInterface *) clazz->interface)->copy = copy;
392 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
393 ((ObjectInterface *) clazz->interface)->hash = hash;
394 ((ObjectInterface *) clazz->interface)->isEqual = isEqual;
395
396 ((DataInterface *) clazz->interface)->dataWithBytes = dataWithBytes;
397 ((DataInterface *) clazz->interface)->dataWithConstMemory = dataWithConstMemory;
398 ((DataInterface *) clazz->interface)->dataWithContentsOfFile = dataWithContentsOfFile;
399 ((DataInterface *) clazz->interface)->dataWithMemory = dataWithMemory;
400 ((DataInterface *) clazz->interface)->initWithBytes = initWithBytes;
401 ((DataInterface *) clazz->interface)->initWithConstMemory = initWithConstMemory;
402 ((DataInterface *) clazz->interface)->initWithContentsOfFile = initWithContentsOfFile;
403 ((DataInterface *) clazz->interface)->initWithMemory = initWithMemory;
404 ((DataInterface *) clazz->interface)->appendBytes = appendBytes;
405 ((DataInterface *) clazz->interface)->appendData = appendData;
406 ((DataInterface *) clazz->interface)->data = data;
407 ((DataInterface *) clazz->interface)->dataWithCapacity = dataWithCapacity;
408 ((DataInterface *) clazz->interface)->init = init;
409 ((DataInterface *) clazz->interface)->initWithCapacity = initWithCapacity;
410 ((DataInterface *) clazz->interface)->initWithData = initWithData;
411 ((DataInterface *) clazz->interface)->setLength = setLength;
412 ((DataInterface *) clazz->interface)->writeToFile = writeToFile;
413}
414
419Class *_Data(void) {
420 static Class *clazz;
421 static Once once;
422
423 do_once(&once, {
424 clazz = _initialize(&(const ClassDef) {
425 .name = "Data",
426 .superclass = _Object(),
427 .instanceSize = sizeof(Data),
428 .interfaceOffset = offsetof(Data, interface),
429 .interfaceSize = sizeof(DataInterface),
431 });
432 });
433
434 return clazz;
435}
436
437#undef _Class
static void destroy(Class *clazz)
Definition Boole.c:102
size_t _pageSize
Definition Class.c:39
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 alloc(type)
Allocate and initialize and instance of type.
Definition Class.h:176
#define super(type, obj, method,...)
static Data * initWithBytes(Data *self, const uint8_t *bytes, size_t length)
Definition Data.c:151
Class * _Data(void)
Definition Data.c:419
static void setLength(Data *self, size_t length)
Definition Data.c:349
static bool writeToFile(const Data *self, const char *path)
Definition Data.c:233
static bool isEqual(const Object *self, const Object *other)
Definition Data.c:86
static Data * dataWithConstMemory(const ident mem, size_t length)
Definition Data.c:124
static void appendData(Data *self, const Data *data)
Definition Data.c:277
static Data * initWithCapacity(Data *self, size_t capacity)
Definition Data.c:313
static Data * init(Data *self)
Definition Data.c:304
static Data * initWithContentsOfFile(Data *self, const char *path)
Definition Data.c:184
static Data * data(void)
Definition Data.c:286
static void dealloc(Object *self)
Definition Data.c:54
static void appendBytes(Data *self, const uint8_t *bytes, size_t length)
Definition Data.c:262
static Data * dataWithContentsOfFile(const char *path)
Definition Data.c:133
static Object * copy(const Object *self)
Definition Data.c:41
static void initialize(Class *clazz)
Definition Data.c:389
static Data * initWithData(Data *self, const Data *data)
Definition Data.c:335
static Data * dataWithCapacity(size_t capacity)
Definition Data.c:295
static Data * dataWithMemory(ident mem, size_t length)
Definition Data.c:142
static Data * dataWithBytes(const uint8_t *bytes, size_t length)
Definition Data.c:115
static int hash(const Object *self)
Definition Data.c:70
static Data * initWithConstMemory(Data *self, const ident mem, size_t length)
Definition Data.c:168
static Data * initWithMemory(Data *self, ident mem, size_t length)
Definition Data.c:219
Data buffers.
int HashForInteger(int hash, const long integer)
Accumulates the hash value of integer into hash.
Definition Hash.c:66
int HashForBytes(int hash, const uint8_t *bytes, const Range range)
Accumulates the hash value of bytes into hash.
Definition Hash.c:28
Utilities for calculating hash values.
#define HASH_SEED
The hash seed value.
Definition Hash.h:37
static bool isKindOfClass(const Object *self, const Class *clazz)
Definition Object.c:101
Class * _Object(void)
Definition Object.c:136
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
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
Data buffers.
Definition Data.h:50
Data * initWithContentsOfFile(Data *self, const char *path)
Initializes this Data with the contents of the file at path.
Definition Data.c:184
Data * initWithMemory(Data *self, ident mem, size_t length)
Initializes this Data, taking ownership of the specified memory.
Definition Data.c:219
Data * initWithData(Data *self, const Data *data)
Initializes this Data with the contents of data.
Definition Data.c:335
Data * init(Data *self)
Initializes this Data with length 0.
Definition Data.c:304
DataDestructor destroy
An optional destructor that, if set, is called on dealloc.
Definition Data.h:71
Data * dataWithMemory(ident mem, size_t length)
Returns a new Data, taking ownership of the specified memory.
Definition Data.c:142
Data * dataWithContentsOfFile(const char *path)
Returns a new Data with the contents of the file at path.
Definition Data.c:133
void appendBytes(Data *self, const uint8_t *bytes, size_t length)
Appends the given bytes to this Data.
Definition Data.c:262
size_t length
The length of bytes.
Definition Data.h:76
uint8_t * bytes
The bytes.
Definition Data.h:66
Data * initWithCapacity(Data *self, size_t capacity)
Initializes this Data with the given capacity.
Definition Data.c:313
void setLength(Data *self, size_t length)
Sets the length of this Data, truncating or expanding it.
Definition Data.c:349
Data * initWithConstMemory(Data *self, const ident mem, size_t length)
Initializes this Data with the given const memory.
Definition Data.c:168
Data * initWithBytes(Data *self, const uint8_t *bytes, size_t length)
Initializes this Data by copying length of bytes.
Definition Data.c:151
Data * dataWithConstMemory(const ident mem, size_t length)
Returns a new Data, backed by the given const memory.
Definition Data.c:124
Data * dataWithCapacity(size_t capacity)
Returns a new Data with the given capacity.
Definition Data.c:295
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46
void dealloc(Object *self)
Frees all resources held by this Object.
Definition Array.c:99
A location and length into contiguous collections.
Definition Types.h:54