interpret/src/lorem.c

72 lines
1.8 KiB
C

/** @license 2023 Neil Edelman, distributed under the terms of the
[MIT License](https://opensource.org/licenses/MIT).
Global stable pool of temporary strings duplicated from substrings. Doesn't
support deletion, only growing.
@std C89 */
#include "lorem.h"
#include <assert.h>
#include <errno.h>
#define ARRAY_NAME block
#define ARRAY_TYPE char *
#include "array.h"
static struct {
size_t capacity, size; /* Lead block. */
struct block_array blocks;
} buffer;
struct lorem lorem(const char *const a, const char *const b) {
struct lorem l;
assert(a && a <= b);
l.sub = a;
l.size = (size_t)(b - a);
return l;
}
const char *lorem_dup(const struct lorem sub) {
char *string;
size_t size;
if(!sub.sub) { errno = EDOM; return 0; } /* Null substring. */
if(sub.size == ~(size_t)0) { errno = ERANGE; return 0; } /* Unlikely. */
if((size = sub.size + 1) > buffer.capacity - buffer.size) {
size_t c0 = buffer.capacity < 8 ? 8 : buffer.capacity;
char *block = 0, **record = 0;
while(c0 < size) { /* Grow. */
size_t c1 = c0 + (c0 >> 1) + (c0 >> 3);
if(c0 >= c1) { c0 = ~(size_t)0; break; } /* Unlikely. */
c0 = c1;
}
if(!(block = malloc(c0))
|| !(record = block_array_new(&buffer.blocks))) { /* Error. */
free(block);
if(!errno) errno = ERANGE;
return 0;
}
*record = block;
buffer.capacity = c0;
buffer.size = 0;
/*printf("%s size %zu\n", orcify(block), c0);*/
}
assert(buffer.blocks.size);
string = buffer.blocks.data[buffer.blocks.size - 1] + buffer.size;
memcpy(string, sub.sub, sub.size);
string[sub.size] = '\0';
buffer.size += size;
return string;
}
void lorem_(void) {
size_t i;
for(i = 0; i < buffer.blocks.size; i++) {
char *block = buffer.blocks.data[i];
/*printf("free %s\n", orcify(block));*/
free(block);
}
buffer.capacity = buffer.size = 0;
block_array_(&buffer.blocks);
}