Objectively 1.0.0
Ultra-lightweight object oriented framework for GNU C.
MutableString.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 "Config.h"
25
26#include <assert.h>
27#include <stdarg.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31
32#include "MutableString.h"
33
34#define _Class _MutableString
35
36#pragma mark - Object
37
41static Object *copy(const Object *self) {
42
43 const String *this = (String *) self;
44
45 return (Object *) $(alloc(MutableString), initWithString, this);
46}
47
48#pragma mark - MutableString
49
54static void appendCharacters(MutableString *self, const char *chars) {
55
56 if (chars) {
57
58 const size_t len = strlen(chars);
59 if (len) {
60
61 const size_t newSize = self->string.length + strlen(chars) + 1;
62 const size_t newCapacity = (newSize / _pageSize + 1) * _pageSize;
63
64 if (newCapacity > self->capacity) {
65
66 if (self->string.length) {
67 self->string.chars = realloc(self->string.chars, newCapacity);
68 } else {
69 self->string.chars = malloc(newCapacity);
70 }
71
72 assert(self->string.chars);
73 self->capacity = newCapacity;
74 }
75
76 ident ptr = self->string.chars + self->string.length;
77 memmove(ptr, chars, len);
78
79 self->string.chars[newSize - 1] = '\0';
80 self->string.length += len;
81 }
82 }
83}
84
89static void appendFormat(MutableString *self, const char *fmt, ...) {
90
91 va_list args;
92 va_start(args, fmt);
93
94 $(self, appendVaList, fmt, args);
95
96 va_end(args);
97}
98
103static void appendString(MutableString *self, const String *string) {
104
105 if (string) {
106 $(self, appendCharacters, string->chars);
107 }
108}
109
114static void appendVaList(MutableString *self, const char *fmt, va_list args) {
115 char *chars;
116
117 const int len = vasprintf(&chars, fmt, args);
118 if (len > 0) {
119 $(self, appendCharacters, chars);
120 }
121
122 free(chars);
123}
124
129static void deleteCharactersInRange(MutableString *self, const Range range) {
130
131 assert(range.location >= 0);
132 assert(range.length <= self->string.length);
133
134 ident ptr = self->string.chars + range.location;
135 const size_t length = self->string.length - range.location - range.length + 1;
136
137 memmove(ptr, ptr + range.length, length);
138
139 self->string.length -= range.length;
140}
141
147 return $(self, initWithCapacity, 0);
148}
149
154static MutableString *initWithCapacity(MutableString *self, size_t capacity) {
155
156 self = (MutableString *) super(String, self, initWithMemory, NULL, 0);
157 if (self) {
158 if (capacity) {
159 self->string.chars = calloc(capacity, sizeof(char));
160 assert(self->string.chars);
161
162 self->capacity = capacity;
163 }
164 }
165
166 return self;
167}
168
173static MutableString *initWithString(MutableString *self, const String *string) {
174
175 self = $(self, init);
176 if (self) {
177 $(self, appendString, string);
178 }
179
180 return self;
181}
182
187static void insertCharactersAtIndex(MutableString *self, const char *chars, size_t index) {
188
189 const Range range = { .location = index };
190
191 $(self, replaceCharactersInRange, range, chars);
192}
193
198static void insertStringAtIndex(MutableString *self, const String *string, size_t index) {
199
200 $(self, insertCharactersAtIndex, string->chars, index);
201}
202
207static void replaceCharactersInRange(MutableString *self, const Range range, const char *chars) {
208
209 assert(range.location >= 0);
210 assert(range.location + range.length <= self->string.length);
211
212 if (self->capacity == 0) {
213 $(self, appendCharacters, chars);
214 } else {
215 char *remainder = strdup(self->string.chars + range.location + range.length);
216
217 self->string.length = range.location;
218 self->string.chars[range.location + 1] = '\0';
219
220 $(self, appendCharacters, chars);
221 $(self, appendCharacters, remainder);
222
223 free(remainder);
224 }
225}
226
231static void replaceOccurrencesOfCharacters(MutableString *self, const char *chars, const char *replacement) {
232 $(self, replaceOccurrencesOfCharactersInRange, chars, (Range) { .length = self->string.length }, replacement);
233}
234
239static void replaceOccurrencesOfCharactersInRange(MutableString *self, const char *chars, const Range range, const char *replacement) {
240
241 assert(chars);
242 assert(replacement);
243
244 assert(range.location >= 0);
245 assert(range.location + range.length <= self->string.length);
246
247 Range search = range;
248 while (true) {
249
250 const Range result = $((String *) self, rangeOfCharacters, chars, search);
251 if (result.location == -1) {
252 break;
253 }
254
255 $(self, replaceCharactersInRange, result, replacement);
256
257 search.length -= (result.location - search.location);
258 search.length -= strlen(replacement);
259 search.length += ((int) strlen(replacement) - (int) strlen(chars));
260
261 search.location = result.location + strlen(replacement);
262 }
263}
264
269static void replaceOccurrencesOfString(MutableString *self, const String *string, const String *replacement) {
270 $(self, replaceOccurrencesOfStringInRange, string, (Range) { .length = self->string.length }, replacement);
271}
272
277static void replaceOccurrencesOfStringInRange(MutableString *self, const String *string, const Range range, const String *replacement) {
278
279 assert(string);
280 assert(replacement);
281
282 $(self, replaceOccurrencesOfCharactersInRange, string->chars, range, replacement->chars);
283}
284
289static void replaceStringInRange(MutableString *self, const Range range, const String *string) {
290
291 $(self, replaceCharactersInRange, range, string->chars);
292}
293
298static MutableString *string(void) {
299
300 return $(alloc(MutableString), init);
301}
302
307static MutableString *stringWithCapacity(size_t capacity) {
308
309 return $(alloc(MutableString), initWithCapacity, capacity);
310}
311
316static void trim(MutableString *self) {
317
318 String *trimmed = $((String *) self, trimmedString);
319
320 $(self, replaceStringInRange, (const Range) { .length = self->string.length }, trimmed);
321
322 release(trimmed);
323}
324
325#pragma mark - Class lifecycle
326
330static void initialize(Class *clazz) {
331
332 ((ObjectInterface *) clazz->interface)->copy = copy;
333
334 ((MutableStringInterface *) clazz->interface)->appendCharacters = appendCharacters;
335 ((MutableStringInterface *) clazz->interface)->appendFormat = appendFormat;
336 ((MutableStringInterface *) clazz->interface)->appendString = appendString;
337 ((MutableStringInterface *) clazz->interface)->appendVaList = appendVaList;
338 ((MutableStringInterface *) clazz->interface)->deleteCharactersInRange = deleteCharactersInRange;
339 ((MutableStringInterface *) clazz->interface)->init = init;
340 ((MutableStringInterface *) clazz->interface)->initWithCapacity = initWithCapacity;
341 ((MutableStringInterface *) clazz->interface)->initWithString = initWithString;
342 ((MutableStringInterface *) clazz->interface)->insertCharactersAtIndex = insertCharactersAtIndex;
343 ((MutableStringInterface *) clazz->interface)->insertStringAtIndex = insertStringAtIndex;
344 ((MutableStringInterface *) clazz->interface)->replaceCharactersInRange = replaceCharactersInRange;
345 ((MutableStringInterface *) clazz->interface)->replaceOccurrencesOfCharacters = replaceOccurrencesOfCharacters;
346 ((MutableStringInterface *) clazz->interface)->replaceOccurrencesOfCharactersInRange = replaceOccurrencesOfCharactersInRange;
347 ((MutableStringInterface *) clazz->interface)->replaceOccurrencesOfString = replaceOccurrencesOfString;
348 ((MutableStringInterface *) clazz->interface)->replaceOccurrencesOfStringInRange = replaceOccurrencesOfStringInRange;
349 ((MutableStringInterface *) clazz->interface)->replaceStringInRange = replaceStringInRange;
350 ((MutableStringInterface *) clazz->interface)->string = string;
351 ((MutableStringInterface *) clazz->interface)->stringWithCapacity = stringWithCapacity;
352 ((MutableStringInterface *) clazz->interface)->trim = trim;
353}
354
360 static Class *clazz;
361 static Once once;
362
363 do_once(&once, {
364 clazz = _initialize(&(const ClassDef) {
365 .name = "MutableString",
366 .superclass = _String(),
367 .instanceSize = sizeof(MutableString),
368 .interfaceOffset = offsetof(MutableString, interface),
369 .interfaceSize = sizeof(MutableStringInterface),
371 });
372 });
373
374 return clazz;
375}
376
377#undef _Class
378
379MutableString *mstr(const char *fmt, ...) {
380
381 MutableString *string = $$(MutableString, string);
382
383 va_list args;
384 va_start(args, fmt);
385
386 $(string, appendVaList, fmt, args);
387
388 va_end(args);
389 return string;
390}
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:196
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition: Class.c:91
#define alloc(type)
Allocate and initialize and instance of type.
Definition: Class.h:159
#define super(type, obj, method,...)
static void initialize(Class *clazz)
Mutable UTF-8 strings.
Immutable 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
Condition * init(Condition *self)
Initializes this Condition.
Definition: Condition.c:67
Data * initWithMemory(Data *self, ident mem, size_t length)
Initializes this Data, taking ownership of the specified memory.
Definition: Data.c:209
MutableArray * initWithCapacity(MutableArray *self, size_t capacity)
Initializes this MutableArray with the specified capacity.
Definition: MutableArray.c:195
Mutable UTF-8 strings.
Definition: MutableString.h:40
String string
The superclass.
Definition: MutableString.h:45
void replaceOccurrencesOfCharacters(MutableString *self, const char *chars, const char *replacement)
Replaces all occurrences of chars with the given replacement.
void replaceStringInRange(MutableString *self, const Range range, const String *string)
Replaces the characters in range with the contents of string.
void trim(MutableString *self)
Trims leading and trailing whitespace from this MutableString.
void insertCharactersAtIndex(MutableString *self, const char *chars, size_t index)
Inserts the specified String at the given index.
void appendString(MutableString *self, const String *string)
Appends the specified String to this MutableString.
void appendVaList(MutableString *self, const char *fmt, va_list args)
Appends the specified format string.
MutableString * initWithString(MutableString *self, const String *string)
Initializes this MutableString with the contents of string.
void replaceCharactersInRange(MutableString *self, const Range range, const char *chars)
Replaces the characters in range with the given characters.
MutableString * stringWithCapacity(size_t capacity)
Returns a new MutableString with the given capacity.
Class * _MutableString(void)
The MutableString archetype.
void replaceOccurrencesOfCharactersInRange(MutableString *self, const char *chars, const Range range, const char *replacement)
Replaces occurrences of chars in range with the given replacement.
void appendFormat(MutableString *self, const char *fmt,...)
Appends the specified formatted string.
Definition: MutableString.c:89
void replaceOccurrencesOfString(MutableString *self, const String *string, const String *replacement)
Replaces all occurrences of string with the given replacement.
void replaceOccurrencesOfStringInRange(MutableString *self, const String *string, const Range range, const String *replacement)
Replaces occurrences of string in range with the given replacement.
MutableString * string(void)
Returns a new MutableString.
void deleteCharactersInRange(MutableString *self, const Range range)
Deletes the characters within range from this MutableString.
void appendCharacters(MutableString *self, const char *chars)
Appends the specified UTF-8 encoded C string.
Definition: MutableString.c:54
void insertStringAtIndex(MutableString *self, const String *string, size_t index)
Inserts the specified String at the given index.
Object is the root Class of The Objectively Class hierarchy.
Definition: Object.h:46
Object * copy(const Object *self)
Creates a shallow copy of this Object.
Definition: Array.c:40
A location and length into contiguous collections.
Definition: Types.h:54
ssize_t location
The location.
Definition: Types.h:59
size_t length
The length.
Definition: Types.h:64
Immutable UTF-8 strings.
Definition: String.h:69
char * chars
The backing null-terminated UTF-8 encoded character array.
Definition: String.h:85
size_t length
The length of the String in bytes.
Definition: String.h:90
String * trimmedString(const String *self)
Creates a copy of this String with leading and trailing whitespace removed.
Definition: String.c:555
OBJECTIVELY_EXPORT MutableString * mstr(const char *fmt,...)
A convenience function for instantiating MutableStrings.
Range rangeOfCharacters(const String *self, const char *chars, const Range range)
Finds and returns the first occurrence of chars in this String.
Definition: String.c:441
Class * _String(void)
The String archetype.
Definition: String.c:654