From b73194d47dd54cf3c2f1a2d118e06262465dfb6d Mon Sep 17 00:00:00 2001 From: Neil Date: Tue, 27 Dec 2022 13:59:47 -0800 Subject: [PATCH] Removed the directory now that it's duplicated in interpet. --- kjv-code/Makefile | 242 ---------- kjv-code/src/array.h | 430 ------------------ kjv-code/src/kjv.re_c.c | 369 ---------------- kjv-code/src/table.h | 934 --------------------------------------- kjv-code/src/to_string.h | 171 ------- 5 files changed, 2146 deletions(-) delete mode 100644 kjv-code/Makefile delete mode 100644 kjv-code/src/array.h delete mode 100644 kjv-code/src/kjv.re_c.c delete mode 100644 kjv-code/src/table.h delete mode 100644 kjv-code/src/to_string.h diff --git a/kjv-code/Makefile b/kjv-code/Makefile deleted file mode 100644 index b0059b7..0000000 --- a/kjv-code/Makefile +++ /dev/null @@ -1,242 +0,0 @@ -# GNU Make 3.81; MacOSX gcc 4.2.1; clang 19.6.0; MacOSX MinGW 4.3.0 - -# https://stackoverflow.com/questions/18136918/how-to-get-current-relative-directory-of-your-makefile -mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST))) -current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path)))) - -project := $(current_dir) - -# dirs -src := src -test := test -build := build -bin := bin -backup := backup -doc := doc -media := media -#lemon := lemon -PREFIX := /usr/local - -# files in $(bin) -install := $(project)-`date +%Y-%m-%d` - -# extra stuff we should back up -extra := - -# John Graham-Cumming: rwildcard is a recursive wildcard -rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) \ -$(filter $(subst *,%,$2),$d)) - -java_srcs := $(call rwildcard, $(src), *.java) -all_c_srcs := $(call rwildcard, $(src), *.c) -c_re_srcs := $(call rwildcard, $(src), *.re.c) -c_rec_srcs := $(call rwildcard, $(src), *.re_c.c) -c_gperf_srcs := $(call rwildcard, $(src), *.gperf.c) -c_srcs := $(filter-out $(c_re_srcs) $(c_rec_srcs) $(c_gperf_srcs), $(all_c_srcs)) -h_srcs := $(call rwildcard, $(src), *.h) -y_srcs := $(call rwildcard, $(src), *.y) -all_c_tests := $(call rwildcard, $(test), *.c) -c_re_tests := $(call rwildcard, $(test), *.re.c) -c_rec_tests := $(call rwildcard, $(test), *.re_c.c) -c_tests := $(filter-out $(c_re_tests) $(c_rec_tests), $(all_c_tests)) -h_tests := $(call rwildcard, $(test), *.h) -icons := $(call rwildcard, $(media), *.ico) - -# combinations -all_h := $(h_srcs) $(h_tests) -all_srcs := $(java_srcs) $(all_c_srcs) $(y_srcs) -all_tests := $(all_c_tests) -all_icons := $(icons) - -java_class := $(patsubst $(src)/%.java, $(build)/%.class, $(java_srcs)) -c_objs := $(patsubst $(src)/%.c, $(build)/%.o, $(c_srcs)) -# must not conflict, eg, foo.c.re and foo.c would go to the same thing -c_re_builds := $(patsubst $(src)/%.re.c, $(build)/%.c, $(c_re_srcs)) -c_re_test_builds := $(patsubst $(test)/%.re.c, $(build)/$(test)/%.c, $(c_re_tests)) -c_rec_builds := $(patsubst $(src)/%.re_c.c, $(build)/%.c, $(c_rec_srcs)) -c_rec_test_builds := $(patsubst $(test)/%.re_c.c, $(build)/%.c, $(c_rec_tests)) -c_y_builds := $(patsubst $(src)/%.y, $(build)/%.c, $(y_srcs)) -c_gperf_builds := $(patsubst $(src)/%.gperf.c, $(build)/%.c, $(c_gperf_srcs)) -# together .re/.re_c/.y/.gperf.c -c_other_objs := $(patsubst $(build)/%.c, $(build)/%.o, $(c_re_builds) \ -$(c_rec_builds) $(c_re_test_builds) $(c_rec_test_builds) $(c_y_builds) $(c_gperf_builds)) -test_c_objs := $(patsubst $(test)/%.c, $(build)/$(test)/%.o, $(c_tests)) -html_docs := $(patsubst $(src)/%.c, $(doc)/%.html, $(c_srcs)) - -cdoc := cdoc -re2c := re2c -mkdir := mkdir -p -cat := cat -zip := zip -bison := bison -#lemon := lemon -gperf := gperf - -target := # -mwindows -optimize := -ffast-math -warnbasic := -Wall -pedantic #-ansi # -std=c99 -# Some stuff is really new. -warnclang := -Wextra \ --Weverything \ --Wno-comma \ --Wno-logical-op-parentheses \ --Wno-parentheses \ --Wno-documentation-unknown-command \ --Wno-documentation \ --Wno-shift-op-parentheses \ --Wno-empty-body \ --Wno-padded \ --Wno-switch-enum \ --Wno-missing-noreturn \ --Wno-implicit-fallthrough - -# https://stackoverflow.com/a/12099167 -UNAME_S := $(shell uname -s) -ifeq ($(UNAME_S),Darwin) - warnclang += -Wno-poison-system-directories -endif - -warn := $(warnbasic) $(warnclang) - -CC := clang # gcc -CF := $(target) $(optimize) $(warn) -OF := # -lm -framework OpenGL -framework GLUT or -lglut -lGLEW - -# Jakob Borg and Eldar Abusalimov -# $(ARGS) is all the extra arguments; $(BRGS) is_all_the_extra_arguments -EMPTY := -SPACE := $(EMPTY) $(EMPTY) -ifeq (backup, $(firstword $(MAKECMDGOALS))) - ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) - BRGS := $(subst $(SPACE),_,$(ARGS)) - ifneq (,$(BRGS)) - BRGS := -$(BRGS) - endif - $(eval $(ARGS):;@:) -endif -ifeq (release, $(firstword $(MAKECMDGOALS))) - CF += -funroll-loops -Ofast -D NDEBUG # -O3 - OF += -Ofast -else - CF += -g -endif - -###### -# compiles the programme by default - -default: $(bin)/$(project) - # . . . success; executable is in $(bin)/$(project) - -docs: $(html_docs) - -# linking -$(bin)/$(project): $(c_objs) $(c_other_objs) $(test_c_objs) - # linking rule - @$(mkdir) $(bin) - $(CC) $(OF) -o $@ $^ - -# compiling -#$(lemon)/$(bin)/$(lem): $(lemon)/$(src)/lemon.c -# # compiling lemon -# @$(mkdir) $(lemon)/$(bin) -# $(CC) $(CF) -o $@ $< - -$(c_objs): $(build)/%.o: $(src)/%.c $(all_h) - # c_objs rule - @$(mkdir) $(build) - $(CC) $(CF) -c -o $@ $< - -$(c_other_objs): $(build)/%.o: $(build)/%.c $(all_h) - # c_other_objs rule - $(CC) $(CF) -c -o $@ $< - -$(test_c_objs): $(build)/$(test)/%.o: $(test)/%.c $(all_h) - # test_c_objs rule - @$(mkdir) $(build) - @$(mkdir) $(build)/$(test) - $(CC) $(CF) -c -o $@ $< - -# -8 made my file 32767 lines or longer - -$(c_re_builds): $(build)/%.c: $(src)/%.re.c - # *.re.c build rule - @$(mkdir) $(build) - $(re2c) -W -T -o $@ $< - -$(c_re_test_builds): $(build)/$(test)/%.c: $(test)/%.re.c - # *.re.c tests rule - @$(mkdir) $(build) - @$(mkdir) $(build)/$(test) - $(re2c) -W -T -o $@ $< - -$(c_rec_builds): $(build)/%.c: $(src)/%.re_c.c - # *.re_c.c (conditions) build rule - @$(mkdir) $(build) - $(re2c) -W -T -c -o $@ $< - -$(c_rec_test_builds): $(build)/$(test)/%.c: $(test)/%.re_c.c - # *.re_c.c (conditions) tests rule - @$(mkdir) $(build) - @$(mkdir) $(build)/$(test) - $(re2c) -W -T -c -o $@ $< - -$(c_y_builds): $(build)/%.c: $(src)/%.y # $(lemon)/$(bin)/$(lem) - # .y rule - @$(mkdir) $(build) - $(bison) -o $@ $< - -$(c_gperf_builds): $(build)/%.c: $(src)/%.gperf.c - # *.gperf.c build rule - @$(mkdir) $(build) - $(gperf) $@ --output-file $< - -$(html_docs): $(doc)/%.html: $(src)/%.c $(src)/%.h - # docs rule - @$(mkdir) $(doc) - cat $^ | $(cdoc) > $@ - -###### -# phoney targets - -.PHONY: setup clean backup icon install uninstall test docs release - -clean: - -rm -f $(c_objs) $(test_c_objs) $(c_other_objs) $(c_re_builds) \ -$(c_rec_builds) $(html_docs) - -rm -rf $(bin)/$(test) - -backup: - @$(mkdir) $(backup) - $(zip) $(backup)/$(project)-`date +%Y-%m-%dT%H%M%S`$(BRGS).zip \ -readme.txt Makefile $(all_h) $(all_srcs) $(all_tests) $(all_icons) - -icon: default - # . . . setting icon on a Mac. - cp $(media)/$(icon) $(bin)/$(icon) - -sips --addIcon $(bin)/$(icon) - -DeRez -only icns $(bin)/$(icon) > $(bin)/$(RSRC) - -Rez -append $(bin)/$(RSRC) -o $(bin)/$(project) - -SetFile -a C $(bin)/$(project) - -setup: default icon - @$(mkdir) $(bin)/$(install) - cp $(bin)/$(project) readme.txt $(bin)/$(install) - rm -f $(bin)/$(install)-MacOSX.dmg - # or rm -f $(BDIR)/$(INST)-Win32.zip - hdiutil create $(bin)/$(install)-MacOSX.dmg -volname "$(project)" -srcfolder $(bin)/$(install) - # or zip $(BDIR)/$(INST)-Win32.zip -r $(BDIR)/$(INST) - rm -R $(bin)/$(install) - -# this needs work -release: clean default - strip $(bin)/$(project) - # define NDEBUG - -install: release - @$(mkdir) -p $(DESTDIR)$(PREFIX)/bin - cp $(bin)/$(project) $(DESTDIR)$(PREFIX)/bin/$(project) - -uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/$(project) - -docs: $(html_docs) diff --git a/kjv-code/src/array.h b/kjv-code/src/array.h deleted file mode 100644 index 2b0b23d..0000000 --- a/kjv-code/src/array.h +++ /dev/null @@ -1,430 +0,0 @@ -/** @license 2016 Neil Edelman, distributed under the terms of the - [MIT License](https://opensource.org/licenses/MIT). - - @abstract Stand-alone header ; examples ; on a - compatible workstation, `make` creates the test suite of the examples. - - @subtitle Contiguous dynamic array - - ![Example of array.](../doc/array.png) - - array> is a dynamic array that stores contiguous type>. - Resizing may be necessary when increasing the size of the array; this incurs - amortised cost, and any pointers to this memory may become stale. - - @param[ARRAY_NAME, ARRAY_TYPE] - `` that satisfies `C` naming conventions when mangled and a valid tag-type, - type>, associated therewith; required. `` is private, whose - names are prefixed in a manner to avoid collisions. - - @param[ARRAY_COMPARE, ARRAY_IS_EQUAL] - Compare `` trait contained in . Requires - `[]compare` to be declared as compare_fn> or - `[]is_equal` to be declared as bipredicate_fn>, - respectfully, (but not both.) - - @param[ARRAY_TO_STRING] - To string `` trait contained in . Requires - `[]to_string` be declared as to_string_fn>. - - @param[ARRAY_EXPECT_TRAIT, ARRAY_TRAIT] - Named traits are obtained by including `array.h` multiple times with - `ARRAY_EXPECT_TRAIT` and then subsequently including the name in - `ARRAY_TRAIT`. - - @std C89 */ - -#if !defined(ARRAY_NAME) || !defined(ARRAY_TYPE) -#error Name or tag type undefined. -#endif -#if defined(ARRAY_TRAIT) ^ defined(BOX_TYPE) -#error ARRAY_TRAIT name must come after ARRAY_EXPECT_TRAIT. -#endif -#if defined(ARRAY_COMPARE) && defined(ARRAY_IS_EQUAL) -#error Only one can be defined at a time. -#endif -#if defined(ARRAY_TEST) && (!defined(ARRAY_TRAIT) && !defined(ARRAY_TO_STRING) \ - || defined(ARRAY_TRAIT) && !defined(ARRAY_HAS_TO_STRING)) -#error Test requires to string. -#endif - -#ifndef ARRAY_H /* */ - -#if !defined(restrict) && (!defined(__STDC__) || !defined(__STDC_VERSION__) \ - || __STDC_VERSION__ < 199901L) -#define ARRAY_RESTRICT /* Undo this at the end. */ -#define restrict /* Attribute only in C99+. */ -#endif - - -#ifndef ARRAY_TRAIT /* */ - -/** A valid tag type set by `ARRAY_TYPE`. */ -typedef ARRAY_TYPE PA_(type); - -/** Manages the array field `data` which has `size` elements. The space is - indexed up to `capacity`, which is at least `size`. The fields should be - treated as read-only; any modification is liable to cause the array to go into - an invalid state. - - ![States.](../doc/states.png) */ -struct A_(array) { PA_(type) *data; size_t size, capacity; }; -/* !data -> !size, data -> capacity >= min && size <= capacity <= max */ - -/** Returns null. */ -static PA_(type) *PA_(null)(void) { return 0; } -/** Is `x` not null? @implements `is_element` */ -static int PA_(is_element)(const PA_(type) *const x) { return !!x; } -/* @implements `iterator` */ -struct PA_(iterator) { struct A_(array) *a; size_t i; int seen; }; -/** @return A pointer to null in `a`. @implements `iterator` */ -static struct PA_(iterator) PA_(iterator)(struct A_(array) *const a) { - struct PA_(iterator) it; it.a = a, it.i = 0, it.seen = 0; - return it; -} -/** Move to next `it`. @return Element or null on end. @implements `next` */ -static PA_(type) *PA_(next)(struct PA_(iterator) *const it) { - size_t i; - assert(it); - if(!it->a || (i = it->i + !!it->seen) >= it->a->size) - { *it = PA_(iterator)(it->a); return 0; } - return it->a->data + (it->seen = 1, it->i = i); -} -/** Move to previous `it`. @return Element or null on end. - @implements `previous` */ -static PA_(type) *PA_(previous)(struct PA_(iterator) *const it) { - size_t i, size; - assert(it); - if(!it->a || !(size = it->a->size)) goto reset; - if(i = it->i) { - if(i > size) i = size; - i--; - } else { - if(!it->seen) i = it->a->size - 1; - else goto reset; - } - return it->a->data + (it->seen = 1, it->i = i); -reset: - *it = PA_(iterator)(it->a); - return 0; -} -/** Removes the element last returned by `it`. (Untested. Unused.) - @return There was an element. @order \O(`a.size`). @implements `remove` */ -static int PA_(remove)(struct PA_(iterator) *const it) { - assert(0 && 1); - if(!it->a || !it->seen || it->a->size <= it->i) return 0; - memmove(it->a->data + it->i, it->a->data + it->i + 1, - sizeof *it->a->data * (--it->a->size - it->i)); - return 1; -} -/** @return Iterator at element `idx` of `a`. - @implements `iterator_at` */ -static struct PA_(iterator) PA_(iterator_at)(struct A_(array) *a, size_t idx) - { struct PA_(iterator) it; it.a = a, it.i = idx, it.seen = 0; return it; } -/** Size of `a`. @implements `size` */ -static size_t PA_(size)(const struct A_(array) *a) { return a ? a->size : 0; } -/** @return Element `idx` of `a`. @implements `at` */ -static PA_(type) *PA_(at)(const struct A_(array) *a, const size_t idx) - { return a->data + idx; } -/** Writes `size` to `a`. @implements `tell_size` */ -static void PA_(tell_size)(struct A_(array) *a, const size_t size) - { assert(a); a->size = size; } - -/** May become invalid after a topological change to any items previous. */ -struct A_(array_iterator); -struct A_(array_iterator) { struct PA_(iterator) _; }; - -/** Zeroed data (not all-bits-zero) is initialized. - @return An idle array. @order \Theta(1) @allow */ -static struct A_(array) A_(array)(void) - { struct A_(array) a; a.data = 0, a.capacity = a.size = 0; return a; } - -/** If `a` is not null, destroys and returns it to idle. @allow */ -static void A_(array_)(struct A_(array) *const a) - { if(a) free(a->data), *a = A_(array)(); } - -/** @return An iterator of `a`. */ -static struct A_(array_iterator) A_(array_iterator)(struct A_(array) *a) - { struct A_(array_iterator) it; it._ = PA_(iterator)(a); return it; } -/** @return An iterator at `idx` of `a`. */ -static struct A_(array_iterator) A_(array_iterator_at)(struct A_(array) *a, - size_t idx) { struct A_(array_iterator) it; - it._ = PA_(iterator_at)(a, idx); return it; } -/** @return `it` next element. */ -static PA_(type) *A_(array_next)(struct A_(array_iterator) *const it) - { return assert(it), PA_(next)(&it->_); } -/** @return `it` previous element. */ -static PA_(type) *A_(array_previous)(struct A_(array_iterator) *const it) - { return assert(it), PA_(previous)(&it->_); } - -/** Ensures `min` capacity of `a`. Invalidates pointers in `a`. @param[min] If - zero, does nothing. @return Success; otherwise, `errno` will be set. - @throws[ERANGE] Tried allocating more then can fit in `size_t` or `realloc` - doesn't follow POSIX. @throws[realloc] @allow */ -static int A_(array_reserve)(struct A_(array) *const a, const size_t min) { - size_t c0; - PA_(type) *data; - const size_t max_size = (size_t)~0 / sizeof *a->data; - assert(a); - if(a->data) { - assert(a->size <= a->capacity); - if(min <= a->capacity) return 1; - c0 = a->capacity < ARRAY_MIN_CAPACITY - ? ARRAY_MIN_CAPACITY : a->capacity; - } else { /* Idle. */ - assert(!a->size && !a->capacity); - if(!min) return 1; - c0 = ARRAY_MIN_CAPACITY; - } - if(min > max_size) return errno = ERANGE, 0; - /* `c_n = a1.625^n`, approximation golden ratio `\phi ~ 1.618`. */ - while(c0 < min) { /* \O(\log min), in practice, negligible. */ - size_t c1 = c0 + (c0 >> 1) + (c0 >> 3); - if(c0 >= c1) { c0 = max_size; break; } /* Unlikely. */ - c0 = c1; - } - if(!(data = realloc(a->data, sizeof *a->data * c0))) - { if(!errno) errno = ERANGE; return 0; } - a->data = data, a->capacity = c0; - return 1; -} - -/** The capacity of `a` will be increased to at least `n` elements beyond the - size. Invalidates any pointers in `a`. - @return The start of the buffered space at the back of the array. If `a` is - idle and `buffer` is zero, a null pointer is returned, otherwise null - indicates an error. @throws[realloc] @allow */ -static PA_(type) *A_(array_buffer)(struct A_(array) *const a, const size_t n) { - assert(a); - if(a->size > (size_t)~0 - n) { errno = ERANGE; return 0; } - return A_(array_reserve)(a, a->size + n) && a->data ? a->data + a->size : 0; -} - -/** Appends `n` contiguous items on the back of `a`. - @implements `append` from `BOX_CONTIGUOUS` */ -static PA_(type) *PA_(append)(struct A_(array) *const a, const size_t n) { - PA_(type) *b; - if(!(b = A_(array_buffer)(a, n))) return 0; - assert(n <= a->capacity && a->size <= a->capacity - n); - return a->size += n, b; -} - -/** Adds `n` un-initialised elements at position `at` in `a`. It will - invalidate any pointers in `a` if the buffer holds too few elements. - @param[at] A number smaller than or equal to `a.size`; if `a.size`, this - function behaves as array_append>. - @return A pointer to the start of the new region, where there are `n` - elements. @throws[realloc, ERANGE] @allow */ -static PA_(type) *A_(array_insert)(struct A_(array) *const a, - const size_t n, const size_t at) { - /* Investigate `n` is better than `element`; all the other are element. But - also, when would I ever use this? */ - const size_t old_size = a->size; - PA_(type) *const b = PA_(append)(a, n); - assert(a && at <= old_size); - if(!b) return 0; - memmove(a->data + at + n, a->data + at, sizeof *a->data * (old_size - at)); - return a->data + at; -} - -/** @return Adds (push back) one new element of `a`. The buffer space holds at - least one element, or it may invalidate pointers in `a`. - @order amortised \O(1) @throws[realloc, ERANGE] @allow */ -static PA_(type) *A_(array_new)(struct A_(array) *const a) - { return PA_(append)(a, 1); } - -/** Shrinks the capacity `a` to the size, freeing unused memory. If the size is - zero, it will be in an idle state. Invalidates pointers in `a`. - @return Success. @throws[ERANGE, realloc] (Unlikely) `realloc` error. */ -static int A_(array_shrink)(struct A_(array) *const a) { - PA_(type) *data; - size_t c; - assert(a && a->capacity >= a->size); - if(!a->data) return assert(!a->size && !a->capacity), 1; - c = a->size && a->size > ARRAY_MIN_CAPACITY ? a->size : ARRAY_MIN_CAPACITY; - if(!(data = realloc(a->data, sizeof *a->data * c))) - { if(!errno) errno = ERANGE; return 0; } - a->data = data, a->capacity = c; - return 1; -} - -/** Removes `element` from `a`. Do not attempt to remove an element that is not - in `a`. @order \O(`a.size`). @allow */ -static void A_(array_remove)(struct A_(array) *const a, - PA_(type) *const element) { - const size_t n = (size_t)(element - a->data); - assert(a && element && element >= a->data && element < a->data + a->size); - memmove(element, element + 1, sizeof *element * (--a->size - n)); -} - -/** Removes `datum` from `a` and replaces it with the tail. Do not attempt to - remove an element that is not in `a`. @order \O(1). @allow */ -static void A_(array_lazy_remove)(struct A_(array) *const a, - PA_(type) *const datum) { - size_t n = (size_t)(datum - a->data); - assert(a && datum && datum >= a->data && datum < a->data + a->size); - if(--a->size != n) memcpy(datum, a->data + a->size, sizeof *datum); -} - -/** Sets `a` to be empty. That is, the size of `a` will be zero, but if it was - previously in an active non-idle state, it continues to be. - @order \Theta(1) @allow */ -static void A_(array_clear)(struct A_(array) *const a) - { assert(a), a->size = 0; } - -/** @return The last element or null if `a` is empty. @order \Theta(1) @allow */ -static PA_(type) *A_(array_peek)(const struct A_(array) *const a) - { return assert(a), a->size ? a->data + a->size - 1 : 0; } - -/** @return Value from the the top of `a` that is removed or null if the array - is empty. @order \Theta(1) @allow */ -static PA_(type) *A_(array_pop)(struct A_(array) *const a) - { return assert(a), a->size ? a->data + --a->size : 0; } - -/** Adds `n` elements to the back of `a`. It will invalidate pointers in `a` if - `n` is greater than the buffer space. - @return A pointer to the elements. If `a` is idle and `n` is zero, a null - pointer will be returned, otherwise null indicates an error. - @throws[realloc, ERANGE] @allow */ -static PA_(type) *A_(array_append)(struct A_(array) *const a, const size_t n) - { return assert(a), PA_(append)(a, n); } - -/** Indices [`i0`, `i1`) of `a` will be replaced with a copy of `b`. - @param[b] Can be null, which acts as empty, but cannot overlap with `a`. - @return Success. @throws[realloc, ERANGE] @allow */ -static int A_(array_splice)(struct A_(array) *restrict const a, - const struct A_(array) *restrict const b, - const size_t i0, const size_t i1) { - const size_t a_range = i1 - i0, b_range = b ? b->size : 0; - assert(a && a != b && i0 <= i1 && i1 <= a->size); - if(a_range < b_range) { /* The output is bigger. */ - const size_t diff = b_range - a_range; - if(!A_(array_buffer)(a, diff)) return 0; - memmove(a->data + i1 + diff, a->data + i1, - (a->size - i1) * sizeof *a->data); - a->size += diff; - } else if(b_range < a_range) { /* The output is smaller. */ - memmove(a->data + i0 + b_range, a->data + i1, - (a->size - i1) * sizeof *a->data); - a->size -= a_range - b_range; - } - if(b) memcpy(a->data + i0, b->data, b->size * sizeof *a->data); - return 1; -} - -/* Box override information. */ -#define BOX_TYPE struct A_(array) -#define BOX_CONTENT PA_(type) * -#define BOX_ PA_ -#define BOX_MAJOR_NAME array -#define BOX_MINOR_NAME ARRAY_NAME -#define BOX_ACCESS -#define BOX_CONTIGUOUS - -#ifdef HAVE_ITERATE_H /* */ - -static void PA_(unused_base_coda)(void); -static void PA_(unused_base)(void) { - PA_(null)(); PA_(is_element)(0); PA_(remove)(0); PA_(size)(0); - PA_(at)(0, 0); PA_(tell_size)(0, 0); - A_(array)(); A_(array_)(0); - A_(array_iterator)(0); A_(array_iterator_at)(0, 0); - A_(array_previous)(0); A_(array_next)(0); A_(array_previous)(0); - A_(array_insert)(0, 0, 0); A_(array_new)(0); - A_(array_shrink)(0); A_(array_remove)(0, 0); A_(array_lazy_remove)(0, 0); - A_(array_clear)(0); A_(array_peek)(0); A_(array_pop)(0); - A_(array_append)(0, 0); A_(array_splice)(0, 0, 0, 0); - PA_(unused_base_coda)(); -} -static void PA_(unused_base_coda)(void) { PA_(unused_base)(); } - -#endif /* base code --> */ - - -#ifdef ARRAY_TRAIT /* <-- trait: Will be different on different includes. */ -#define BOX_TRAIT_NAME ARRAY_TRAIT -#endif /* trait --> */ - - -#ifdef ARRAY_TO_STRING /* */ - - -#if defined(ARRAY_TEST) && !defined(ARRAY_TRAIT) /* */ - - -#if defined(ARRAY_COMPARE) || defined(ARRAY_IS_EQUAL) /* */ -#include "compare.h" /** \include */ -#ifdef ARRAY_TEST /* */ -#undef CMP_ /* From . */ -#undef CMPEXTERN_ -#ifdef ARRAY_COMPARE -#undef ARRAY_COMPARE -#else -#undef ARRAY_IS_EQUAL -#endif -#endif /* compare trait --> */ - - -#ifdef ARRAY_EXPECT_TRAIT /* */ -#ifdef ARRAY_TRAIT -#undef ARRAY_TRAIT -#undef BOX_TRAIT_NAME -#endif -#ifdef ARRAY_RESTRICT -#undef ARRAY_RESTRICT -#undef restrict -#endif diff --git a/kjv-code/src/kjv.re_c.c b/kjv-code/src/kjv.re_c.c deleted file mode 100644 index be6c0a6..0000000 --- a/kjv-code/src/kjv.re_c.c +++ /dev/null @@ -1,369 +0,0 @@ -/** @license 2022 Neil Edelman, distributed under the terms of the - [MIT License](https://opensource.org/licenses/MIT). - Is intended to use - . - @std C13 */ - -#include -#include -#include -#include -#include /* opendir readdir closedir */ -#include /* chdir (POSIX) (because I'm lazy) */ - - -/* Dynamic contiguous string that is used to load files. */ - -#define ARRAY_NAME char -#define ARRAY_TYPE char -#include "../src/array.h" - -/** Append a text file, `fn`, to `c`, and add a '\0'. - @return The start of the appended file or null on error. A partial read is a - failure. @throws[fopen, fread, malloc] - @throws[EISEQ] The text file has embedded nulls. - @throws[ERANGE] If the standard library does not follow POSIX. */ -static char *append_file(struct char_array *text, const char *const fn) { - FILE *fp = 0; - const size_t granularity = 1024; - size_t nread, start; - char *cursor; - int success = 1; - assert(text && fn); - start = text->size; - if(!(fp = fopen(fn, "r"))) goto catch; - /* Read entire file in chunks. */ - do if(!(cursor = char_array_buffer(text, granularity)) - || (nread = fread(cursor, 1, granularity, fp), ferror(fp)) - || !char_array_append(text, nread)) goto catch; - while(nread == granularity); - /* File to `C` string. */ - if(!(cursor = char_array_new(text))) goto catch; - *cursor = '\0'; - /* Binary files with embedded '\0' are not allowed; check just this read. */ - if(strchr(text->data + start, '\0') != cursor) - { errno = EILSEQ; goto catch; } - goto finally; -catch: - if(!errno) errno = EILSEQ; /* Will never be true on POSIX. */ - success = 0; -finally: - if(fp) fclose(fp); - return success ? text->data + start : 0; -} - - -/** Helper to parse unsigned; [`s`,`e`) => `n`. */ -static int parse_natural(const char *s, const char *const e, unsigned *const n) { - unsigned accum = 0; - while(s < e) { - unsigned next = accum * 10 + (unsigned)(*s - '0'); - if(accum >= next) return errno = ERANGE, 0; - accum = next; - s++; - } - *n = accum; - return 1; -} - - -/* Enumerate books. */ - -#define BOOKS \ - X(Genesis),\ - X(Exodus),\ - X(Leviticus),\ - X(Numbers),\ - X(Deuteronomy),\ - X(Joshua),\ - X(Judges),\ - X(Ruth),\ - X(ISamuel),\ - X(IISamuel),\ - X(IKings),\ - X(IIKings),\ - X(IChronicles),\ - X(IIChronicles),\ - X(Ezra),\ - X(Nehemiah),\ - X(Esther),\ - X(Job),\ - X(Psalms),\ - X(Proverbs),\ - X(Ecclesiastes),\ - X(Song_of_Solomon),\ - X(Isaiah),\ - X(Jeremiah),\ - X(Lamentations),\ - X(Ezekiel),\ - X(Daniel),\ - X(Hosea),\ - X(Joel),\ - X(Amos),\ - X(Obadiah),\ - X(Jonah),\ - X(Micah),\ - X(Nahum),\ - X(Habakkuk),\ - X(Zephaniah),\ - X(Haggai),\ - X(Zechariah),\ - X(Malachi),\ - \ - X(Matthew),\ - X(Mark),\ - X(Luke),\ - X(John),\ - X(Acts),\ - X(Romans),\ - X(ICorinthians),\ - X(IICorinthians),\ - X(Galatians),\ - X(Ephesians),\ - X(Philippians),\ - X(Colossians),\ - X(IThessalonians),\ - X(IIThessalonians),\ - X(ITimothy),\ - X(IITimothy),\ - X(Titus),\ - X(Philemon),\ - X(Hebrews),\ - X(James),\ - X(IPeter),\ - X(IIPeter),\ - X(IJohn),\ - X(IIJohn),\ - X(IIIJohn),\ - X(Jude),\ - X(Revelation),\ - X(KJV_BOOK_SIZE) - -#define X(book) book -enum kjv_book { BOOKS }; -#undef X -#define X(book) #book -static const char *kjv_book_string[] = { BOOKS }; -#undef X -#undef BOOKS - - -/* Parse filename of books. This works with - */ - -/*!re2c /**/ -re2c:yyfill:enable = 0; -re2c:define:YYCTYPE = char; -natural = [1-9][0-9]*; -whitespace = [ \t\v\f]; -word = [^ \t\v\f\n\x00]+; -*/ - -/** `fn` contains "[*].txt", sticks that in `book_no`, otherwise - returns false. */ -static int kjv_filename(const char *fn, unsigned *const book_no) { - const char *YYCURSOR = fn, *YYMARKER, *yyt1, *yyt2, *s0, *s1; - assert(fn && book_no); - /*!re2c /**/ - * - { return 0; } - @s0 natural @s1 [^.\x00]* ".txt" "\x00" - { return parse_natural(s0, s1, book_no); } - */ -} - - -/* Parse book contents. */ - -struct lex { - size_t line; - const char *cursor; - int error; - unsigned chapter, verse, words; -}; - -static struct lex lex(const char *cursor) { - struct lex lex; - assert(cursor); - lex.line = 1; - lex.cursor = cursor; - lex.error = 0; - lex.chapter = lex.verse = lex.words = 0; - return lex; -} - -/*!conditions:re2c*/ - -static int lex_next_verse(struct lex *const lex) { - const char *YYMARKER, *yyt1 = 0, *yyt2 = 0, *s0, *s1, *t0, *t1; - enum YYCONDTYPE condition = yycline; - /*!re2c /**/ - re2c:define:YYCURSOR = lex->cursor; - re2c:define:YYGETCONDITION = "condition"; - re2c:define:YYSETCONDITION = "condition = @@;"; - re2c:define:YYGETCONDITION:naked = 1; - re2c:define:YYSETCONDITION:naked = 1; */ - assert(lex && lex->cursor); - lex->error = 0; -scan: - /*!re2c /**/ - <*> * { return errno = EILSEQ, lex->error = 1, 0; } - [^[\]\n\x00]* "\n" { lex->line++; goto scan; } - "\x00" { return 0; } - "[" @s0 natural @s1 ":" @t0 natural @t1 "]" => verse { - if(!parse_natural(s0, s1, &lex->chapter) - || !parse_natural(t0, t1, &lex->verse)) - return errno = EILSEQ, lex->error = 1, 0; - lex->words = 0; - /*printf("%u:%u", lex->chapter, lex->verse);*/ - goto scan; - } - whitespace+ { goto scan; } - @s0 word @s1 { lex->words++; goto scan; } - "\n" { /*printf(" -> %u\n", lex->words);*/ lex->line++; return 1; } - */ -} - - -/* Reversible hash map to store data on bible. */ - -#include - -/** - on `x`. */ -static uint32_t lowbias32(uint32_t x) { - x ^= x >> 16; - x *= 0x7feb352dU; - x ^= x >> 15; - x *= 0x846ca68bU; - x ^= x >> 16; - return x; -} -/* Inverts `x`. */ -static uint32_t lowbias32_r(uint32_t x) { - x ^= x >> 16; - x *= 0x43021123U; - x ^= x >> 15 ^ x >> 30; - x *= 0x1d69e2a5U; - x ^= x >> 16; - return x; -} - -/** Two hash-tables use the same structure. */ -union kjvcite { - /* Overkill, but no initializing unused bits, 12 + 13 + 7 = 32. */ - struct { unsigned verse : 12, chapter : 13, book : 7; }; - uint32_t u32; -}; -static uint32_t kjv_hash(const union kjvcite x) { return lowbias32(x.u32); } -static union kjvcite kjv_unhash(const uint32_t x) { - union kjvcite k; - k.u32 = lowbias32_r(x); - return k; -} -static void kjv_to_string(const union kjvcite x, char (*const a)[12]) - { sprintf(*a, "%.4s%u:%u", kjv_book_string[x.book], - (x.chapter + 1) % 1000, (x.verse + 1) % 1000); } - -/** Derived information on verse word count. */ -static uint32_t verse_hash(const union kjvcite x) { return kjv_hash(x); } -static union kjvcite verse_unhash(const uint32_t x) { return kjv_unhash(x); } -static void verse_to_string(const union kjvcite x, char (*const a)[12]) - { kjv_to_string(x, a); } -#define TABLE_NAME verse -#define TABLE_KEY union kjvcite -#define TABLE_UINT uint32_t -#define TABLE_VALUE unsigned -#define TABLE_INVERSE -#define TABLE_DEFAULT 0 -#define TABLE_TO_STRING -#include "../src/table.h" - -/* A set of verses. */ -static uint32_t kjvset_hash(const union kjvcite x) { return kjv_hash(x); } -static union kjvcite kjvset_unhash(const uint32_t x) { return kjv_unhash(x); } -static void kjvset_to_string(const union kjvcite x, char (*const a)[12]) - { kjv_to_string(x, a); } -#define TABLE_NAME kjvset -#define TABLE_KEY union kjvcite -#define TABLE_UINT uint32_t -#define TABLE_INVERSE -#define TABLE_TO_STRING -#include "../src/table.h" - -int main(void) { - const char *const dir_kjv = "KJV"; - struct { - struct char_array backing; - struct verse_table verses; - size_t words; - } kjv = { 0 }; - DIR *dir = 0; - struct dirent *de = 0; - struct { size_t offset; int is; } build[KJV_BOOK_SIZE] = { 0 }; - enum kjv_book b = 0; - int success = EXIT_SUCCESS, attempted_closedir = 0; - errno = 0; - - /* For all files in directory KJV with <#>*.txt, read into backing. */ - if(chdir(dir_kjv) == -1 || !(dir = opendir("."))) goto catch; - while((de = readdir(dir))) { - unsigned ordinal; - char *unstable_book; - if(!kjv_filename(de->d_name, &ordinal)) continue; /* Extract no. */ - /*fprintf(stderr, "<%s> ordinal: %u\n", de->d_name, ordinal);*/ - if(ordinal < 1 || ordinal > KJV_BOOK_SIZE) - { errno = ERANGE; goto catch; } /* Not in range. */ - if(build[b = ordinal - 1].is) /* Convert to zero-based. */ - { errno = EDOM; goto catch; } /* Is duplicate. */ - if(!(unstable_book = append_file(&kjv.backing, de->d_name))) goto catch; - build[b].is = 1; - build[b].offset = (size_t)(unstable_book - kjv.backing.data); - } - if(attempted_closedir = 1, closedir(dir) == -1) goto catch; dir = 0; - - /* Now backing is stable; count all the words for each verse. */ - for(b = 0; b < KJV_BOOK_SIZE; b++) { - struct lex x; - if(!build[b].is) { fprintf(stderr, "Missing book [%u]%s.\n", - b + 1, kjv_book_string[b]); errno = EDOM; goto catch; } - x = lex(kjv.backing.data + build[b].offset); - while(lex_next_verse(&x)) { - const union kjvcite cite - = { .book = b, .chapter = x.chapter, .verse = x.verse }; - unsigned *words; - switch(verse_table_assign(&kjv.verses, cite, &words)) { - case TABLE_PRESENT: fprintf(stderr, "[%u]%s %u:%u duplicated.\n", - b + 1, kjv_book_string[b], x.chapter, x.verse); errno = EDOM; - case TABLE_ERROR: goto catch; - case TABLE_ABSENT: break; - } - *words = x.words, kjv.words += x.words; - } - if(x.error) { fprintf(stderr, "[%u]%s on line %zu\n", - b + 1, kjv_book_string[b], x.line); goto catch; } - } - - printf("words: %s\n", verse_table_to_string(&kjv.verses)); - printf("kjv: %zu total words\n", kjv.words); - { - union kjvcite c; - struct verse_table_iterator it = verse_table_begin(&kjv.verses); - unsigned *w; - while(verse_table_next(&it, &c, &w)) - printf("%s %u:%u -> %u\n", - kjv_book_string[c.book], c.chapter, c.verse, *w); - c = (union kjvcite){ .book = Genesis, .chapter = 1, .verse = 1 }; - printf("1:1:1 -> %u\n", verse_table_get(&kjv.verses, c)); - } - goto finally; -catch: - success = EXIT_FAILURE; - if(de) fprintf(stderr, "While reading %s.\n", de->d_name); - perror(de ? de->d_name : dir_kjv); - if(dir && !attempted_closedir && closedir(dir) == -1) perror(dir_kjv); -finally: - verse_table_(&kjv.verses); - char_array_(&kjv.backing); - return success; -} diff --git a/kjv-code/src/table.h b/kjv-code/src/table.h deleted file mode 100644 index 4673ea1..0000000 --- a/kjv-code/src/table.h +++ /dev/null @@ -1,934 +0,0 @@ -/** @license 2019 Neil Edelman, distributed under the terms of the - [MIT License](https://opensource.org/licenses/MIT). - - @abstract Stand-alone header ; examples ; - article . On a compatible workstation, `make` creates the - test suite of the examples. - - @subtitle Hash table - - ![Example of table.](../doc/table.png) - - table> implements a set or map of entry> as a hash table. - It must be supplied hash_fn> `hash` and, - is_equal_fn> `is_equal` or unhash_fn> `unhash`. - - (Fixme: remove entry as public struct, this should be entirely private.) - - @param[TABLE_NAME, TABLE_KEY] - `` that satisfies `C` naming conventions when mangled and a valid - key> associated therewith; required. `` is private, whose - names are prefixed in a manner to avoid collisions. - - @param[TABLE_INVERSE] - By default it assumes that `is_equal` is supplied; with this, instead - requires `unhash` satisfying unhash_fn>. - - @param[TABLE_VALUE] - An optional type that is the payload of the key, thus making this a map or - associative array. - - @param[TABLE_UINT] - This is uint>, the unsigned type of hash hash of the key given by - hash_fn>; defaults to `size_t`. - - @param[TABLE_DEFAULT] - Default trait; a value> used in tableget>. - - @param[TABLE_TO_STRING] - To string trait `` contained in . Require - `[]to_string` be declared as to_string_fn>. - - @param[TABLE_EXPECT_TRAIT, TABLE_TRAIT] - Named traits are obtained by including `table.h` multiple times with - `TABLE_EXPECT_TRAIT` and then subsequently including the name in - `TABLE_TRAIT`. - - @std C89 */ - -#if !defined(TABLE_NAME) || !defined(TABLE_KEY) -#error Name TABLE_NAME or tag type TABLE_KEY undefined. -#endif -#if defined(TABLE_TRAIT) ^ defined(BOX_TYPE) -#error TABLE_TRAIT name must come after TABLE_EXPECT_TRAIT. -#endif -#if defined(TABLE_TEST) && (!defined(TABLE_TRAIT) && !defined(TABLE_TO_STRING) \ - || defined(TABLE_TRAIT) && !defined(TABLE_HAS_TO_STRING)) -#error Test requires to string. -#endif - -#ifndef TABLE_H /* */ - - -#ifndef TABLE_TRAIT /* */ -#endif /* documentation --> */ - -#ifdef TABLE_VALUE /* */ - -/** @return Key from `e`. */ -static PN_(key) PN_(entry_key)(PN_(entry) e) { -#ifdef TABLE_VALUE - return e.key; -#else - return e; -#endif -} - -/* Address is hash modulo size of table. Any occupied buckets at the head of - the linked structure are closed, that is, the address equals the index. These - form a linked table, possibly with other, open buckets that have the same - address in vacant buckets. */ -struct PN_(bucket) { - PN_(uint) next; /* Bucket index, including `TABLE_NULL` and `TABLE_END`. */ - PN_(uint) hash; -#ifndef TABLE_INVERSE - PN_(key) key; -#endif -#ifdef TABLE_VALUE - PN_(value) value; -#endif -}; - -/** Gets the key of an occupied `bucket`. */ -static PN_(key) PN_(bucket_key)(const struct PN_(bucket) *const bucket) { - assert(bucket && bucket->next != TABLE_NULL); -#ifdef TABLE_INVERSE - /* On `TABLE_INVERSE`, this function must be defined by the user. */ - return N_(unhash)(bucket->hash); -#else - return bucket->key; -#endif -} - -/** Gets the value of an occupied `bucket`, which might be the same as the - key. */ -static PN_(value) PN_(bucket_value)(const struct PN_(bucket) *const bucket) { - assert(bucket && bucket->next != TABLE_NULL); -#ifdef TABLE_VALUE - return bucket->value; -#else - return PN_(bucket_key)(bucket); -#endif -} - -/** Fills `entry` with the information of `bucket`. */ -static PN_(entry) PN_(to_entry)(struct PN_(bucket) *const bucket) { - PN_(entry) e; - assert(bucket); -#ifdef TABLE_VALUE /* entry { key key; value value; } */ - e.key = PN_(bucket_key)(bucket); - e.value = bucket->value; -#else /* entry key */ - e = PN_(bucket_key)(bucket); -#endif - return e; -} - -/** Returns true if the `replace` replaces the `original`. - (Shouldn't it be entry?) */ -typedef int (*PN_(policy_fn))(PN_(key) original, PN_(key) replace); - -/** To initialize, see table>, `TABLE_IDLE`, `{0}` (`C99`,) or being - `static`. The fields should be treated as read-only; any modification is - liable to cause the table to go into an invalid state. - - ![States.](../doc/states.png) */ -struct N_(table) { /* "Padding size," good. */ - struct PN_(bucket) *buckets; /* @ has zero/one key specified by `next`. */ - /* `size <= capacity`; size is not needed but convenient and allows - short-circuiting. Top is an index of the stack, potentially lazy: MSB - stores whether this is a step ahead (which would make it less, the stack - grows from the bottom,) otherwise it is right at the top, */ - PN_(uint) log_capacity, size, top; -}; - -/** The capacity of a non-idle `table` is always a power-of-two. */ -static PN_(uint) PN_(capacity)(const struct N_(table) *const table) - { return assert(table && table->buckets && table->log_capacity >= 3), - (PN_(uint))((PN_(uint))1 << table->log_capacity); } - -/** @return Indexes the first closed bucket in the set of buckets with the same - address from non-idle `table` given the `hash`. If the bucket is empty, it - will have `next = TABLE_NULL` or it's own to_bucket_no> not equal to - the index. */ -static PN_(uint) PN_(to_bucket_no)(const struct N_(table) *const table, - const PN_(uint) hash) { return hash & (PN_(capacity)(table) - 1); } - -/** @return Search for the previous link in the bucket to `b` in `table`, if it - exists, (by restarting and going though the list.) This is not the same as the - iterator. @order \O(`bucket size`) */ -static struct PN_(bucket) *PN_(prev)(const struct N_(table) *const table, - const PN_(uint) b) { - const struct PN_(bucket) *const bucket = table->buckets + b; - PN_(uint) to_next = TABLE_NULL, next; - assert(table && bucket->next != TABLE_NULL); - /* Note that this does not check for corrupted tables; would get assert. */ - for(next = PN_(to_bucket_no)(table, bucket->hash); - /* assert(next < capacity), */ next != b; - to_next = next, next = table->buckets[next].next); - return to_next != TABLE_NULL ? table->buckets + to_next : 0; -} - -/* */ - -/** `TABLE_INVERSE` is injective, so in that case, we only compare hashes. - @return `a` and `b`. */ -static int PN_(equal_buckets)(PN_(key_c) a, PN_(key_c) b) { -#ifdef TABLE_INVERSE - return (void)a, (void)b, 1; -#else - /* Must have this function declared. */ - return N_(is_equal)(a, b); -#endif -} - -/** `table` will be searched linearly for `key` which has `hash`. */ -static struct PN_(bucket) *PN_(query)(struct N_(table) *const table, - PN_(key_c) key, const PN_(uint) hash) { - struct PN_(bucket) *bucket1; - PN_(uint) head, b0 = TABLE_NULL, b1, b2; - assert(table && table->buckets && table->log_capacity); - bucket1 = table->buckets + (head = b1 = PN_(to_bucket_no)(table, hash)); - /* Not the start of a bucket: empty or in the collision stack. */ - if((b2 = bucket1->next) == TABLE_NULL - || PN_(in_stack_range)(table, b1) - && b1 != PN_(to_bucket_no)(table, bucket1->hash)) return 0; - while(hash != bucket1->hash - || !PN_(equal_buckets)(key, PN_(bucket_key)(bucket1))) { - if(b2 == TABLE_END) return 0; - bucket1 = table->buckets + (b0 = b1, b1 = b2); - assert(b1 < PN_(capacity)(table) && PN_(in_stack_range)(table, b1) - && b1 != TABLE_NULL); - b2 = bucket1->next; - } -#ifdef TABLE_DONT_SPLAY /* */ -} - -/** Ensures that `table` has enough buckets to fill `n` more than the size. May - invalidate and re-arrange the order. - @return Success; otherwise, `errno` will be set. @throws[realloc] - @throws[ERANGE] Tried allocating more then can fit in half uint> - or `realloc` doesn't follow [POSIX - ](https://pubs.opengroup.org/onlinepubs/009695399/functions/realloc.html). */ -static int PN_(buffer)(struct N_(table) *const table, const PN_(uint) n) { - struct PN_(bucket) *buckets; - const PN_(uint) log_c0 = table->log_capacity, - c0 = log_c0 ? (PN_(uint))((PN_(uint))1 << log_c0) : 0; - PN_(uint) log_c1, c1, size1, i, wait, mask; - assert(table && table->size <= TABLE_HIGH - && (!table->buckets && !table->size && !log_c0 && !c0 - || table->buckets && table->size <= c0 && log_c0>=3)); - /* Can we satisfy `n` growth from the buffer? */ - if(TABLE_M1 - table->size < n || TABLE_HIGH < (size1 = table->size + n)) - return errno = ERANGE, 0; - if(table->buckets) log_c1 = log_c0, c1 = c0 ? c0 : 1; - else log_c1 = 3, c1 = 8; - while(c1 < size1) log_c1++, c1 <<= 1; - if(log_c0 == log_c1) return 1; - - /* Otherwise, need to allocate more. */ - if(!(buckets = realloc(table->buckets, sizeof *buckets * c1))) - { if(!errno) errno = ERANGE; return 0; } - table->top = (c1 - 1) | TABLE_HIGH; /* No stack. */ - table->buckets = buckets, table->log_capacity = log_c1; - - /* Initialize new values. Mask to identify the added bits. */ - { struct PN_(bucket) *e = buckets + c0, *const e_end = buckets + c1; - for( ; e < e_end; e++) e->next = TABLE_NULL; } - mask = (PN_(uint))((((PN_(uint))1 << log_c0) - 1) - ^ (((PN_(uint))1 << log_c1) - 1)); - - /* Rehash most closed buckets in the lower half. Create waiting - linked-stack by borrowing next. */ - wait = TABLE_END; - for(i = 0; i < c0; i++) { - struct PN_(bucket) *idx, *go; - PN_(uint) g, hash; - idx = table->buckets + i; - if(idx->next == TABLE_NULL) continue; - g = PN_(to_bucket_no)(table, hash = idx->hash); - /* It's a power-of-two size, so, like consistent hashing, `E[old/new]` - capacity that a closed bucket will remain where it is. */ - if(i == g) { idx->next = TABLE_END; continue; } - if((go = table->buckets + g)->next == TABLE_NULL) { - /* Priority is given to the first closed bucket; simpler later. */ - struct PN_(bucket) *head; - PN_(uint) h = g & ~mask; assert(h <= g); - if(h < g && i < h - && (head = table->buckets + h, assert(head->next != TABLE_NULL), - PN_(to_bucket_no)(table, head->hash) == g)) { - memcpy(go, head, sizeof *head); - go->next = TABLE_END, head->next = TABLE_NULL; - /* Fall-though -- the bucket still needs to be put on wait. */ - } else { - /* If the new bucket is available and this bucket is first. */ - memcpy(go, idx, sizeof *idx); - go->next = TABLE_END, idx->next = TABLE_NULL; - continue; - } - } - idx->next = wait, wait = i; /* Push for next sweep. */ - } - - /* Search waiting stack for buckets that moved concurrently. */ - { PN_(uint) prev = TABLE_END, w = wait; while(w != TABLE_END) { - struct PN_(bucket) *waiting = table->buckets + w; - PN_(uint) cl = PN_(to_bucket_no)(table, waiting->hash); - struct PN_(bucket) *const closed = table->buckets + cl; - assert(cl != w); - if(closed->next == TABLE_NULL) { - memcpy(closed, waiting, sizeof *waiting), closed->next = TABLE_END; - if(prev != TABLE_END) table->buckets[prev].next = waiting->next; - if(wait == w) wait = waiting->next; /* First, modify head. */ - w = waiting->next, waiting->next = TABLE_NULL; - } else { - assert(closed->next == TABLE_END); /* Not in the wait stack. */ - prev = w, w = waiting->next; - } - }} - - /* Rebuild the top stack at the high numbers from the waiting at low. */ - while(wait != TABLE_END) { - struct PN_(bucket) *const waiting = table->buckets + wait; - PN_(uint) h = PN_(to_bucket_no)(table, waiting->hash); - struct PN_(bucket) *const head = table->buckets + h; - struct PN_(bucket) *top; - assert(h != wait && head->next != TABLE_NULL); - PN_(grow_stack)(table), top = table->buckets + table->top; - memcpy(top, waiting, sizeof *waiting); - top->next = head->next, head->next = table->top; - wait = waiting->next, waiting->next = TABLE_NULL; /* Pop. */ - } - - return 1; -} - -/** Replace the `key` and `hash` of `bucket`. Don't touch next. */ -static void PN_(replace_key)(struct PN_(bucket) *const bucket, - const PN_(key) key, const PN_(uint) hash) { - (void)key; - bucket->hash = hash; -#ifndef TABLE_INVERSE - bucket->key = key; -#endif -} - -/** Replace the entire `entry` and `hash` of `bucket`. Don't touch next. */ -static void PN_(replace_entry)(struct PN_(bucket) *const bucket, - const PN_(entry) entry, const PN_(uint) hash) { - PN_(replace_key)(bucket, PN_(entry_key)(entry), hash); -#ifdef TABLE_VALUE - bucket->value = entry.value; -#endif -} - -/** Evicts the spot where `hash` goes in `table`. This results in a space in - the table. */ -static struct PN_(bucket) *PN_(evict)(struct N_(table) *const table, - const PN_(uint) hash) { - PN_(uint) i; - struct PN_(bucket) *bucket; - if(!PN_(buffer)(table, 1)) return 0; /* Amortized. */ - bucket = table->buckets + (i = PN_(to_bucket_no)(table, hash));/* Closed. */ - if(bucket->next != TABLE_NULL) { /* Occupied. */ - int in_stack = PN_(to_bucket_no)(table, bucket->hash) != i; - PN_(move_to_top)(table, i); - bucket->next = in_stack ? TABLE_END : table->top; - } else { /* Unoccupied. */ - bucket->next = TABLE_END; - } - table->size++; - return bucket; -} - -/** Put `entry` in `table`. For collisions, only if `policy` exists and returns - true do and displace it to `eject`, if non-null. - @return A . @throws[malloc] - @order Amortized \O(max bucket length); the key to another bucket may have to - be moved to the top; the table might be full and have to be resized. */ -static enum table_result PN_(put)(struct N_(table) *const table, - PN_(entry) entry, PN_(entry) *eject, const PN_(policy_fn) policy) { - struct PN_(bucket) *bucket; - const PN_(key) key = PN_(entry_key)(entry); - /* This function must be defined by the user. */ - const PN_(uint) hash = N_(hash)(key); - enum table_result result; - assert(table); - if(table->buckets && (bucket = PN_(query)(table, key, hash))) { - if(!policy || !policy(PN_(bucket_key)(bucket), key)) - return TABLE_PRESENT; - if(eject) *eject = PN_(to_entry)(bucket); - result = TABLE_PRESENT; - } else { - if(!(bucket = PN_(evict)(table, hash))) return TABLE_ERROR; - result = TABLE_ABSENT; - } - PN_(replace_entry)(bucket, entry, hash); - return result; -} - -/** Is `x` not null? @implements `is_content` */ -static int PN_(is_element)(const struct PN_(bucket) *const x) { return !!x; } -/* In no particular order, usually, but deterministic up to topology changes. - @implements `iterator` */ -struct PN_(iterator) { struct N_(table) *table; PN_(uint) cur, prev; }; -/** Helper to skip the buckets of `it` that are not there. - @return Whether it found another index. */ -static int PN_(skip)(struct PN_(iterator) *const it) { - const struct N_(table) *const t = it->table; - const PN_(uint) limit = PN_(capacity)(t); - assert(it && it->table && it->table->buckets); - while(it->cur < limit) { - struct PN_(bucket) *const bucket = t->buckets + it->cur; - if(bucket->next != TABLE_NULL) return 1; - it->cur++; - } - return 0; -} -/** @return Before `table`. @implements `begin` */ -static struct PN_(iterator) PN_(iterator)(struct N_(table) *const table) { - struct PN_(iterator) it; it.table = table, it.cur = 0; it.prev = TABLE_NULL; - return it; -} -/** Advances `it` to the next element. @return Pointer to the current element - or null. @implements `next` */ -static struct PN_(bucket) *PN_(next)(struct PN_(iterator) *const it) { - assert(it); - if(!it->table || !it->table->buckets) return 0; - if(PN_(skip)(it)) - return it->prev = it->cur, it->table->buckets + it->cur++; - it->table = 0, it->cur = 0; - return 0; -} -/** Removes the entry at `it`. @return Success. */ -static int PN_(remove)(struct PN_(iterator) *const it) { - struct N_(table) *table; - PN_(uint) prev = it->prev; - struct PN_(bucket) *previous = 0, *current; - PN_(uint) prv = TABLE_NULL, crnt; - assert(it); - if(prev == TABLE_NULL) return 0; - table = it->table; - assert(it->table == it->table - && it->table->buckets && prev < PN_(capacity)(it->table)); - /* Egregious code reuse. :[ */ - current = it->table->buckets + prev, assert(current->next != TABLE_NULL); - crnt = PN_(to_bucket_no)(it->table, current->hash); - while(crnt != prev) assert(crnt < PN_(capacity)(it->table)), - crnt = (previous = it->table->buckets + (prv = crnt))->next; - if(prv != TABLE_NULL) { /* Open entry. */ - previous->next = current->next; - } else if(current->next != TABLE_END) { /* Head closed entry and others. */ - const PN_(uint) scnd = current->next; - struct PN_(bucket) *const second = table->buckets + scnd; - assert(scnd < PN_(capacity)(table)); - memcpy(current, second, sizeof *second); - if(crnt < scnd) it->cur = it->prev; /* Iterate new entry. */ - crnt = scnd; current = second; - } - current->next = TABLE_NULL, table->size--, PN_(shrink_stack)(table, crnt); - it->prev = TABLE_NULL; - return 1; -} - -/** ![States](../doc/it.png) - - Adding, deleting, successfully looking up entries, or any modification of the - table's topology invalidates the iterator. - Iteration usually not in any particular order. The asymptotic runtime of - iterating though the whole table is proportional to the capacity. */ -struct N_(table_iterator); -struct N_(table_iterator) { struct PN_(iterator) _; }; - -/** Zeroed data (not all-bits-zero) is initialized. @return An idle array. - @order \Theta(1) @allow */ -static struct N_(table) N_(table)(void) { - struct N_(table) table; - table.buckets = 0; table.log_capacity = 0; table.size = 0; table.top = 0; - return table; -} - -/** If `table` is not null, destroys and returns it to idle. @allow */ -static void N_(table_)(struct N_(table) *const table) - { if(table) free(table->buckets), *table = N_(table)(); } - -/** Loads `table` (can be null) into `it`. @allow */ -static struct N_(table_iterator) N_(table_begin)(struct N_(table) *const - table) { struct N_(table_iterator) it; it._ = PN_(iterator)(table); - return it; } -#ifdef TABLE_VALUE /* */ -/** Removes the entry at `it`. Whereas table_remove> invalidates the - iterator, this corrects for a signal `it`. - @return Success, or there was no entry at the iterator's position, (anymore.) - @allow */ -static int N_(table_iterator_remove)(struct N_(table_iterator) *const it) - { return assert(it), PN_(remove)(&it->_); } - -/** Reserve at least `n` more empty buckets in `table`. This may cause the - capacity to increase and invalidates any pointers to data in the table. - @return Success. - @throws[ERANGE] The request was unsatisfiable. @throws[realloc] @allow */ -static int N_(table_buffer)(struct N_(table) *const table, const PN_(uint) n) - { return assert(table), PN_(buffer)(table, n); } - -/** Clears and removes all buckets from `table`. The capacity and memory of the - `table` is preserved, but all previous values are un-associated. (The load - factor will be less until it reaches it's previous size.) - @order \Theta(`table.capacity`) @allow */ -static void N_(table_clear)(struct N_(table) *const table) { - struct PN_(bucket) *b, *b_end; - assert(table); - if(!table->buckets) { assert(!table->log_capacity); return; } - assert(table->log_capacity); - for(b = table->buckets, b_end = b + PN_(capacity)(table); b < b_end; b++) - b->next = TABLE_NULL; - table->size = 0; - table->top = (PN_(capacity)(table) - 1) | TABLE_HIGH; -} - -/** @return Whether `key` is in `table` (which can be null.) @allow */ -static int N_(table_is)(struct N_(table) *const table, const PN_(key) key) { - /* This function must be defined by the user. */ - return table && table->buckets - ? !!PN_(query)(table, key, N_(hash)(key)) : 0; -} - -/** @param[result] If null, behaves like table_is>, otherwise, a - entry> which gets filled on true. - @return Whether `key` is in `table` (which can be null.) @allow */ -static int N_(table_query)(struct N_(table) *const table, const PN_(key) key, - PN_(entry) *result) { - struct PN_(bucket) *bucket; - /* This function must be defined by the user. */ - if(!table || !table->buckets - || !(bucket = PN_(query)(table, key, N_(hash)(key)))) return 0; - if(result) *result = PN_(to_entry)(bucket); - return 1; -} - -/** @return The value associated with `key` in `table`, (which can be null.) If - no such value exists, `default_value` is returned. - @order Average \O(1); worst \O(n). @allow */ -static PN_(value) N_(table_get_or)(struct N_(table) *const table, - const PN_(key) key, PN_(value) default_value) { - struct PN_(bucket) *bucket; - /* This function must be defined by the user. */ - return table && table->buckets - && (bucket = PN_(query)(table, key, N_(hash)(key))) - ? PN_(bucket_value)(bucket) : default_value; -} - -/** Puts `entry` in `table` only if absent. - @return One of: `TABLE_ERROR`, tried putting the entry in the table but - failed, the table is not modified; `TABLE_PRESENT`, does nothing if there is - another entry with the same key; `TABLE_ABSENT`, put an entry in the table. - @throws[realloc, ERANGE] On `TABLE_ERROR`. - @order Average amortised \O(1); worst \O(n). @allow */ -static enum table_result N_(table_try)(struct N_(table) *const table, - PN_(entry) entry) { return PN_(put)(table, entry, 0, 0); } - -/** Callback in table_update>. - @return `original` and `replace` ignored, true. - @implements policy_fn> */ -static int PN_(always_replace)(const PN_(key) original, - const PN_(key) replace) { return (void)original, (void)replace, 1; } - -/** Puts `entry` in `table`. - @return One of: `TABLE_ERROR`, the table is not modified; `TABLE_ABSENT`, the - `entry` is put if the table; `TABLE_PRESENT` if non-null, `eject` will be - filled with the previous entry. - @throws[realloc, ERANGE] On `TABLE_ERROR`. - @order Average amortised \O(1); worst \O(n). @allow */ -static enum table_result N_(table_update)(struct N_(table) *const table, - PN_(entry) entry, PN_(entry) *eject) { - return PN_(put)(table, entry, eject, &PN_(always_replace)); -} - -/** Puts `entry` in `table` only if absent or if calling `policy` returns true. - @return One of: `TABLE_ERROR`, the table is not modified; `TABLE_ABSENT`, the - `entry` is new; `TABLE_PRESENT`, the entry has the same key as some other - entry. If `policy` returns true, `eject` will be filled; - @throws[realloc, ERANGE] On `TABLE_ERROR`. - @order Average amortised \O(1); worst \O(n). @allow */ -static enum table_result N_(table_policy)(struct N_(table) *const table, - PN_(entry) entry, PN_(entry) *eject, const PN_(policy_fn) policy) - { return PN_(put)(table, entry, eject, policy); } - -#ifdef TABLE_VALUE /* */ - -/** Removes `key` from `table` (which could be null.) - @return Whether that `key` was in `table`. @order Average \O(1), (hash - distributes elements uniformly); worst \O(n). @allow */ -static int N_(table_remove)(struct N_(table) *const table, - const PN_(key) key) { - struct PN_(bucket) *current; - /* This function must be defined by the user. */ - PN_(uint) crnt, prv = TABLE_NULL, nxt, hash = N_(hash)(key); - if(!table || !table->size) return 0; assert(table->buckets); - /* Find item and keep track of previous. */ - current = table->buckets + (crnt = PN_(to_bucket_no)(table, hash)); - if((nxt = current->next) == TABLE_NULL - || PN_(in_stack_range)(table, crnt) - && crnt != PN_(to_bucket_no)(table, current->hash)) return 0; - while(hash != current->hash - && !PN_(equal_buckets)(key, PN_(bucket_key)(current))) { - if(nxt == TABLE_END) return 0; - prv = crnt, current = table->buckets + (crnt = nxt); - assert(crnt < PN_(capacity)(table) && PN_(in_stack_range)(table, crnt) - && crnt != TABLE_NULL); - nxt = current->next; - } - if(prv != TABLE_NULL) { /* Open entry. */ - struct PN_(bucket) *previous = table->buckets + prv; - previous->next = current->next; - } else if(current->next != TABLE_END) { /* Head closed entry and others. */ - struct PN_(bucket) *const second - = table->buckets + (crnt = current->next); - assert(current->next < PN_(capacity)(table)); - memcpy(current, second, sizeof *second); - current = second; - } - current->next = TABLE_NULL, table->size--, PN_(shrink_stack)(table, crnt); - return 1; -} - -/* Box override information. */ -#define BOX_TYPE struct N_(table) -#define BOX_CONTENT struct PN_(bucket) * -#define BOX_ PN_ -#define BOX_MAJOR_NAME table -#define BOX_MINOR_NAME TABLE_NAME - -#ifdef HAVE_ITERATE_H /* */ - -static void PN_(unused_base_coda)(void); -static void PN_(unused_base)(void) { - PN_(entry) e; PN_(key) k; PN_(value) v; - memset(&e, 0, sizeof e); memset(&k, 0, sizeof k); memset(&v, 0, sizeof v); - PN_(is_element)(0); - N_(table)(); N_(table_)(0); N_(table_begin)(0); - N_(table_buffer)(0, 0); N_(table_clear)(0); N_(table_is)(0, k); - N_(table_query)(0, k, 0); N_(table_get_or)(0, k, v); N_(table_try)(0, e); - N_(table_update)(0, e, 0); N_(table_policy)(0,e,0,0); - N_(table_remove)(0, k); N_(table_iterator_remove)(0); -#ifdef TABLE_VALUE - N_(table_next)(0, 0, 0); N_(table_assign)(0, k, 0); -#else - N_(table_next)(0, 0); -#endif - PN_(unused_base_coda)(); -} -static void PN_(unused_base_coda)(void) { PN_(unused_base)(); } - -#endif /* base code --> */ - - -#ifdef TABLE_TRAIT /* <-- trait: Will be different on different includes. */ -#define BOX_TRAIT_NAME TABLE_TRAIT -#endif /* trait --> */ -/* #ifdef TABLE_TRAIT -#define N_D_(n, m) TABLE_CAT(N_(n), TABLE_CAT(TABLE_TRAIT, m)) -#else -#define N_D_(n, m) TABLE_CAT(N_(n), m) -#endif -#define PN_D_(n, m) TABLE_CAT(table, N_D_(n, m)) */ - - -#ifdef TABLE_TO_STRING /* */ - - -#if defined(TABLE_TEST) && !defined(TABLE_TRAIT) /* */ - - -#ifdef TABLE_DEFAULT /* */ - - -#ifdef TABLE_EXPECT_TRAIT /* */ -#ifdef TABLE_TRAIT -#undef TABLE_TRAIT -#undef BOX_TRAIT_NAME -#endif diff --git a/kjv-code/src/to_string.h b/kjv-code/src/to_string.h deleted file mode 100644 index affdc62..0000000 --- a/kjv-code/src/to_string.h +++ /dev/null @@ -1,171 +0,0 @@ -/* @license 2020 Neil Edelman, distributed under the terms of the - [MIT License](https://opensource.org/licenses/MIT). - - @subtitle To string trait - - Interface defined by box. Requires `[_]_to_string` be declared as - a to_string_fn>. - - @param[TO_STRING_LEFT, TO_STRING_RIGHT] - 7-bit characters, defaults to '(' and ')'. - - @param[TO_STRING_EXTERN, TO_STRING_INTERN] - Normally the space to put the temporary strings is static, one per file. With - this, it's possible to have a global storage to save space: have one file have - `TO_STRING_INTERN` as the first box, the other files `TO_STRING_EXTERN`. This - is unsynchronized. - - @fixme `extern` untested. - - @std C89 */ - -#if !defined(BOX_TYPE) || !defined(BOX_CONTENT) || !defined(BOX_) \ - || !defined(BOX_MAJOR_NAME) || !defined(BOX_MINOR_NAME) \ - || defined(STR_) || defined(STREXTERN_) -#error Unexpected preprocessor symbols. -#endif - -#if defined(TO_STRING_H) \ - && (defined(TO_STRING_EXTERN) || defined(TO_STRING_INTERN)) /* */ -#endif /* !not --> */ - -#ifndef TO_STRING_H /* */ -#else /* ntern --> */ -#endif /* idempotent --> */ - -#ifndef TO_STRING_LEFT -#define TO_STRING_LEFT '(' -#endif -#ifndef TO_STRING_RIGHT -#define TO_STRING_RIGHT ')' -#endif - -#ifndef BOX_TRAIT_NAME /* */ - -/* Provides an extra level of indirection for boxes if they need it. */ -#ifndef TO_STRING_THUNK_ -#define TO_STRING_THUNK_(n) n -#endif - -/* Hopefully gets rid of any nestled-qualifiers, but only when appropriate. */ -#ifndef TO_STRING_CAST -#define TO_STRING_CAST (void *) -#endif - -typedef BOX_TYPE PSTR_(box); -typedef BOX_CONTENT PSTR_(element); -typedef const BOX_CONTENT PSTR_(element_c); /* Assumes a lot. */ - -/** : responsible for turning the read-only argument into a - 12-`char` null-terminated output string. The first argument should be a - read-only reference to an element and the second a pointer to the bytes. */ -typedef void (*PSTR_(to_string_fn))(const PSTR_(element), char (*)[12]); -/* _Nb_: this is for documentation only; there is no way to get a general - read-only type which what we are supplied. Think of nested pointers. */ - -/** : print the contents of `box` in a static string buffer of - 256 bytes, with limitations of only printing 4 things at a time. - @return Address of the static buffer. @order \Theta(1) @allow */ -static const char *STR_(to_string)(const PSTR_(box) *const box) { - const char comma = ',', space = ' ', ellipsis[] = "…", - left = TO_STRING_LEFT, right = TO_STRING_RIGHT; - const size_t ellipsis_len = sizeof ellipsis - 1; - char *const buffer = to_string_buffers[to_string_buffer_i++], *b = buffer; - size_t advance; - PSTR_(element) x; - struct BOX_(iterator) it; - int is_sep = 0; - /* Minimum size: "(" "XXXXXXXXXXX" "," "…" ")" "\0". */ - assert(box && !(to_string_buffers_no & (to_string_buffers_no - 1)) - && to_string_buffer_size >= 1 + 11 + 1 + ellipsis_len + 1 + 1); - /* Advance the buffer for next time. */ - to_string_buffer_i &= to_string_buffers_no - 1; - { /* We do not modify `box`, but the compiler doesn't know that. */ - PSTR_(box) *promise_box; - memcpy(&promise_box, &box, sizeof box); - it = BOX_(iterator)(promise_box); - } - *b++ = left; - while(BOX_(is_element)(x = BOX_(next)(&it))) { - /* One must have this function declared! */ - TO_STRING_THUNK_(STREXTERN_(to_string))(TO_STRING_CAST - x, (char (*)[12])b); - /* Paranoid about '\0'; wastes 1 byte of 12, but otherwise confusing. */ - for(advance = 0; *b != '\0' && advance < 11; b++, advance++); - is_sep = 1, *b++ = comma, *b++ = space; - /* Greedy typesetting: enough for "XXXXXXXXXXX" "," "…" ")" "\0". */ - if((size_t)(b - buffer) - > to_string_buffer_size - 11 - 1 - ellipsis_len - 1 - 1) { - if(BOX_(is_element)(BOX_(next)(&it))) goto ellipsis; - else break; - } - } - if(is_sep) b -= 2; - *b++ = right; - goto terminate; -ellipsis: - b--; - memcpy(b, ellipsis, ellipsis_len), b += ellipsis_len; - *b++ = right; -terminate: - *b++ = '\0'; - assert(b - buffer <= to_string_buffer_size); - return buffer; -} - -static void PSTR_(unused_to_string_coda)(void); -static void PSTR_(unused_to_string)(void) - { STR_(to_string)(0); PSTR_(unused_to_string_coda)(); } -static void PSTR_(unused_to_string_coda)(void) { PSTR_(unused_to_string)(); } - -#undef STR_ -#undef STREXTERN_ -#undef TO_STRING_CAST -#undef TO_STRING_THUNK_ -#ifdef TO_STRING_EXTERN -#undef TO_STRING_EXTERN -#endif -#ifdef TO_STRING_INTERN -#undef TO_STRING_INTERN -#endif -#undef TO_STRING_LEFT -#undef TO_STRING_RIGHT