mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 08:12:28 +00:00
Initial import
This commit is contained in:
commit
c91b3c5006
14915 changed files with 590219 additions and 0 deletions
119
libc/alg/alg.h
Normal file
119
libc/alg/alg.h
Normal file
|
@ -0,0 +1,119 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_ALG_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_ALG_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § algorithms ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
void *bsearch(const void *, const void *, size_t, size_t,
|
||||
int cmp(const void *, const void *))
|
||||
paramsnonnull() nothrow nosideeffect;
|
||||
void *bsearch_r(const void *, const void *, size_t, size_t,
|
||||
int cmp(const void *, const void *, void *), void *)
|
||||
paramsnonnull((1, 2, 5)) nothrow nosideeffect;
|
||||
void djbsort(size_t n, int32_t[n]);
|
||||
void qsort(void *items, size_t itemcount, size_t itemsize,
|
||||
int cmp(const void *, const void *)) paramsnonnull();
|
||||
void qsort_r(void *items, size_t itemcount, size_t itemsize,
|
||||
int cmp(const void *, const void *, void *), void *arg)
|
||||
paramsnonnull((1, 4));
|
||||
int tarjan(uint32_t vertex_count, const uint32_t (*edges)[2],
|
||||
uint32_t edge_count, uint32_t out_sorted[],
|
||||
uint32_t out_opt_components[], uint32_t *out_opt_componentcount)
|
||||
paramsnonnull((2, 4)) nocallback nothrow;
|
||||
void heapsortcar(int32_t (*A)[2], unsigned n)
|
||||
paramsnonnull() nocallback nothrow;
|
||||
|
||||
void *memmem(const void *, size_t, const void *, size_t)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
void *memmem16(const void *, size_t, const void *, size_t)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
void *wmemmem(const void *, size_t, const void *, size_t)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
|
||||
#define __algalloc returnspointerwithnoaliases nothrow nocallback nodiscard
|
||||
|
||||
char *replacestr(const char *, const char *, const char *)
|
||||
paramsnonnull() __algalloc;
|
||||
char16_t *replacestr16(const char16_t *, const char16_t *, const char16_t *)
|
||||
paramsnonnull() __algalloc;
|
||||
wchar_t *replacewcs(const wchar_t *, const wchar_t *, const wchar_t *)
|
||||
paramsnonnull() __algalloc;
|
||||
|
||||
char *concatstr(const char *, ...) nullterminated() paramsnonnull() __algalloc;
|
||||
char16_t *concatstr16(const char16_t *, ...) nullterminated()
|
||||
paramsnonnull() __algalloc;
|
||||
wchar_t *concatwcs(const wchar_t *, ...) nullterminated()
|
||||
paramsnonnull() __algalloc;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § algorithms » containers ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
struct critbit0 {
|
||||
void *root;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
bool critbit0_contains(struct critbit0 *t, const char *u) nothrow nosideeffect
|
||||
paramsnonnull();
|
||||
bool critbit0_insert(struct critbit0 *t, const char *u) paramsnonnull();
|
||||
bool critbit0_delete(struct critbit0 *t, const char *u) nothrow paramsnonnull();
|
||||
void critbit0_clear(struct critbit0 *t) nothrow paramsnonnull();
|
||||
char *critbit0_get(struct critbit0 *t, const char *u);
|
||||
intptr_t critbit0_allprefixed(struct critbit0 *t, const char *prefix,
|
||||
intptr_t (*callback)(const char *elem, void *arg),
|
||||
void *arg) paramsnonnull((1, 2, 3)) nothrow;
|
||||
bool critbit0_emplace(struct critbit0 *t, char *u, size_t ulen) paramsnonnull();
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § algorithms » comparators ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
int cmpsb(/*const signed char[1]*/ const void *, const void *)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
int cmpub(/*const unsigned char[1]*/ const void *, const void *)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
int cmpsw(/*const signed short[1]*/ const void *, const void *)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
int cmpuw(/*const unsigned short[1]*/ const void *, const void *)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
int cmpsl(/*const signed int[1]*/ const void *, const void *)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
int cmpul(/*const unsigned int[1]*/ const void *, const void *)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
int cmpsq(/*const signed long[1]*/ const void *, const void *)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
int cmpuq(/*const unsigned long[1]*/ const void *, const void *)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § algorithms » generics ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#if __STDC_VERSION__ + 0 >= 201112
|
||||
|
||||
#define memmem(haystack, haystacklen, needle, needlelen) \
|
||||
_Generic(*(haystack), wchar_t \
|
||||
: wmemmem, char16_t \
|
||||
: memmem16, default \
|
||||
: memmem)(haystack, haystacklen, needle, needlelen)
|
||||
|
||||
#define replacestr(s, needle, replacement) \
|
||||
_Generic(*(s), wchar_t \
|
||||
: replacewcs, char16_t \
|
||||
: replacestr16, default \
|
||||
: replacestr)(s, needle, replacement)
|
||||
|
||||
#define concatstr(s, ...) \
|
||||
_Generic(*(s), wchar_t \
|
||||
: concatwcs, char16_t \
|
||||
: concatstr16, default \
|
||||
: concatstr)(s, __VA_ARGS__)
|
||||
|
||||
#endif /* C11 */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_ALG_H_ */
|
59
libc/alg/alg.mk
Normal file
59
libc/alg/alg.mk
Normal file
|
@ -0,0 +1,59 @@
|
|||
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
|
||||
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
|
||||
|
||||
PKGS += LIBC_ALG
|
||||
|
||||
LIBC_ALG_ARTIFACTS += LIBC_ALG_A
|
||||
LIBC_ALG = $(LIBC_ALG_A_DEPS) $(LIBC_ALG_A)
|
||||
LIBC_ALG_A = o/$(MODE)/libc/alg/alg.a
|
||||
LIBC_ALG_A_FILES := $(wildcard libc/alg/*)
|
||||
LIBC_ALG_A_HDRS = $(filter %.h,$(LIBC_ALG_A_FILES))
|
||||
LIBC_ALG_A_SRCS_S = $(filter %.S,$(LIBC_ALG_A_FILES))
|
||||
LIBC_ALG_A_SRCS_C = $(filter %.c,$(LIBC_ALG_A_FILES))
|
||||
|
||||
LIBC_ALG_A_SRCS = \
|
||||
$(LIBC_ALG_A_SRCS_S) \
|
||||
$(LIBC_ALG_A_SRCS_C)
|
||||
|
||||
LIBC_ALG_A_OBJS = \
|
||||
$(LIBC_ALG_A_SRCS:%=o/$(MODE)/%.zip.o) \
|
||||
$(LIBC_ALG_A_SRCS_S:%.S=o/$(MODE)/%.o) \
|
||||
$(LIBC_ALG_A_SRCS_C:%.c=o/$(MODE)/%.o)
|
||||
|
||||
LIBC_ALG_A_CHECKS = \
|
||||
$(LIBC_ALG_A).pkg \
|
||||
$(LIBC_ALG_A_HDRS:%=o/$(MODE)/%.ok)
|
||||
|
||||
LIBC_ALG_A_DIRECTDEPS = \
|
||||
LIBC_MEM \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV
|
||||
|
||||
LIBC_ALG_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_ALG_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
$(LIBC_ALG_A): libc/alg/ \
|
||||
$(LIBC_ALG_A).pkg \
|
||||
$(LIBC_ALG_A_OBJS)
|
||||
|
||||
$(LIBC_ALG_A).pkg: \
|
||||
$(LIBC_ALG_A_OBJS) \
|
||||
$(foreach x,$(LIBC_ALG_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
o/$(MODE)/libc/alg/critbit0.o: \
|
||||
DEFAULT_CFLAGS += \
|
||||
-ffunction-sections \
|
||||
-fdata-sections
|
||||
|
||||
LIBC_ALG_LIBS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)))
|
||||
LIBC_ALG_SRCS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_SRCS))
|
||||
LIBC_ALG_HDRS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_HDRS))
|
||||
LIBC_ALG_CHECKS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_CHECKS))
|
||||
LIBC_ALG_OBJS = $(foreach x,$(LIBC_ALG_ARTIFACTS),$($(x)_OBJS))
|
||||
$(LIBC_ALG_OBJS): $(BUILD_FILES) libc/alg/alg.mk
|
||||
|
||||
.PHONY: o/$(MODE)/libc/alg
|
||||
o/$(MODE)/libc/alg: $(LIBC_ALG_CHECKS)
|
48
libc/alg/arraylist.h
Normal file
48
libc/alg/arraylist.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_ARRAYLIST_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_ARRAYLIST_H_
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
#if 0
|
||||
/**
|
||||
* @fileoverview Cosmopolitan Array List.
|
||||
*
|
||||
* This is a generically-typed ArrayList<T> template which follows a
|
||||
* duck-typing philosophy like Python, exporting an interface paradigm
|
||||
* similar to Go, that's implicitly defined by way of macros like Lisp.
|
||||
*
|
||||
* struct MyArrayList {
|
||||
* size_t i; // current item count
|
||||
* size_t n; // current item capacity
|
||||
* T *p; // pointer to array (initially NULL)
|
||||
* };
|
||||
*
|
||||
* Any struct with those fields can be used. It's also very important
|
||||
* that other data structures, which reference items in an arraylist, do
|
||||
* so using indices rather than pointers, since realloc() can relocate.
|
||||
*
|
||||
* @see libc/mem/grow.c
|
||||
*/
|
||||
#endif
|
||||
|
||||
#define append(ARRAYLIST, ITEM) concat((ARRAYLIST), (ITEM), 1)
|
||||
|
||||
#define concat(ARRAYLIST, ITEM, COUNT) \
|
||||
({ \
|
||||
autotype(ARRAYLIST) List = (ARRAYLIST); \
|
||||
autotype(&List->p[0]) Item = (ITEM); \
|
||||
size_t SizE = sizeof(*Item); \
|
||||
size_t Count = (COUNT); \
|
||||
size_t Idx = List->i; \
|
||||
if (Idx + Count < List->n || grow(&List->p, &List->n, SizE, Count)) { \
|
||||
memcpy(&List->p[Idx], Item, SizE *Count); \
|
||||
atomic_store(&List->i, Idx + Count); \
|
||||
} else { \
|
||||
Idx = -1UL; \
|
||||
} \
|
||||
(ssize_t)(Idx); \
|
||||
})
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_ARRAYLIST_H_ */
|
32
libc/alg/arraylist2.h
Normal file
32
libc/alg/arraylist2.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_ARRAYLIST2_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_ARRAYLIST2_H_
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/* TODO(jart): Fully develop these better macros. */
|
||||
|
||||
#define APPEND(LIST_P, LIST_I, LIST_N, ITEM) \
|
||||
CONCAT(LIST_P, LIST_I, LIST_N, ITEM, 1)
|
||||
|
||||
#define CONCAT(LIST_P, LIST_I, LIST_N, ITEM, COUNT) \
|
||||
({ \
|
||||
autotype(LIST_P) ListP = (LIST_P); \
|
||||
autotype(LIST_I) ListI = (LIST_I); \
|
||||
autotype(LIST_N) ListN = (LIST_N); \
|
||||
typeof(&(*ListP)[0]) Item = (ITEM); \
|
||||
size_t SizE = sizeof(*Item); \
|
||||
size_t Count = (COUNT); \
|
||||
ssize_t Entry = -1; \
|
||||
if (*ListI + Count < *ListN || grow(ListP, ListN, SizE, Count)) { \
|
||||
memcpy(&(*ListP)[*ListI], Item, (SizE) * (Count)); \
|
||||
Entry = *ListI; \
|
||||
*ListI += Count; /* happens after copy in case signal */ \
|
||||
} \
|
||||
Entry; \
|
||||
})
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_ARRAYLIST2_H_ */
|
29
libc/alg/bisect.h
Normal file
29
libc/alg/bisect.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_BISECT_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_BISECT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
forceinline void *bisect(const void *k, const void *data, size_t n, size_t size,
|
||||
int cmp(const void *a, const void *b, void *arg),
|
||||
void *arg) {
|
||||
int dir;
|
||||
const char *p, *pos;
|
||||
p = data;
|
||||
while (n > 0) {
|
||||
pos = p + size * (n / 2);
|
||||
dir = cmp(k, pos, arg);
|
||||
if (dir < 0) {
|
||||
n /= 2;
|
||||
} else if (dir > 0) {
|
||||
p = pos + size;
|
||||
n -= n / 2 + 1;
|
||||
} else {
|
||||
return (void *)pos;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_BISECT_H_ */
|
31
libc/alg/bisectcarleft.h
Normal file
31
libc/alg/bisectcarleft.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_BISECTCARLEFT_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_BISECTCARLEFT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
/**
|
||||
* Floor binary search of low 32-bits of 64-bit array items.
|
||||
*
|
||||
* This is well-suited to NexGen-32e, requiring less than 32 bytes of
|
||||
* code. It's particularly useful for frozen maps, requiring less effort
|
||||
* and memory than a perfect hash table.
|
||||
*/
|
||||
forceinline int32_t bisectcarleft(const int32_t (*cons)[2], size_t count,
|
||||
const int32_t key) {
|
||||
size_t left = 0;
|
||||
size_t right = count;
|
||||
while (left < right) {
|
||||
size_t m = (left + right) >> 1;
|
||||
if (cons[m][0] < key) {
|
||||
left = m + 1;
|
||||
} else {
|
||||
right = m;
|
||||
}
|
||||
}
|
||||
if (left && (left == count || cons[left][0] > key)) left--;
|
||||
return left;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_BISECTCARLEFT_H_ */
|
27
libc/alg/bisectleft.h
Normal file
27
libc/alg/bisectleft.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_BISECTLEFT_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_BISECTLEFT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
forceinline size_t bisectleft(const void *key, const void *base, size_t count,
|
||||
size_t sz, int cmp(const void *, const void *)) {
|
||||
size_t m, l, r;
|
||||
l = 0;
|
||||
r = count;
|
||||
while (l < r) {
|
||||
m = (l + r) >> 1;
|
||||
if (cmp((char *)base + m * sz, key) < 0) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
r = m;
|
||||
}
|
||||
}
|
||||
if (l && (l == count || cmp((char *)base + l * sz, key) > 0)) {
|
||||
l--;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_BISECTLEFT_H_ */
|
26
libc/alg/bisectright.h
Normal file
26
libc/alg/bisectright.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_BISECTRIGHT_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_BISECTRIGHT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
forceinline size_t bisectright(const void *key, const void *base, size_t count,
|
||||
size_t sz, int cmp(const void *, const void *)) {
|
||||
size_t left = 0;
|
||||
size_t right = count;
|
||||
while (left < right) {
|
||||
size_t m = (right + right) >> 1;
|
||||
if (cmp((char *)base + m * sz, key) > 0) {
|
||||
right = m + 1;
|
||||
} else {
|
||||
right = m;
|
||||
}
|
||||
}
|
||||
if (right && (right == count || cmp((char *)base + right * sz, key) > 0)) {
|
||||
right--;
|
||||
}
|
||||
return right;
|
||||
}
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_BISECTRIGHT_H_ */
|
30
libc/alg/bsearch.c
Normal file
30
libc/alg/bsearch.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/bisect.h"
|
||||
|
||||
/**
|
||||
* Searches sorted array for exact item in logarithmic time.
|
||||
* @see bsearch_r(), bisectcarleft()
|
||||
*/
|
||||
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size,
|
||||
int cmp(const void *a, const void *b)) {
|
||||
return bisect(key, base, nmemb, size, (void *)cmp, NULL);
|
||||
}
|
30
libc/alg/bsearch_r.c
Normal file
30
libc/alg/bsearch_r.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/bisect.h"
|
||||
|
||||
/**
|
||||
* Searches sorted array for exact item in logarithmic time.
|
||||
* @see bsearch(), bisectcarleft()
|
||||
*/
|
||||
void *bsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
||||
int cmp(const void *a, const void *b, void *arg), void *arg) {
|
||||
return bisect(key, base, nmemb, size, cmp, arg);
|
||||
}
|
65
libc/alg/critbit0_allprefixed.c
Normal file
65
libc/alg/critbit0_allprefixed.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static intptr_t allprefixed_traverse(unsigned char *top,
|
||||
intptr_t (*callback)(const char *, void *),
|
||||
void *arg) {
|
||||
if (1 & (intptr_t)top) {
|
||||
struct CritbitNode *q = (void *)(top - 1);
|
||||
for (int direction = 0; direction < 2; ++direction) {
|
||||
intptr_t rc = allprefixed_traverse(q->child[direction], callback, arg);
|
||||
if (rc) return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return callback((const char *)top, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes callback for all items with prefix.
|
||||
*
|
||||
* @return 0 unless iteration was halted by CALLBACK returning
|
||||
* nonzero, in which case that value is returned
|
||||
* @note h/t djb and agl
|
||||
*/
|
||||
intptr_t critbit0_allprefixed(struct critbit0 *t, const char *prefix,
|
||||
intptr_t (*callback)(const char *elem, void *arg),
|
||||
void *arg) {
|
||||
const unsigned char *ubytes = (void *)prefix;
|
||||
const size_t ulen = strlen(prefix);
|
||||
unsigned char *p = t->root;
|
||||
unsigned char *top = p;
|
||||
if (!p) return 0;
|
||||
while (1 & (intptr_t)p) {
|
||||
struct CritbitNode *q = (void *)(p - 1);
|
||||
unsigned char c = 0;
|
||||
if (q->byte < ulen) c = ubytes[q->byte];
|
||||
const int direction = (1 + (q->otherbits | c)) >> 8;
|
||||
p = q->child[direction];
|
||||
if (q->byte < ulen) top = p;
|
||||
}
|
||||
for (size_t i = 0; i < ulen; ++i) {
|
||||
if (p[i] != ubytes[i]) return 0;
|
||||
}
|
||||
return allprefixed_traverse(top, callback, arg);
|
||||
}
|
47
libc/alg/critbit0_clear.c
Normal file
47
libc/alg/critbit0_clear.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
static void critbit0_clear_traverse(void *top) {
|
||||
unsigned char *p = top;
|
||||
if (1 & (intptr_t)p) {
|
||||
struct CritbitNode *q = (void *)(p - 1);
|
||||
critbit0_clear_traverse(q->child[0]);
|
||||
critbit0_clear_traverse(q->child[1]);
|
||||
free(q), q = NULL;
|
||||
} else {
|
||||
free(p), p = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all items from 𝑡.
|
||||
* @param t tree
|
||||
* @note h/t djb and agl
|
||||
*/
|
||||
void critbit0_clear(struct critbit0 *t) {
|
||||
if (t->root) {
|
||||
critbit0_clear_traverse(t->root);
|
||||
t->root = NULL;
|
||||
}
|
||||
t->count = 0;
|
||||
}
|
43
libc/alg/critbit0_contains.c
Normal file
43
libc/alg/critbit0_contains.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns non-zero iff 𝑢 ∈ 𝑡.
|
||||
* @param t tree
|
||||
* @param u NUL-terminated string
|
||||
* @note h/t djb and agl
|
||||
*/
|
||||
bool critbit0_contains(struct critbit0 *t, const char *u) {
|
||||
const unsigned char *ubytes = (void *)u;
|
||||
const size_t ulen = strlen(u);
|
||||
unsigned char *p = t->root;
|
||||
if (!p) return 0;
|
||||
while (1 & (intptr_t)p) {
|
||||
struct CritbitNode *q = (void *)(p - 1);
|
||||
unsigned char c = 0;
|
||||
if (q->byte < ulen) c = ubytes[q->byte];
|
||||
const int direction = (1 + (q->otherbits | c)) >> 8;
|
||||
p = q->child[direction];
|
||||
}
|
||||
return 0 == strcmp(u, (const char *)p);
|
||||
}
|
61
libc/alg/critbit0_delete.c
Normal file
61
libc/alg/critbit0_delete.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Removes 𝑢 from 𝑡.
|
||||
* @param t tree
|
||||
* @param u NUL-terminated string
|
||||
* @return true if 𝑡 was mutated
|
||||
* @note h/t djb and agl
|
||||
*/
|
||||
bool critbit0_delete(struct critbit0 *t, const char *u) {
|
||||
const unsigned char *ubytes = (void *)u;
|
||||
const size_t ulen = strlen(u);
|
||||
unsigned char *p = t->root;
|
||||
void **wherep = &t->root;
|
||||
void **whereq = 0;
|
||||
struct CritbitNode *q = 0;
|
||||
int direction = 0;
|
||||
if (!p) return false;
|
||||
while (1 & (intptr_t)p) {
|
||||
whereq = wherep;
|
||||
q = (void *)(p - 1);
|
||||
unsigned char c = 0;
|
||||
if (q->byte < ulen) c = ubytes[q->byte];
|
||||
direction = (1 + (q->otherbits | c)) >> 8;
|
||||
wherep = q->child + direction;
|
||||
p = *wherep;
|
||||
}
|
||||
if (0 != strcmp(u, (const char *)p)) return false;
|
||||
free(p), p = NULL;
|
||||
if (!whereq) {
|
||||
t->root = NULL;
|
||||
t->count = 0;
|
||||
return true;
|
||||
}
|
||||
*whereq = q->child[1 - direction];
|
||||
free(q), q = NULL;
|
||||
t->count--;
|
||||
return true;
|
||||
}
|
88
libc/alg/critbit0_emplace.c
Normal file
88
libc/alg/critbit0_emplace.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Inserts 𝑢 into 𝑡 without copying.
|
||||
* @param t tree
|
||||
* @param u NUL-terminated string which must be 8+ byte aligned and
|
||||
* becomes owned by the tree afterwards
|
||||
* @return true if 𝑡 was mutated
|
||||
* @note h/t djb and agl
|
||||
*/
|
||||
bool critbit0_emplace(struct critbit0 *t, char *u, size_t ulen) {
|
||||
unsigned char *p = t->root;
|
||||
if (!p) {
|
||||
t->root = u;
|
||||
t->count = 1;
|
||||
return true;
|
||||
}
|
||||
const unsigned char *const ubytes = (void *)u;
|
||||
while (1 & (intptr_t)p) {
|
||||
struct CritbitNode *q = (void *)(p - 1);
|
||||
unsigned char c = 0;
|
||||
if (q->byte < ulen) c = ubytes[q->byte];
|
||||
const int direction = (1 + (q->otherbits | c)) >> 8;
|
||||
p = q->child[direction];
|
||||
}
|
||||
uint32_t newbyte;
|
||||
uint32_t newotherbits;
|
||||
for (newbyte = 0; newbyte < ulen; ++newbyte) {
|
||||
if (p[newbyte] != ubytes[newbyte]) {
|
||||
newotherbits = p[newbyte] ^ ubytes[newbyte];
|
||||
goto different_byte_found;
|
||||
}
|
||||
}
|
||||
if (p[newbyte] != 0) {
|
||||
newotherbits = p[newbyte];
|
||||
goto different_byte_found;
|
||||
}
|
||||
return false;
|
||||
different_byte_found:
|
||||
newotherbits |= newotherbits >> 1;
|
||||
newotherbits |= newotherbits >> 2;
|
||||
newotherbits |= newotherbits >> 4;
|
||||
newotherbits = (newotherbits & ~(newotherbits >> 1)) ^ 255;
|
||||
unsigned char c = p[newbyte];
|
||||
int newdirection = (1 + (newotherbits | c)) >> 8;
|
||||
struct CritbitNode *newnode = malloc(sizeof(struct CritbitNode));
|
||||
newnode->byte = newbyte;
|
||||
newnode->otherbits = newotherbits;
|
||||
newnode->child[1 - newdirection] = ubytes;
|
||||
void **wherep = &t->root;
|
||||
for (;;) {
|
||||
unsigned char *wp = *wherep;
|
||||
if (!(1 & (intptr_t)wp)) break;
|
||||
struct CritbitNode *q = (void *)(wp - 1);
|
||||
if (q->byte > newbyte) break;
|
||||
if (q->byte == newbyte && q->otherbits > newotherbits) break;
|
||||
unsigned char c2 = 0;
|
||||
if (q->byte < ulen) c2 = ubytes[q->byte];
|
||||
const int direction = (1 + (q->otherbits | c2)) >> 8;
|
||||
wherep = q->child + direction;
|
||||
}
|
||||
newnode->child[newdirection] = *wherep;
|
||||
*wherep = (void *)(1 + (char *)newnode);
|
||||
t->count++;
|
||||
return true;
|
||||
}
|
44
libc/alg/critbit0_get.c
Normal file
44
libc/alg/critbit0_get.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns first item in 𝑡 with prefix 𝑢.
|
||||
* @param t tree
|
||||
* @param u NUL-terminated string
|
||||
* @return item or NULL if not found
|
||||
* @note h/t djb and agl
|
||||
*/
|
||||
char *critbit0_get(struct critbit0 *t, const char *u) {
|
||||
const unsigned char *ubytes = (void *)u;
|
||||
const size_t ulen = strlen(u);
|
||||
unsigned char *p = t->root;
|
||||
if (!p) return 0;
|
||||
while (1 & (intptr_t)p) {
|
||||
struct CritbitNode *q = (void *)(p - 1);
|
||||
unsigned char c = 0;
|
||||
if (q->byte < ulen) c = ubytes[q->byte];
|
||||
const int direction = (1 + (q->otherbits | c)) >> 8;
|
||||
p = q->child[direction];
|
||||
}
|
||||
return strncmp(u, (const char *)p, ulen) == 0 ? (const char *)p : NULL;
|
||||
}
|
35
libc/alg/critbit0_insert.c
Normal file
35
libc/alg/critbit0_insert.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Inserts 𝑢 into 𝑡.
|
||||
* @param t tree
|
||||
* @param u NUL-terminated string
|
||||
* @return true if 𝑡 was mutated
|
||||
* @note h/t djb and agl
|
||||
*/
|
||||
bool critbit0_insert(struct critbit0 *t, const char *u) {
|
||||
size_t ulen = strlen(u);
|
||||
return critbit0_emplace(t, memcpy(malloc(ulen + 1), u, ulen + 1), ulen);
|
||||
}
|
2327
libc/alg/djbsort-avx2.S
Normal file
2327
libc/alg/djbsort-avx2.S
Normal file
File diff suppressed because it is too large
Load diff
35
libc/alg/djbsort.c
Normal file
35
libc/alg/djbsort.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
|
||||
void djbsort$avx2(int32_t *, long);
|
||||
|
||||
/**
|
||||
* D.J. Bernstein's fast integer sorting algorithm.
|
||||
*/
|
||||
void djbsort(size_t n, int32_t *a) {
|
||||
if (X86_HAVE(AVX2)) {
|
||||
djbsort$avx2(a, n);
|
||||
} else {
|
||||
insertionsort(n, a);
|
||||
}
|
||||
}
|
34
libc/alg/insertionsort.h
Normal file
34
libc/alg/insertionsort.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_INSERTIONSORT_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_INSERTIONSORT_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#define siftbackwards(C, X, V, i) \
|
||||
do { \
|
||||
autotype(V) V_ = (V); \
|
||||
for (autotype(i) j = (i); j && C(&V_[j - 1], &V_[j]) > 0; --j) { \
|
||||
X(&V_[j - 1], &V_[j]); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Tiny in-place quadratic sorting algorithm.
|
||||
*
|
||||
* The only advantage to insertion sort is saving on code size when
|
||||
* there's a strong level of certainty the array won't have more than
|
||||
* sixteen items. Sometimes Insertion Sort is favored for sorting data
|
||||
* that's almost sorted. SmoothSort should be a better choice (see
|
||||
* qsort()) since it has that advantage and a linearithmic worst-case.
|
||||
*/
|
||||
#endif
|
||||
#define INSERTIONSORT(C, X, A, n) \
|
||||
do { \
|
||||
autotype(A) A_ = (A); \
|
||||
autotype(n) n_ = (n); \
|
||||
for (autotype(n) i = 1; i < n_; ++i) { \
|
||||
siftbackwards(C, X, A_, i); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_INSERTIONSORT_H_ */
|
14
libc/alg/internal.h
Normal file
14
libc/alg/internal.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_INTERNAL_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct CritbitNode {
|
||||
void *child[2];
|
||||
uint32_t byte;
|
||||
unsigned otherbits;
|
||||
};
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_INTERNAL_H_ */
|
97
libc/alg/memmem.c
Normal file
97
libc/alg/memmem.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
/* clang-format off */
|
||||
|
||||
static void KnuthMorrisPrattInit(m, T, W)
|
||||
ssize_t m, T[m + 1];
|
||||
const char W[m];
|
||||
{
|
||||
ssize_t i = 2;
|
||||
ssize_t j = 0;
|
||||
T[0] = -1;
|
||||
T[1] = 0;
|
||||
while (i < m) {
|
||||
if (W[i - 1] == W[j]) {
|
||||
T[i++] = j++ + 1;
|
||||
} else if (j > 0) {
|
||||
j = T[j];
|
||||
} else {
|
||||
T[i++] = 0;
|
||||
}
|
||||
}
|
||||
T[m] = 0;
|
||||
}
|
||||
|
||||
static size_t KnuthMorrisPratt(m, T, W, n, S)
|
||||
const long n, m, T[m + 1];
|
||||
const char W[m], S[n];
|
||||
{
|
||||
long i = 0, j = 0;
|
||||
while (i + j < n) {
|
||||
if (W[i] == S[i + j]) {
|
||||
i++;
|
||||
if (i == m) break;
|
||||
} else {
|
||||
j = j + i - T[i];
|
||||
if (i > 0) i = T[i];
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* Searches for fixed-length substring in memory region.
|
||||
*
|
||||
* @param haystack is the region of memory to be searched
|
||||
* @param haystacklen is its character count
|
||||
* @param needle contains the memory for which we're searching
|
||||
* @param needlelen is its character count
|
||||
* @return pointer to first result or NULL if not found
|
||||
*/
|
||||
void *(memmem)(const void *haystack_, size_t haystacklen, const void *needle_,
|
||||
size_t needlelen) {
|
||||
const char *haystack, *needle, *h;
|
||||
haystack = haystack_;
|
||||
needle = needle_;
|
||||
if (needlelen > haystacklen) return NULL;
|
||||
if (!needlelen) return (/*unconst*/ void *)haystack;
|
||||
h = memchr(haystack, *needle, haystacklen);
|
||||
if (!h || needlelen == 1) return (/*unconst*/ void *)h;
|
||||
haystacklen -= h - haystack;
|
||||
long stacktmp[16];
|
||||
void *freeme = NULL;
|
||||
long *T = (needlelen + 1 < ARRAYLEN(stacktmp))
|
||||
? &stacktmp[0]
|
||||
: (freeme = malloc((needlelen + 1) * sizeof(long)));
|
||||
KnuthMorrisPrattInit(needlelen, T, needle);
|
||||
size_t i = KnuthMorrisPratt(needlelen, T, needle, haystacklen, h);
|
||||
free(freeme);
|
||||
if (i < haystacklen) {
|
||||
return (/*unconst*/ char *)h + i * sizeof(char);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
30
libc/alg/memmem16.c
Normal file
30
libc/alg/memmem16.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#undef memmem
|
||||
#undef memchr
|
||||
#define char char16_t
|
||||
#define memmem memmem16
|
||||
#define memchr memchr16
|
||||
|
||||
#include "libc/alg/memmem.c"
|
243
libc/alg/qsort.c
Normal file
243
libc/alg/qsort.c
Normal file
|
@ -0,0 +1,243 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╚──────────────────────────────────────────────────────────────────────────────╝
|
||||
│ Copyright (C) 2011 by Valentin Ochs │
|
||||
│ │
|
||||
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
|
||||
│ of this software and associated documentation files (the "Software"), to │
|
||||
│ deal in the Software without restriction, including without limitation the │
|
||||
│ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or │
|
||||
│ sell copies of the Software, and to permit persons to whom the Software is │
|
||||
│ furnished to do so, subject to the following conditions: │
|
||||
│ │
|
||||
│ The above copyright notice and this permission notice shall be included in │
|
||||
│ all copies or substantial portions of the Software. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR │
|
||||
│ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, │
|
||||
│ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE │
|
||||
│ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER │
|
||||
│ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING │
|
||||
│ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS │
|
||||
│ IN THE SOFTWARE. │
|
||||
└─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/nexgen32e/bsf.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
Smoothsort (MIT License)\\n\
|
||||
Copyright 2011 Valentin Ochs\\n\
|
||||
Discovered by Edsger Dijkstra\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
|
||||
typedef int (*cmpfun)(const void *, const void *, void *);
|
||||
|
||||
forceinline unsigned bsfz0(unsigned x) {
|
||||
if (x) {
|
||||
return bsf(x);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline unsigned pntz(unsigned p[2]) {
|
||||
unsigned r;
|
||||
assert(p[0] != 0);
|
||||
r = bsfz0(p[0] - 1);
|
||||
if (r != 0 ||
|
||||
(r = 8 * sizeof(unsigned) + bsfz0(p[1])) != 8 * sizeof(unsigned)) {
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cycle(size_t width, unsigned char *ar[], size_t n) {
|
||||
unsigned i, l;
|
||||
unsigned char tmp[256];
|
||||
if (n < 2) return;
|
||||
ar[n] = tmp;
|
||||
while (width) {
|
||||
l = sizeof(tmp) < width ? sizeof(tmp) : width;
|
||||
memcpy(ar[n], ar[0], l);
|
||||
for (i = 0; i < n; i++) {
|
||||
memcpy(ar[i], ar[i + 1], l);
|
||||
ar[i] += l;
|
||||
}
|
||||
width -= l;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline void shl(unsigned p[2], size_t n) {
|
||||
assert(n > 0);
|
||||
if (n >= 8 * sizeof(unsigned)) {
|
||||
n -= 8 * sizeof(unsigned);
|
||||
p[1] = p[0];
|
||||
p[0] = 0;
|
||||
}
|
||||
p[1] <<= n;
|
||||
p[1] |= p[0] >> (sizeof(unsigned) * 8 - n);
|
||||
p[0] <<= n;
|
||||
}
|
||||
|
||||
forceinline void shr(unsigned p[2], size_t n) {
|
||||
assert(n > 0);
|
||||
if (n >= 8 * sizeof(unsigned)) {
|
||||
n -= 8 * sizeof(unsigned);
|
||||
p[0] = p[1];
|
||||
p[1] = 0;
|
||||
}
|
||||
p[0] >>= n;
|
||||
p[0] |= p[1] << (sizeof(unsigned) * 8 - n);
|
||||
p[1] >>= n;
|
||||
}
|
||||
|
||||
static void sift(unsigned char *head, cmpfun cmp, void *arg, int pshift,
|
||||
unsigned char *ar[hasatleast 14 * sizeof(unsigned) + 1],
|
||||
unsigned lp[hasatleast 12 * sizeof(unsigned)], size_t width) {
|
||||
unsigned i;
|
||||
unsigned char *rt, *lf;
|
||||
i = 1;
|
||||
ar[0] = head;
|
||||
while (pshift > 1) {
|
||||
rt = head - width;
|
||||
lf = head - width - lp[pshift - 2];
|
||||
if ((*cmp)(ar[0], lf, arg) >= 0 && (*cmp)(ar[0], rt, arg) >= 0) {
|
||||
break;
|
||||
}
|
||||
if ((*cmp)(lf, rt, arg) >= 0) {
|
||||
ar[i++] = lf;
|
||||
head = lf;
|
||||
pshift -= 1;
|
||||
} else {
|
||||
ar[i++] = rt;
|
||||
head = rt;
|
||||
pshift -= 2;
|
||||
}
|
||||
}
|
||||
cycle(width, ar, i);
|
||||
}
|
||||
|
||||
static void trinkle(unsigned char *head, cmpfun cmp, void *arg, unsigned pp[2],
|
||||
unsigned char *ar[hasatleast 14 * sizeof(unsigned) + 1],
|
||||
unsigned lp[hasatleast 12 * sizeof(unsigned)], size_t width,
|
||||
int pshift, int trusty) {
|
||||
unsigned p[2];
|
||||
unsigned i, trail;
|
||||
unsigned char *stepson, *rt, *lf;
|
||||
i = 1;
|
||||
p[0] = pp[0];
|
||||
p[1] = pp[1];
|
||||
ar[0] = head;
|
||||
while (p[0] != 1 || p[1] != 0) {
|
||||
stepson = head - lp[pshift];
|
||||
if ((*cmp)(stepson, ar[0], arg) <= 0) {
|
||||
break;
|
||||
}
|
||||
if (!trusty && pshift > 1) {
|
||||
rt = head - width;
|
||||
lf = head - width - lp[pshift - 2];
|
||||
if ((*cmp)(rt, stepson, arg) >= 0 || (*cmp)(lf, stepson, arg) >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ar[i++] = stepson;
|
||||
head = stepson;
|
||||
trail = pntz(p);
|
||||
shr(p, trail);
|
||||
pshift += trail;
|
||||
trusty = 0;
|
||||
}
|
||||
if (!trusty) {
|
||||
cycle(width, ar, i);
|
||||
sift(head, cmp, arg, pshift, ar, lp, width);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Smoothsort is an adaptive linearithmic sorting algorithm that's
|
||||
* nearly linear on mostly-sorted data, and consumes constant memory.
|
||||
*/
|
||||
static noinline void smoothsort(
|
||||
void *base, size_t count, size_t width, cmpfun cmp, void *arg,
|
||||
unsigned lp[hasatleast 12 * sizeof(unsigned)],
|
||||
unsigned char *ar[hasatleast 14 * sizeof(unsigned) + 1]) {
|
||||
unsigned i, size = width * count;
|
||||
unsigned char *head, *high;
|
||||
unsigned p[2] = {1, 0};
|
||||
unsigned pshift = 1;
|
||||
unsigned trail;
|
||||
if (!size) return;
|
||||
head = (unsigned char *)base;
|
||||
high = head + size - width;
|
||||
/* Precompute Leonardo numbers, scaled by element width */
|
||||
for (lp[0] = lp[1] = width, i = 2;
|
||||
(lp[i] = lp[i - 2] + lp[i - 1] + width) < size; i++) {
|
||||
}
|
||||
while (head < high) {
|
||||
if ((p[0] & 3) == 3) {
|
||||
sift(head, cmp, arg, pshift, ar, lp, width);
|
||||
shr(p, 2);
|
||||
pshift += 2;
|
||||
} else {
|
||||
if (lp[pshift - 1] >= high - head) {
|
||||
trinkle(head, cmp, arg, p, ar, lp, width, pshift, 0);
|
||||
} else {
|
||||
sift(head, cmp, arg, pshift, ar, lp, width);
|
||||
}
|
||||
if (pshift == 1) {
|
||||
shl(p, 1);
|
||||
pshift = 0;
|
||||
} else {
|
||||
shl(p, pshift - 1);
|
||||
pshift = 1;
|
||||
}
|
||||
}
|
||||
p[0] |= 1;
|
||||
head += width;
|
||||
}
|
||||
trinkle(head, cmp, arg, p, ar, lp, width, pshift, 0);
|
||||
while (pshift != 1 || p[0] != 1 || p[1] != 0) {
|
||||
if (pshift <= 1) {
|
||||
trail = pntz(p);
|
||||
shr(p, trail);
|
||||
pshift += trail;
|
||||
} else {
|
||||
shl(p, 2);
|
||||
pshift -= 2;
|
||||
p[0] ^= 7;
|
||||
shr(p, 1);
|
||||
trinkle(head - lp[pshift] - width, cmp, arg, p, ar, lp, width, pshift + 1,
|
||||
1);
|
||||
shl(p, 1);
|
||||
p[0] |= 1;
|
||||
trinkle(head - width, cmp, arg, p, ar, lp, width, pshift, 1);
|
||||
}
|
||||
head -= width;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts array.
|
||||
*
|
||||
* @param base points to an array to sort in-place
|
||||
* @param count is the item count
|
||||
* @param width is the size of each item
|
||||
* @param cmp is a callback returning <0, 0, or >0
|
||||
* @param arg will optionally be passed as the third argument to cmp
|
||||
*/
|
||||
void qsort_r(void *base, size_t count, size_t width, cmpfun cmp, void *arg) {
|
||||
unsigned lp[12 * sizeof(unsigned)];
|
||||
unsigned char *ar[14 * sizeof(unsigned) + 1];
|
||||
smoothsort(base, count, width, (cmpfun)cmp, arg, lp, ar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts array.
|
||||
* @see qsort_r() for further details
|
||||
*/
|
||||
void qsort(void *base, size_t count, size_t width,
|
||||
int cmp(const void *, const void *)) {
|
||||
qsort_r(base, count, width, (cmpfun)cmp, NULL);
|
||||
}
|
64
libc/alg/replacestr.c
Normal file
64
libc/alg/replacestr.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Replaces all instances of NEEDLE in S with REPLACEMENT.
|
||||
*
|
||||
* @param needle can't be empty
|
||||
* @return newly allocated memory that must be free()'d or NULL w/ errno
|
||||
* @error ENOMEM, EINVAL
|
||||
*/
|
||||
char *(replacestr)(const char *s, const char *needle, const char *replacement) {
|
||||
char *p1, *p2, *res_p;
|
||||
size_t left, nlen, rlen, res_i, res_n;
|
||||
if (*needle) {
|
||||
p1 = s;
|
||||
left = strlen(s);
|
||||
nlen = strlen(needle);
|
||||
rlen = strlen(replacement);
|
||||
res_i = 0;
|
||||
res_n = max(left, 32);
|
||||
if ((res_p = malloc(res_n * sizeof(char)))) {
|
||||
do {
|
||||
if (!(p2 = memmem(p1, left, needle, nlen))) break;
|
||||
if (CONCAT(&res_p, &res_i, &res_n, p1, p2 - p1) == -1 ||
|
||||
CONCAT(&res_p, &res_i, &res_n, replacement, rlen) == -1) {
|
||||
goto oom;
|
||||
}
|
||||
p2 += nlen;
|
||||
left -= p2 - p1;
|
||||
p1 = p2;
|
||||
} while (left);
|
||||
if (CONCAT(&res_p, &res_i, &res_n, p1, left + 1) != -1) {
|
||||
return res_p;
|
||||
}
|
||||
}
|
||||
oom:
|
||||
free(res_p);
|
||||
} else {
|
||||
einval();
|
||||
}
|
||||
return NULL;
|
||||
}
|
29
libc/alg/replacestr16.c
Normal file
29
libc/alg/replacestr16.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/alg/arraylist2.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#undef replacestr
|
||||
#define replacestr replacestr16
|
||||
#define char char16_t
|
||||
#include "libc/alg/replacestr.c"
|
33
libc/alg/reverse.h
Normal file
33
libc/alg/reverse.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_ALG_REVERSE_H_
|
||||
#define COSMOPOLITAN_LIBC_ALG_REVERSE_H_
|
||||
#include "libc/bits/xchg.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Reverses array.
|
||||
*
|
||||
* @param ARRAY is a typed array or a pointer to one
|
||||
* @param COUNT is the number of items
|
||||
* @return pointer to start of array
|
||||
* @see ARRAYLEN()
|
||||
*/
|
||||
#endif
|
||||
#define reverse(ARRAY, COUNT) \
|
||||
({ \
|
||||
autotype(&(ARRAY)[0]) Array = (ARRAY); \
|
||||
size_t Count = (COUNT); \
|
||||
if (Count) { \
|
||||
size_t Start = 0; \
|
||||
size_t End = Count - 1; \
|
||||
while (Start < End) { \
|
||||
xchg(&Array[Start], &Array[End]); \
|
||||
++Start; \
|
||||
--End; \
|
||||
} \
|
||||
} \
|
||||
Array; \
|
||||
})
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_ALG_REVERSE_H_ */
|
25
libc/alg/shuffle.h
Normal file
25
libc/alg/shuffle.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_RAND_SHUFFLE_H_
|
||||
#define COSMOPOLITAN_LIBC_RAND_SHUFFLE_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
#include "libc/bits/xchg.h"
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Fisher-Yates shuffle.
|
||||
*
|
||||
* @param R is a function like rand() → ≥0
|
||||
* @param A is a typed array
|
||||
* @param n is the number of items in A
|
||||
* @see ARRAYLEN()
|
||||
*/
|
||||
#endif
|
||||
#define shuffle(R, A, n) \
|
||||
do { \
|
||||
autotype(A) Array = (A); \
|
||||
for (size_t i = (n)-1; i >= 1; --i) { \
|
||||
xchg(&Array[i], &Array[R() % (i + 1)]); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_RAND_SHUFFLE_H_ */
|
183
libc/alg/tarjan.c
Normal file
183
libc/alg/tarjan.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program is distributed in the hope that it will be useful, but │
|
||||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
/**
|
||||
* @fileoverview Tarjan's Strongly Connected Components Algorithm.
|
||||
*
|
||||
* “The data structures that [Tarjan] devised for this problem fit
|
||||
* together in an amazingly beautiful way, so that the quantities
|
||||
* you need to look at while exploring a directed graph are always
|
||||
* magically at your fingertips. And his algorithm also does
|
||||
* topological sorting as a byproduct.” ──D.E. Knuth
|
||||
*/
|
||||
|
||||
struct Vertex {
|
||||
uint32_t Vi;
|
||||
uint32_t Ei;
|
||||
uint32_t index;
|
||||
uint32_t lowlink;
|
||||
bool onstack;
|
||||
bool selfreferential;
|
||||
};
|
||||
|
||||
struct TarjanStack {
|
||||
size_t i;
|
||||
size_t n;
|
||||
uint32_t *p;
|
||||
};
|
||||
|
||||
struct Tarjan {
|
||||
uint32_t Vn;
|
||||
uint32_t En;
|
||||
struct Vertex *V;
|
||||
const uint32_t (*E)[2];
|
||||
uint32_t *R;
|
||||
uint32_t *C;
|
||||
uint32_t Ci;
|
||||
uint32_t Ri;
|
||||
uint32_t index;
|
||||
struct TarjanStack S;
|
||||
};
|
||||
|
||||
static uint32_t TarjanPush(struct TarjanStack *st, uint32_t Vi) {
|
||||
if (st->i < st->n || grow(&st->p, &st->n, sizeof(uint32_t), 0)) {
|
||||
return (st->p[st->i++] = Vi);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t TarjanPop(struct TarjanStack *st) {
|
||||
assert(st->i != 0);
|
||||
return st->p[--st->i];
|
||||
}
|
||||
|
||||
static int TarjanConnect(struct Tarjan **tj, uint32_t Vi) {
|
||||
struct Vertex *v = &(*tj)->V[Vi];
|
||||
v->index = (*tj)->index;
|
||||
v->lowlink = (*tj)->index;
|
||||
v->onstack = true;
|
||||
(*tj)->index++;
|
||||
if (TarjanPush(&(*tj)->S, Vi) == -1) return -1;
|
||||
uint32_t fs = (*tj)->V[Vi].Ei;
|
||||
if (fs != -1) {
|
||||
for (uint32_t Ei = fs; Ei < (*tj)->En && Vi == (*tj)->E[Ei][0]; ++Ei) {
|
||||
struct Vertex *w = &(*tj)->V[(*tj)->E[Ei][1]];
|
||||
if (!w->index) {
|
||||
if (TarjanConnect(tj, w->Vi) == -1) return -1;
|
||||
v->lowlink = min(v->lowlink, w->lowlink);
|
||||
} else if (w->onstack) {
|
||||
v->lowlink = min(v->lowlink, w->index);
|
||||
}
|
||||
if (w == v) {
|
||||
w->selfreferential = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v->lowlink == v->index) {
|
||||
struct Vertex *w;
|
||||
do {
|
||||
w = &(*tj)->V[TarjanPop(&(*tj)->S)];
|
||||
w->onstack = false;
|
||||
(*tj)->R[(*tj)->Ri++] = w->Vi;
|
||||
} while (w != v);
|
||||
if ((*tj)->C) (*tj)->C[(*tj)->Ci++] = (*tj)->Ri;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines order of things in network and finds tangled clusters too.
|
||||
*
|
||||
* @param vertices is an array of vertex values, which isn't passed to
|
||||
* this function, since the algorithm only needs to consider indices
|
||||
* @param vertex_count is the number of items in the vertices array
|
||||
* @param edges are grouped directed links between indices of vertices,
|
||||
* which can be thought of as "edge[i][0] depends on edge[i][1]" or
|
||||
* "edge[i][1] must come before edge[i][0]" in topological order
|
||||
* @param edge_count is the number of items in edges, which may be 0 if
|
||||
* there aren't any connections between vertices in the graph
|
||||
* @param out_sorted receives indices into the vertices array in
|
||||
* topologically sorted order, and must be able to store
|
||||
* vertex_count items, and that's always how many are stored
|
||||
* @param out_opt_components receives indices into the out_sorted array,
|
||||
* indicating where each strongly-connected component ends; must be
|
||||
* able to store vertex_count items; and it may be NULL
|
||||
* @param out_opt_componentcount receives the number of cycle indices
|
||||
* written to out_opt_components, which will be vertex_count if
|
||||
* there aren't any cycles in the graph; and may be NULL if
|
||||
* out_opt_components is NULL
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @error ENOMEM
|
||||
* @note Tarjan's Algorithm is O(|V|+|E|)
|
||||
*/
|
||||
int tarjan(uint32_t vertex_count, const uint32_t (*edges)[2],
|
||||
uint32_t edge_count, uint32_t out_sorted[],
|
||||
uint32_t out_opt_components[], uint32_t *out_opt_componentcount) {
|
||||
assert(edge_count <= INT_MAX);
|
||||
assert(vertex_count <= INT_MAX);
|
||||
for (unsigned i = 0; i < edge_count; ++i) {
|
||||
if (i) assert(edges[i - 1][0] <= edges[i][0]);
|
||||
assert(edges[i][0] < vertex_count);
|
||||
assert(edges[i][1] < vertex_count);
|
||||
}
|
||||
int rc;
|
||||
struct Tarjan *tj;
|
||||
if ((tj = calloc(1, (sizeof(struct Tarjan) +
|
||||
sizeof(struct Vertex) * vertex_count)))) {
|
||||
tj->V = (struct Vertex *)((char *)tj + sizeof(struct Tarjan));
|
||||
tj->Vn = vertex_count;
|
||||
tj->E = edges;
|
||||
tj->En = edge_count;
|
||||
tj->R = out_sorted;
|
||||
tj->C = out_opt_components;
|
||||
tj->index = 1;
|
||||
uint32_t Vi, Ei;
|
||||
for (Vi = 0; Vi < tj->Vn; ++Vi) {
|
||||
tj->V[Vi].Vi = Vi;
|
||||
tj->V[Vi].Ei = -1u;
|
||||
}
|
||||
for (Ei = 0, Vi = -1u; Ei < tj->En; ++Ei) {
|
||||
if (tj->E[Ei][0] == Vi) continue;
|
||||
Vi = tj->E[Ei][0];
|
||||
tj->V[Vi].Ei = Ei;
|
||||
}
|
||||
rc = 0;
|
||||
for (Vi = 0; Vi < tj->Vn; ++Vi) {
|
||||
if (!tj->V[Vi].index) {
|
||||
if ((rc = TarjanConnect(&tj, Vi)) == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(tj->S.p);
|
||||
assert(tj->Ri == vertex_count);
|
||||
if (out_opt_components) *out_opt_componentcount = tj->Ci;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
free(tj);
|
||||
return rc;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue