读书笔记之:C语言接口与实现[+]
第1章 简介
1. literate程序
2. 宏指令与条件编译指令
第2章 接口与实现
1. 接口与实现的关系
2. Arith接口及实现:
arith.h:
extern int Arith_max(int x, int y);
extern int Arith_min(int x, int y);
extern int Arith_div(int x, int y);
extern int Arith_mod(int x, int y);
extern int Arith_ceiling(int x, int y);
extern int Arith_floor (int x, int y);
arith.c
#include "arith.h"
int Arith_max(int x, int y) {
return x > y ? x : y;
}
int Arith_min(int x, int y) {
return x > y ? y : x;
}
int Arith_div(int x, int y) {
if (-13/5 == -2
&& (x < 0) != (y < 0) && x%y != 0)
return x/y - 1;
else
return x/y;
}
int Arith_mod(int x, int y) {
if (-13/5 == -2
&& (x < 0) != (y < 0) && x%y != 0)
return x%y + y;
else
return x%y;
}
int Arith_floor(int x, int y) {
return Arith_div(x, y);
}
int Arith_ceiling(int x, int y) {
return Arith_div(x, y) + (x%y != 0);
}
3. 抽象数据类型Stack
4. 客户调用程序的责任
stack.h
#ifndef STACK_INCLUDED
#define STACK_INCLUDED
#define T Stack_T
typedef struct T *T;
extern T Stack_new (void);
extern int Stack_empty(T stk);
extern void Stack_push (T stk, void *x);
extern void *Stack_pop (T stk);
extern void Stack_free (T *stk);
#undef T
#endif
stack.c
#include <stddef.h>
#include "assert.h"
#include "mem.h"
#include "stack.h"
#define T Stack_T
struct T {
int count;
struct elem {
void *x;
struct elem *link;
} *head;
};
T Stack_new(void) {
T stk;
NEW(stk);
stk->count = 0;
stk->head = NULL;
return stk;
}
int Stack_empty(T stk) {
assert(stk);
return stk->count == 0;
}
void Stack_push(T stk, void *x) {
struct elem *t;
assert(stk);
NEW(t);
t->x = x;
t->link = stk->head;
stk->head = t;
stk->count++;
}
void *Stack_pop(T stk) {
void *x;
struct elem *t;
assert(stk);
assert(stk->count > 0);
t = stk->head;
stk->head = t->link;
stk->count--;
x = t->x;
FREE(t);
return x;
}
void Stack_free(T *stk) {
struct elem *t, *u;
assert(stk && *stk);
for (t = (*stk)->head; t; t = u) {
u = t->link;
FREE(t);
}
FREE(*stk);
}
第3章 原子
1. 接口
atom.h:
#ifndef ATOM_INCLUDED
#define ATOM_INCLUDED
extern int Atom_length(const char *str);
extern const char *Atom_new (const char *str, int len);
extern const char *Atom_string(const char *str);
extern const char *Atom_int (long n);
#endif
atom.c:
#include "atom.h"
#include <string.h>
#include "assert.h"
#include <limits.h>
#include "mem.h"
#define NELEMS(x) ((sizeof (x))/(sizeof ((x)[0])))
static struct atom {
struct atom *link;
int len;
char *str;
} *buckets[2048];
static unsigned long scatter[] = {
2078917053, 143302914, 1027100827, 1953210302, 755253631, 2002600785,
1405390230, 45248011, 1099951567, 433832350, 2018585307, 438263339,
813528929, 1703199216, 618906479, 573714703, 766270699, 275680090,
1510320440, 1583583926, 1723401032, 1965443329, 1098183682, 1636505764,
980071615, 1011597961, 643279273, 1315461275, 157584038, 1069844923,
471560540, 89017443, 1213147837, 1498661368, 2042227746, 1968401469,
1353778505, 1300134328, 2013649480, 306246424, 1733966678, 1884751139,
744509763, 400011959, 1440466707, 1363416242, 973726663, 59253759,
1639096332, 336563455, 1642837685, 1215013716, 154523136, 593537720,
704035832, 1134594751, 1605135681, 1347315106, 302572379, 1762719719,
269676381, 774132919, 1851737163, 1482824219, 125310639, 1746481261,
1303742040, 1479089144, 899131941, 1169907872, 1785335569, 485614972,
907175364, 382361684, 885626931, 200158423, 1745777927, 1859353594,
259412182, 1237390611, 48433401, 1902249868, 304920680, 202956538,
348303940, 1008956512, 1337551289, 1953439621, 208787970, 1640123668,
1568675693, 478464352, 266772940, 1272929208, 1961288571, 392083579,
871926821, 1117546963, 1871172724, 1771058762, 139971187, 1509024645,
109190086, 1047146551, 1891386329, 994817018, 1247304975, 1489680608,
706686964, 1506717157, 579587572, 755120366, 1261483377, 884508252,
958076904, 1609787317, 1893464764, 148144545, 1415743291, 2102252735,
1788268214, 836935336, 433233439, 2055041154, 2109864544, 247038362,
299641085, 834307717, 1364585325, 23330161, 457882831, 1504556512,
1532354806, 567072918, 404219416, 1276257488, 1561889936, 1651524391,
618454448, 121093252, 1010757900, 1198042020, 876213618, 124757630,
2082550272, 1834290522, 1734544947, 1828531389, 1982435068, 1002804590,
1783300476, 1623219634, 1839739926, 69050267, 1530777140, 1802120822,
316088629, 1830418225, 488944891, 1680673954, 1853748387, 946827723,
1037746818, 1238619545, 1513900641, 1441966234, 367393385, 928306929,
946006977, 985847834, 1049400181, 1956764878, 36406206, 1925613800,
2081522508, 2118956479, 1612420674, 1668583807, 1800004220, 1447372094,
523904750, 1435821048, 923108080, 216161028, 1504871315, 306401572,
2018281851, 1820959944, 2136819798, 359743094, 1354150250, 1843084537,
1306570817, 244413420, 934220434, 672987810, 1686379655, 1301613820,
1601294739, 484902984, 139978006, 503211273, 294184214, 176384212,
281341425, 228223074, 147857043, 1893762099, 1896806882, 1947861263,
1193650546, 273227984, 1236198663, 2116758626, 489389012, 593586330,
275676551, 360187215, 267062626, 265012701, 719930310, 1621212876,
2108097238, 2026501127, 1865626297, 894834024, 552005290, 1404522304,
48964196, 5816381, 1889425288, 188942202, 509027654, 36125855,
365326415, 790369079, 264348929, 513183458, 536647531, 13672163,
313561074, 1730298077, 286900147, 1549759737, 1699573055, 776289160,
2143346068, 1975249606, 1136476375, 262925046, 92778659, 1856406685,
1884137923, 53392249, 1735424165, 1602280572
};
const char *Atom_string(const char *str) {
assert(str);
return Atom_new(str, strlen(str));
}
const char *Atom_int(long n) {
char str[43];
char *s = str + sizeof str;
unsigned long m;
if (n == LONG_MIN)
m = LONG_MAX + 1UL;
else if (n < 0)
m = -n;
else
m = n;
do
*--s = m%10 + '0';
while ((m /= 10) > 0);
if (n < 0)
*--s = '-';
return Atom_new(s, (str + sizeof str) - s);
}
const char *Atom_new(const char *str, int len) {
unsigned long h;
int i;
struct atom *p;
assert(str);
assert(len >= 0);
for (h = 0, i = 0; i < len; i++)
h = (h<<1) + scatter[(unsigned char)str[i]];
h &= NELEMS(buckets)-1;
for (p = buckets[h]; p; p = p->link)
if (len == p->len) {
for (i = 0; i < len && p->str[i] == str[i]; )
i++;
if (i == len)
return p->str;
}
p = ALLOC(sizeof (*p) + len + 1);
p->len = len;
p->str = (char *)(p + 1);
if (len > 0)
memcpy(p->str, str, len);
p->str[len] = '\0';
p->link = buckets[h];
buckets[h] = p;
return p->str;
}
int Atom_length(const char *str) {
struct atom *p;
int i;
assert(str);
for (i = 0; i < NELEMS(buckets); i++)
for (p = buckets[i]; p; p = p->link)
if (p->str == str)
return p->len;
assert(0);
return 0;
}
第4章 异常与断言
except.h
#ifndef EXCEPT_INCLUDED
#define EXCEPT_INCLUDED
#include <setjmp.h>
#define T Except_T
typedef struct T {
char *reason;
} T;
typedef struct Except_Frame Except_Frame;
struct Except_Frame {
Except_Frame *prev;
jmp_buf env;
const char *file;
int line;
const T *exception;
};
enum { Except_entered=0, Except_raised,
Except_handled, Except_finalized };
#ifdef WIN32
__declspec(thread)
#endif
extern Except_Frame *Except_stack;
extern const Except_T Assert_Failed;
void Except_raise(const T *e, const char *file,int line);
#define RAISE(e) Except_raise(&(e), __FILE__, __LINE__)
#define RERAISE Except_raise(Except_frame.exception, \
Except_frame.file, Except_frame.line)
#define RETURN switch (Except_stack = Except_stack->prev,0) default: return
#define TRY do { \
volatile int Except_flag; \
Except_Frame Except_frame; \
Except_frame.prev = Except_stack; \
Except_stack = &Except_frame; \
Except_flag = setjmp(Except_frame.env); \
if (Except_flag == Except_entered) {
#define EXCEPT(e) \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} else if (Except_frame.exception == &(e)) { \
Except_flag = Except_handled;
#define ELSE \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} else { \
Except_flag = Except_handled;
#define FINALLY \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} { \
if (Except_flag == Except_entered) \
Except_flag = Except_finalized;
#define END_TRY \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} if (Except_flag == Except_raised) RERAISE; \
} while (0)
#undef T
#endif
except.c
#include <stdlib.h>
#include <stdio.h>
#include "assert.h"
#include "except.h"
#define T Except_T
#ifdef WIN32
__declspec(thread)
#endif
Except_Frame *Except_stack = NULL;
void Except_raise(const T *e, const char *file,
int line) {
Except_Frame *p = Except_stack;
assert(e);
if (p == NULL) {
fprintf(stderr, "Uncaught exception");
if (e->reason)
fprintf(stderr, " %s", e->reason);
else
fprintf(stderr, " at 0x%p", e);
if (file && line > 0)
fprintf(stderr, " raised at %s:%d\n", file, line);
fprintf(stderr, "aborting...\n");
fflush(stderr);
abort();
}
p->exception = e;
p->file = file;
p->line = line;
Except_stack = Except_stack->prev;
longjmp(p->env, Except_raised);
}
assert.h
#undef assert
#ifdef NDEBUG
#define assert(e) ((void)0)
#else
#include "except.h"
extern void assert(int e);
#define assert(e) ((void)((e)||(RAISE(Assert_Failed),0)))
#endif
assert.c
#include "assert.h"
const Except_T Assert_Failed = { "Assertion failed" };
void (assert)(int e) {
assert(e);
}
第5章 内存管理
MEM分配接口
mem.h
#ifndef MEM_INCLUDED
#define MEM_INCLUDED
#include "except.h"
extern const Except_T Mem_Failed;
extern void *Mem_alloc (long nbytes,
const char *file, int line);
extern void *Mem_calloc(long count, long nbytes,
const char *file, int line);
extern void Mem_free(void *ptr,
const char *file, int line);
extern void *Mem_resize(void *ptr, long nbytes,
const char *file, int line);
#define ALLOC(nbytes) \
Mem_alloc((nbytes), __FILE__, __LINE__)
#define CALLOC(count, nbytes) \
Mem_calloc((count), (nbytes), __FILE__, __LINE__)
#define NEW(p) ((p) = ALLOC((long)sizeof *(p)))
#define NEW0(p) ((p) = CALLOC(1, (long)sizeof *(p)))
#define FREE(ptr) ((void)(Mem_free((ptr), \
__FILE__, __LINE__), (ptr) = 0))
#define RESIZE(ptr, nbytes) ((ptr) = Mem_resize((ptr), \
(nbytes), __FILE__, __LINE__))
#endif
mem.c
#include <stdlib.h>
#include <stddef.h>
#include "assert.h"
#include "except.h"
#include "mem.h"
const Except_T Mem_Failed = { "Allocation Failed" };
void *Mem_alloc(long nbytes, const char *file, int line){
void *ptr;
assert(nbytes > 0);
ptr = malloc(nbytes);
if (ptr == NULL)
{
if (file == NULL)
RAISE(Mem_Failed);
else
Except_raise(&Mem_Failed, file, line);
}
return ptr;
}
void *Mem_calloc(long count, long nbytes,
const char *file, int line) {
void *ptr;
assert(count > 0);
assert(nbytes > 0);
ptr = calloc(count, nbytes);
if (ptr == NULL)
{
if (file == NULL)
RAISE(Mem_Failed);
else
Except_raise(&Mem_Failed, file, line);
}
return ptr;
}
void Mem_free(void *ptr, const char *file, int line) {
if (ptr)
free(ptr);
}
void *Mem_resize(void *ptr, long nbytes,
const char *file, int line) {
assert(ptr);
assert(nbytes > 0);
ptr = realloc(ptr, nbytes);
if (ptr == NULL)
{
if (file == NULL)
RAISE(Mem_Failed);
else
Except_raise(&Mem_Failed, file, line);
}
return ptr;
}
第6章 进一步内存管理
arena.h
#ifndef ARENA_INCLUDED
#define ARENA_INCLUDED
#include "except.h"
#define T Arena_T
typedef struct T *T;
extern const Except_T Arena_NewFailed;
extern const Except_T Arena_Failed;
extern T Arena_new (void);
extern void Arena_dispose(T *ap);
extern void *Arena_alloc (T arena, long nbytes,
const char *file, int line);
extern void *Arena_calloc(T arena, long count,
long nbytes, const char *file, int line);
extern void Arena_free (T arena);
#undef T
#endif
arena.c
#include <stdlib.h>
#include <string.h>
#include "assert.h"
#include "except.h"
#include "arena.h"
#define T Arena_T
const Except_T Arena_NewFailed =
{ "Arena Creation Failed" };
const Except_T Arena_Failed =
{ "Arena Allocation Failed" };
#define THRESHOLD 10
struct T {
T prev;
char *avail;
char *limit;
};
union align {
#ifdef MAXALIGN
char pad[MAXALIGN];
#else
int i;
long l;
long *lp;
void *p;
void (*fp)(void);
float f;
double d;
long double ld;
#endif
};
union header {
struct T b;
union align a;
};
static T freechunks;
static int nfree;
T Arena_new(void) {
T arena = malloc(sizeof (*arena));
if (arena == NULL)
RAISE(Arena_NewFailed);
arena->prev = NULL;
arena->limit = arena->avail = NULL;
return arena;
}
void Arena_dispose(T *ap) {
assert(ap && *ap);
Arena_free(*ap);
free(*ap);
*ap = NULL;
}
void *Arena_alloc(T arena, long nbytes,
const char *file, int line) {
assert(arena);
assert(nbytes > 0);
nbytes = ((nbytes + sizeof (union align) - 1)/
(sizeof (union align)))*(sizeof (union align));
while (nbytes > arena->limit - arena->avail) {
T ptr;
char *limit;
if ((ptr = freechunks) != NULL) {
freechunks = freechunks->prev;
nfree--;
limit = ptr->limit;
} else {
long m = sizeof (union header) + nbytes + 10*1024;
ptr = malloc(m);
if (ptr == NULL)
{
if (file == NULL)
RAISE(Arena_Failed);
else
Except_raise(&Arena_Failed, file, line);
}
limit = (char *)ptr + m;
}
*ptr = *arena;
arena->avail = (char *)((union header *)ptr + 1);
arena->limit = limit;
arena->prev = ptr;
}
arena->avail += nbytes;
return arena->avail - nbytes;
}
void *Arena_calloc(T arena, long count, long nbytes,
const char *file, int line) {
void *ptr;
assert(count > 0);
ptr = Arena_alloc(arena, count*nbytes, file, line);
memset(ptr, '\0', count*nbytes);
return ptr;
}
void Arena_free(T arena) {
assert(arena);
while (arena->prev) {
struct T tmp = *arena->prev;
if (nfree < THRESHOLD) {
arena->prev->prev = freechunks;
freechunks = arena->prev;
nfree++;
freechunks->limit = arena->limit;
} else
free(arena->prev);
*arena = tmp;
}
assert(arena->limit == NULL);
assert(arena->avail == NULL);
}
第7章 链表
list.h
#ifndef LIST_INCLUDED
#define LIST_INCLUDED
#define T List_T
typedef struct T *T;
struct T {
T rest;
void *first;
};
extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
extern T List_pop (T list, void **x);
extern T List_push (T list, void *x);
extern T List_reverse(T list);
extern int List_length (T list);
extern void List_free (T *list);
extern void List_map (T list,
void apply(void **x, void *cl), void *cl);
extern void **List_toArray(T list, void *end);
#undef T
#endif
list.c
#include <stdarg.h>
#include <stddef.h>
#include "assert.h"
#include "mem.h"
#include "list.h"
#define T List_T
T List_push(T list, void *x) {
T p;
NEW(p);
p->first = x;
p->rest = list;
return p;
}
T List_list(void *x, ...) {
va_list ap;
T list, *p = &list;
va_start(ap, x);
for ( ; x; x = va_arg(ap, void *)) {
NEW(*p);
(*p)->first = x;
p = &(*p)->rest;
}
*p = NULL;
va_end(ap);
return list;
}
T List_append(T list, T tail) {
T *p = &list;
while (*p)
p = &(*p)->rest;
*p = tail;
return list;
}
T List_copy(T list) {
T head, *p = &head;
for ( ; list; list = list->rest) {
NEW(*p);
(*p)->first = list->first;
p = &(*p)->rest;
}
*p = NULL;
return head;
}
T List_pop(T list, void **x) {
if (list) {
T head = list->rest;
if (x)
*x = list->first;
FREE(list);
return head;
} else
return list;
}
T List_reverse(T list) {
T head = NULL, next;
for ( ; list; list = next) {
next = list->rest;
list->rest = head;
head = list;
}
return head;
}
int List_length(T list) {
int n;
for (n = 0; list; list = list->rest)
n++;
return n;
}
void List_free(T *list) {
T next;
assert(list);
for ( ; *list; *list = next) {
next = (*list)->rest;
FREE(*list);
}
}
void List_map(T list,
void apply(void **x, void *cl), void *cl) {
assert(apply);
for ( ; list; list = list->rest)
apply(&list->first, cl);
}
void **List_toArray(T list, void *end) {
int i, n = List_length(list);
void **array = ALLOC((n + 1)*sizeof (*array));
for (i = 0; i < n; i++) {
array[i] = list->first;
list = list->rest;
}
array[i] = end;
return array;
}
第8章 表格
table.h
#ifndef TABLE_INCLUDED
#define TABLE_INCLUDED
#define T Table_T
typedef struct T *T;
extern T Table_new (int hint,
int cmp(const void *x, const void *y),
unsigned hash(const void *key));
extern void Table_free(T *table);
extern int Table_length(T table);
extern void *Table_put (T table, const void *key,
void *value);
extern void *Table_get (T table, const void *key);
extern void *Table_remove(T table, const void *key);
extern void Table_map (T table,
void apply(const void *key, void **value, void *cl),
void *cl);
extern void **Table_toArray(T table, void *end);
#undef T
#endif
table.c
#include <limits.h>
#include <stddef.h>
#include "mem.h"
#include "assert.h"
#include "table.h"
#define T Table_T
struct T {
int size;
int (*cmp)(const void *x, const void *y);
unsigned (*hash)(const void *key);
int length;
unsigned timestamp;
struct binding {
struct binding *link;
const void *key;
void *value;
} **buckets;
};
static int cmpatom(const void *x, const void *y) {
return x != y;
}
static unsigned hashatom(const void *key) {
return (unsigned long)key>>2;
}
T Table_new(int hint,
int cmp(const void *x, const void *y),
unsigned hash(const void *key)) {
T table;
int i;
static int primes[] = { 509, 509, 1021, 2053, 4093,
8191, 16381, 32771, 65521, INT_MAX };
assert(hint >= 0);
for (i = 1; primes[i] < hint; i++)
;
table = ALLOC(sizeof (*table) +
primes[i-1]*sizeof (table->buckets[0]));
table->size = primes[i-1];
table->cmp = cmp ? cmp : cmpatom;
table->hash = hash ? hash : hashatom;
table->buckets = (struct binding **)(table + 1);
for (i = 0; i < table->size; i++)
table->buckets[i] = NULL;
table->length = 0;
table->timestamp = 0;
return table;
}
void *Table_get(T table, const void *key) {
int i;
struct binding *p;
assert(table);
assert(key);
i = (*table->hash)(key)%table->size;
for (p = table->buckets[i]; p; p = p->link)
if ((*table->cmp)(key, p->key) == 0)
break;
return p ? p->value : NULL;
}
void *Table_put(T table, const void *key, void *value) {
int i;
struct binding *p;
void *prev;
assert(table);
assert(key);
i = (*table->hash)(key)%table->size;
for (p = table->buckets[i]; p; p = p->link)
if ((*table->cmp)(key, p->key) == 0)
break;
if (p == NULL) {
NEW(p);
p->key = key;
p->link = table->buckets[i];
table->buckets[i] = p;
table->length++;
prev = NULL;
} else
prev = p->value;
p->value = value;
table->timestamp++;
return prev;
}
int Table_length(T table) {
assert(table);
return table->length;
}
void Table_map(T table,
void apply(const void *key, void **value, void *cl),
void *cl) {
int i;
unsigned stamp;
struct binding *p;
assert(table);
assert(apply);
stamp = table->timestamp;
for (i = 0; i < table->size; i++)
for (p = table->buckets[i]; p; p = p->link) {
apply(p->key, &p->value, cl);
assert(table->timestamp == stamp);
}
}
void *Table_remove(T table, const void *key) {
int i;
struct binding **pp;
assert(table);
assert(key);
table->timestamp++;
i = (*table->hash)(key)%table->size;
for (pp = &table->buckets[i]; *pp; pp = &(*pp)->link)
if ((*table->cmp)(key, (*pp)->key) == 0) {
struct binding *p = *pp;
void *value = p->value;
*pp = p->link;
FREE(p);
table->length--;
return value;
}
return NULL;
}
void **Table_toArray(T table, void *end) {
int i, j = 0;
void **array;
struct binding *p;
assert(table);
array = ALLOC((2*table->length + 1)*sizeof (*array));
for (i = 0; i < table->size; i++)
for (p = table->buckets[i]; p; p = p->link) {
array[j++] = (void *)p->key;
array[j++] = p->value;
}
array[j] = end;
return array;
}
void Table_free(T *table) {
assert(table && *table);
if ((*table)->length > 0) {
int i;
struct binding *p, *q;
for (i = 0; i < (*table)->size; i++)
for (p = (*table)->buckets[i]; p; p = q) {
q = p->link;
FREE(p);
}
}
FREE(*table);
}
wf程序来统计单词的频率
getword.c
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include "assert.h"
#include "getword.h"
int getword(FILE *fp, char *buf, int size,
int first(int c), int rest(int c)) {
int i = 0, c;
assert(fp && buf && size > 1 && first && rest);
c = getc(fp);
for ( ; c != EOF; c = getc(fp))
if (first(c)) {
{
if (i < size - 1)
buf[i++] = c;
}
c = getc(fp);
break;
}
for ( ; c != EOF && rest(c); c = getc(fp))
{
if (i < size - 1)
buf[i++] = c;
}
if (i < size)
buf[i] = '\0';
else
buf[size-1] = '\0';
if (c != EOF)
ungetc(c, fp);
return i > 0;
}
wf.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include "atom.h"
#include "table.h"
#include "mem.h"
#include "getword.h"
#include <string.h>
void wf(char *, FILE *);
int first(int c);
int rest (int c);
int compare(const void *x, const void *y);
void vfree(const void *, void **, void *);
int main(int argc, char *argv[]) {
int i;
for (i = 1; i < argc; i++) {
FILE *fp = fopen(argv[i], "r");
if (fp == NULL) {
fprintf(stderr, "%s: can't open '%s' (%s)\n",
argv[0], argv[i], strerror(errno));
return EXIT_FAILURE;
} else {
wf(argv[i], fp);
fclose(fp);
}
}
if (argc == 1) wf(NULL, stdin);
return EXIT_SUCCESS;
}
void wf(char *name, FILE *fp) {
Table_T table = Table_new(0, NULL, NULL);
char buf[128];
while (getword(fp, buf, sizeof buf, first, rest)) {
const char *word;
int i, *count;
for (i = 0; buf[i] != '\0'; i++)
buf[i] = tolower(buf[i]);
word = Atom_string(buf);
count = Table_get(table, word);
if (count)
(*count)++;
else {
NEW(count);
*count = 1;
Table_put(table, word, count);
}
}
if (name)
printf("%s:\n", name);
{ int i;
void **array = Table_toArray(table, NULL);
qsort(array, Table_length(table), 2*sizeof (*array),
compare);
for (i = 0; array[i]; i += 2)
printf("%d\t%s\n", *(int *)array[i+1],
(char *)array[i]);
FREE(array); }
Table_map(table, vfree, NULL);
Table_free(&table);
}
int first(int c) {
return isalpha(c);
}
int rest(int c) {
return isalpha(c) || c == '_';
}
int compare(const void *x, const void *y) {
return strcmp(*(char **)x, *(char **)y);
}
void vfree(const void *key, void **count, void *cl) {
FREE(*count);
}
第9章 集合
集合的实现
set.h
#ifndef SET_INCLUDED
#define SET_INCLUDED
#define T Set_T
typedef struct T *T;
extern T Set_new (int hint,
int cmp(const void *x, const void *y),
unsigned hash(const void *x));
extern void Set_free(T *set);
extern int Set_length(T set);
extern int Set_member(T set, const void *member);
extern void Set_put (T set, const void *member);
extern void *Set_remove(T set, const void *member);
extern void Set_map (T set,
void apply(const void *member, void *cl), void *cl);
extern void **Set_toArray(T set, void *end);
extern T Set_union(T s, T t);
extern T Set_inter(T s, T t);
extern T Set_minus(T s, T t);
extern T Set_diff (T s, T t);
#undef T
#endif
set.c
#include <limits.h>
#include <stddef.h>
#include "mem.h"
#include "assert.h"
#include "arith.h"
#include "set.h"
#define T Set_T
struct T {
int length;
unsigned timestamp;
int (*cmp)(const void *x, const void *y);
unsigned (*hash)(const void *x);
int size;
struct member {
struct member *link;
const void *member;
} **buckets;
};
static int cmpatom(const void *x, const void *y) {
return x != y;
}
static unsigned hashatom(const void *x) {
return (unsigned long)x>>2;
}
static T copy(T t, int hint) {
T set;
assert(t);
set = Set_new(hint, t->cmp, t->hash);
{ int i;
struct member *q;
for (i = 0; i < t->size; i++)
for (q = t->buckets[i]; q; q = q->link)
{
struct member *p;
const void *member = q->member;
int i = (*set->hash)(member)%set->size;
NEW(p);
p->member = member;
p->link = set->buckets[i];
set->buckets[i] = p;
set->length++;
}
}
return set;
}
T Set_new(int hint,
int cmp(const void *x, const void *y),
unsigned hash(const void *x)) {
T set;
int i;
static int primes[] = { 509, 509, 1021, 2053, 4093,
8191, 16381, 32771, 65521, INT_MAX };
assert(hint >= 0);
for (i = 1; primes[i] < hint; i++)
;
set = ALLOC(sizeof (*set) +
primes[i-1]*sizeof (set->buckets[0]));
set->size = primes[i-1];
set->cmp = cmp ? cmp : cmpatom;
set->hash = hash ? hash : hashatom;
set->buckets = (struct member **)(set + 1);
for (i = 0; i < set->size; i++)
set->buckets[i] = NULL;
set->length = 0;
set->timestamp = 0;
return set;
}
int Set_member(T set, const void *member) {
int i;
struct member *p;
assert(set);
assert(member);
i = (*set->hash)(member)%set->size;
for (p = set->buckets[i]; p; p = p->link)
if ((*set->cmp)(member, p->member) == 0)
break;
return p != NULL;
}
void Set_put(T set, const void *member) {
int i;
struct member *p;
assert(set);
assert(member);
i = (*set->hash)(member)%set->size;
for (p = set->buckets[i]; p; p = p->link)
if ((*set->cmp)(member, p->member) == 0)
break;
if (p == NULL) {
NEW(p);
p->member = member;
p->link = set->buckets[i];
set->buckets[i] = p;
set->length++;
} else
p->member = member;
set->timestamp++;
}
void *Set_remove(T set, const void *member) {
int i;
struct member **pp;
assert(set);
assert(member);
set->timestamp++;
i = (*set->hash)(member)%set->size;
for (pp = &set->buckets[i]; *pp; pp = &(*pp)->link)
if ((*set->cmp)(member, (*pp)->member) == 0) {
struct member *p = *pp;
*pp = p->link;
member = p->member;
FREE(p);
set->length--;
return (void *)member;
}
return NULL;
}
int Set_length(T set) {
assert(set);
return set->length;
}
void Set_free(T *set) {
assert(set && *set);
if ((*set)->length > 0) {
int i;
struct member *p, *q;
for (i = 0; i < (*set)->size; i++)
for (p = (*set)->buckets[i]; p; p = q) {
q = p->link;
FREE(p);
}
}
FREE(*set);
}
void Set_map(T set,
void apply(const void *member, void *cl), void *cl) {
int i;
unsigned stamp;
struct member *p;
assert(set);
assert(apply);
stamp = set->timestamp;
for (i = 0; i < set->size; i++)
for (p = set->buckets[i]; p; p = p->link) {
apply(p->member, cl);
assert(set->timestamp == stamp);
}
}
void **Set_toArray(T set, void *end) {
int i, j = 0;
void **array;
struct member *p;
assert(set);
array = ALLOC((set->length + 1)*sizeof (*array));
for (i = 0; i < set->size; i++)
for (p = set->buckets[i]; p; p = p->link)
array[j++] = (void *)p->member;
array[j] = end;
return array;
}
T Set_union(T s, T t) {
if (s == NULL) {
assert(t);
return copy(t, t->size);
} else if (t == NULL)
return copy(s, s->size);
else {
T set = copy(s, Arith_max(s->size, t->size));
assert(s->cmp == t->cmp && s->hash == t->hash);
{ int i;
struct member *q;
for (i = 0; i < t->size; i++)
for (q = t->buckets[i]; q; q = q->link)
Set_put(set, q->member);
}
return set;
}
}
T Set_inter(T s, T t) {
if (s == NULL) {
assert(t);
return Set_new(t->size, t->cmp, t->hash);
} else if (t == NULL)
return Set_new(s->size, s->cmp, s->hash);
else if (s->length < t->length)
return Set_inter(t, s);
else {
T set = Set_new(Arith_min(s->size, t->size),
s->cmp, s->hash);
assert(s->cmp == t->cmp && s->hash == t->hash);
{ int i;
struct member *q;
for (i = 0; i < t->size; i++)
for (q = t->buckets[i]; q; q = q->link)
if (Set_member(s, q->member))
{
struct member *p;
const void *member = q->member;
int i = (*set->hash)(member)%set->size;
NEW(p);
p->member = member;
p->link = set->buckets[i];
set->buckets[i] = p;
set->length++;
}
}
return set;
}
}
T Set_minus(T t, T s) {
if (t == NULL){
assert(s);
return Set_new(s->size, s->cmp, s->hash);
} else if (s == NULL)
return copy(t, t->size);
else {
T set = Set_new(Arith_min(s->size, t->size),
s->cmp, s->hash);
assert(s->cmp == t->cmp && s->hash == t->hash);
{ int i;
struct member *q;
for (i = 0; i < t->size; i++)
for (q = t->buckets[i]; q; q = q->link)
if (!Set_member(s, q->member))
{
struct member *p;
const void *member = q->member;
int i = (*set->hash)(member)%set->size;
NEW(p);
p->member = member;
p->link = set->buckets[i];
set->buckets[i] = p;
set->length++;
}
}
return set;
}
}
T Set_diff(T s, T t) {
if (s == NULL) {
assert(t);
return copy(t, t->size);
} else if (t == NULL)
return copy(s, s->size);
else {
T set = Set_new(Arith_min(s->size, t->size),
s->cmp, s->hash);
assert(s->cmp == t->cmp && s->hash == t->hash);
{ int i;
struct member *q;
for (i = 0; i < t->size; i++)
for (q = t->buckets[i]; q; q = q->link)
if (!Set_member(s, q->member))
{
struct member *p;
const void *member = q->member;
int i = (*set->hash)(member)%set->size;
NEW(p);
p->member = member;
p->link = set->buckets[i];
set->buckets[i] = p;
set->length++;
}
}
{ T u = t; t = s; s = u; }
{ int i;
struct member *q;
for (i = 0; i < t->size; i++)
for (q = t->buckets[i]; q; q = q->link)
if (!Set_member(s, q->member))
{
struct member *p;
const void *member = q->member;
int i = (*set->hash)(member)%set->size;
NEW(p);
p->member = member;
p->link = set->buckets[i];
set->buckets[i] = p;
set->length++;
}
}
return set;
}
}
实例:交叉引用列表
xref.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "table.h"
#include <string.h>
#include "atom.h"
#include "set.h"
#include "mem.h"
#include "getword.h"
#include <ctype.h>
int compare(const void *x, const void *y);
void print(Table_T);
int cmpint(const void *x, const void *y);
void xref(const char *, FILE *, Table_T);
int first(int c);
int rest (int c);
int intcmp (const void *x, const void *y);
unsigned inthash(const void *x);
int linenum;
int main(int argc, char *argv[]) {
int i;
Table_T identifiers = Table_new(0, NULL, NULL);
for (i = 1; i < argc; i++) {
FILE *fp = fopen(argv[i], "r");
if (fp == NULL) {
fprintf(stderr, "%s: can't open '%s' (%s)\n",
argv[0], argv[i], strerror(errno));
return EXIT_FAILURE;
} else {
xref(argv[i], fp, identifiers);
fclose(fp);
}
}
if (argc == 1) xref(NULL, stdin, identifiers);
{
int i;
void **array = Table_toArray(identifiers, NULL);
qsort(array, Table_length(identifiers),
2*sizeof (*array), compare);
for (i = 0; array[i]; i += 2) {
printf("%s", (char *)array[i]);
print(array[i+1]);
}
FREE(array);
}
return EXIT_SUCCESS;
}
int compare(const void *x, const void *y) {
return strcmp(*(char **)x, *(char **)y);
}
void print(Table_T files) {
int i;
void **array = Table_toArray(files, NULL);
qsort(array, Table_length(files), 2*sizeof (*array),
compare);
for (i = 0; array[i]; i += 2) {
if (*(char *)array[i] != '\0')
printf("\t%s:", (char *)array[i]);
{
int j;
void **lines = Set_toArray(array[i+1], NULL);
qsort(lines, Set_length(array[i+1]), sizeof (*lines),
cmpint);
for (j = 0; lines[j]; j++)
printf(" %d", *(int *)lines[j]);
FREE(lines);
}
printf("\n");
}
FREE(array);
}
int cmpint(const void *x, const void *y) {
if (**(int **)x < **(int **)y)
return -1;
else if (**(int **)x > **(int **)y)
return +1;
else
return 0;
}
void xref(const char *name, FILE *fp,
Table_T identifiers){
char buf[128];
if (name == NULL)
name = "";
name = Atom_string(name);
linenum = 1;
while (getword(fp, buf, sizeof buf, first, rest)) {
Set_T set;
Table_T files;
const char *id = Atom_string(buf);
files = Table_get(identifiers, id);
if (files == NULL) {
files = Table_new(0, NULL, NULL);
Table_put(identifiers, id, files);
}
set = Table_get(files, name);
if (set == NULL) {
set = Set_new(0, intcmp, inthash);
Table_put(files, name, set);
}
{
int *p = &linenum;
if (!Set_member(set, p)) {
NEW(p);
*p = linenum;
Set_put(set, p);
}
}
}
}
int first(int c) {
if (c == '\n')
linenum++;
return isalpha(c) || c == '_';
}
int rest(int c) {
return isalpha(c) || c == '_' || isdigit(c);
}
int intcmp(const void *x, const void *y) {
return cmpint(&x, &y);
}
unsigned inthash(const void *x) {
return *(int *)x;
}
第10章 动态数组
array.h
#ifndef ARRAY_INCLUDED
#define ARRAY_INCLUDED
#define T Array_T
typedef struct T *T;
extern T Array_new (int length, int size);
extern void Array_free(T *array);
extern int Array_length(T array);
extern int Array_size (T array);
extern void *Array_get(T array, int i);
extern void *Array_put(T array, int i, void *elem);
extern void Array_resize(T array, int length);
extern T Array_copy (T array, int length);
#undef T
#endif
array.c
#include <stdlib.h>
#include <string.h>
#include "assert.h"
#include "array.h"
#include "arrayrep.h"
#include "mem.h"
#define T Array_T
T Array_new(int length, int size) {
T array;
NEW(array);
if (length > 0)
ArrayRep_init(array, length, size,
CALLOC(length, size));
else
ArrayRep_init(array, length, size, NULL);
return array;
}
void ArrayRep_init(T array, int length, int size,
void *ary) {
assert(array);
assert(ary && length>0 || length==0 && ary==NULL);
assert(size > 0);
array->length = length;
array->size = size;
if (length > 0)
array->array = ary;
else
array->array = NULL;
}
void Array_free(T *array) {
assert(array && *array);
FREE((*array)->array);
FREE(*array);
}
void *Array_get(T array, int i) {
assert(array);
assert(i >= 0 && i < array->length);
return array->array + i*array->size;
}
void *Array_put(T array, int i, void *elem) {
assert(array);
assert(i >= 0 && i < array->length);
assert(elem);
memcpy(array->array + i*array->size, elem,
array->size);
return elem;
}
int Array_length(T array) {
assert(array);
return array->length;
}
int Array_size(T array) {
assert(array);
return array->size;
}
void Array_resize(T array, int length) {
assert(array);
assert(length >= 0);
if (length == 0)
FREE(array->array);
else if (array->length == 0)
array->array = ALLOC(length*array->size);
else
RESIZE(array->array, length*array->size);
array->length = length;
}
T Array_copy(T array, int length) {
T copy;
assert(array);
assert(length >= 0);
copy = Array_new(length, array->size);
if (copy->length >= array->length
&& array->length > 0)
memcpy(copy->array, array->array, array->length);
else if (array->length > copy->length
&& copy->length > 0)
memcpy(copy->array, array->array, copy->length);
return copy;
}
第11章 序列
seq.h
#ifndef SEQ_INCLUDED
#define SEQ_INCLUDED
#define T Seq_T
typedef struct T *T;
extern T Seq_new(int hint);
extern T Seq_seq(void *x, ...);
extern void Seq_free(T *seq);
extern int Seq_length(T seq);
extern void *Seq_get(T seq, int i);
extern void *Seq_put(T seq, int i, void *x);
extern void *Seq_addlo(T seq, void *x);
extern void *Seq_addhi(T seq, void *x);
extern void *Seq_remlo(T seq);
extern void *Seq_remhi(T seq);
#undef T
#endif
seq.c
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "assert.h"
#include "seq.h"
#include "array.h"
#include "arrayrep.h"
#include "mem.h"
#define T Seq_T
struct T {
struct Array_T array;
int length;
int head;
};
static void expand(T seq) {
int n = seq->array.length;
Array_resize(&seq->array, 2*n);
if (seq->head > 0)
{
void **old = &((void **)seq->array.array)[seq->head];
memcpy(old+n, old, (n - seq->head)*sizeof (void *));
seq->head += n;
}
}
T Seq_new(int hint) {
T seq;
assert(hint >= 0);
NEW0(seq);
if (hint == 0)
hint = 16;
ArrayRep_init(&seq->array, hint, sizeof (void *),
ALLOC(hint*sizeof (void *)));
return seq;
}
T Seq_seq(void *x, ...) {
va_list ap;
T seq = Seq_new(0);
va_start(ap, x);
for ( ; x; x = va_arg(ap, void *))
Seq_addhi(seq, x);
va_end(ap);
return seq;
}
void Seq_free(T *seq) {
assert(seq && *seq);
assert((void *)*seq == (void *)&(*seq)->array);
Array_free((Array_T *)seq);
}
int Seq_length(T seq) {
assert(seq);
return seq->length;
}
void *Seq_get(T seq, int i) {
assert(seq);
assert(i >= 0 && i < seq->length);
return ((void **)seq->array.array)[
(seq->head + i)%seq->array.length];
}
void *Seq_put(T seq, int i, void *x) {
void *prev;
assert(seq);
assert(i >= 0 && i < seq->length);
prev = ((void **)seq->array.array)[
(seq->head + i)%seq->array.length];
((void **)seq->array.array)[
(seq->head + i)%seq->array.length] = x;
return prev;
}
void *Seq_remhi(T seq) {
int i;
assert(seq);
assert(seq->length > 0);
i = --seq->length;
return ((void **)seq->array.array)[
(seq->head + i)%seq->array.length];
}
void *Seq_remlo(T seq) {
int i = 0;
void *x;
assert(seq);
assert(seq->length > 0);
x = ((void **)seq->array.array)[
(seq->head + i)%seq->array.length];
seq->head = (seq->head + 1)%seq->array.length;
--seq->length;
return x;
}
void *Seq_addhi(T seq, void *x) {
int i;
assert(seq);
if (seq->length == seq->array.length)
expand(seq);
i = seq->length++;
return ((void **)seq->array.array)[
(seq->head + i)%seq->array.length] = x;
}
void *Seq_addlo(T seq, void *x) {
int i = 0;
assert(seq);
if (seq->length == seq->array.length)
expand(seq);
if (--seq->head < 0)
seq->head = seq->array.length - 1;
seq->length++;
return ((void **)seq->array.array)[
(seq->head + i)%seq->array.length] = x;
}
第12章 环
ring.h
#ifndef RING_INCLUDED
#define RING_INCLUDED
#define T Ring_T
typedef struct T *T;
extern T Ring_new (void);
extern T Ring_ring(void *x, ...);
extern void Ring_free (T *ring);
extern int Ring_length(T ring);
extern void *Ring_get(T ring, int i);
extern void *Ring_put(T ring, int i, void *x);
extern void *Ring_add(T ring, int pos, void *x);
extern void *Ring_addlo(T ring, void *x);
extern void *Ring_addhi(T ring, void *x);
extern void *Ring_remove(T ring, int i);
extern void *Ring_remlo(T ring);
extern void *Ring_remhi(T ring);
extern void Ring_rotate(T ring, int n);
#undef T
#endif
ring.c
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "assert.h"
#include "ring.h"
#include "mem.h"
#define T Ring_T
struct T {
struct node {
struct node *llink, *rlink;
void *value;
} *head;
int length;
};
T Ring_new(void) {
T ring;
NEW0(ring);
ring->head = NULL;
return ring;
}
T Ring_ring(void *x, ...) {
va_list ap;
T ring = Ring_new();
va_start(ap, x);
for ( ; x; x = va_arg(ap, void *))
Ring_addhi(ring, x);
va_end(ap);
return ring;
}
void Ring_free(T *ring) {
struct node *p, *q;
assert(ring && *ring);
if ((p = (*ring)->head) != NULL) {
int n = (*ring)->length;
for ( ; n-- > 0; p = q) {
q = p->rlink;
FREE(p);
}
}
FREE(*ring);
}
int Ring_length(T ring) {
assert(ring);
return ring->length;
}
void *Ring_get(T ring, int i) {
struct node *q;
assert(ring);
assert(i >= 0 && i < ring->length);
{
int n;
q = ring->head;
if (i <= ring->length/2)
for (n = i; n-- > 0; )
q = q->rlink;
else
for (n = ring->length - i; n-- > 0; )
q = q->llink;
}
return q->value;
}
void *Ring_put(T ring, int i, void *x) {
struct node *q;
void *prev;
assert(ring);
assert(i >= 0 && i < ring->length);
{
int n;
q = ring->head;
if (i <= ring->length/2)
for (n = i; n-- > 0; )
q = q->rlink;
else
for (n = ring->length - i; n-- > 0; )
q = q->llink;
}
prev = q->value;
q->value = x;
return prev;
}
void *Ring_addhi(T ring, void *x) {
struct node *p, *q;
assert(ring);
NEW(p);
if ((q = ring->head) != NULL)
{
p->llink = q->llink;
q->llink->rlink = p;
p->rlink = q;
q->llink = p;
}
else
ring->head = p->llink = p->rlink = p;
ring->length++;
return p->value = x;
}
void *Ring_addlo(T ring, void *x) {
assert(ring);
Ring_addhi(ring, x);
ring->head = ring->head->llink;
return x;
}
void *Ring_add(T ring, int pos, void *x) {
assert(ring);
assert(pos >= -ring->length && pos<=ring->length+1);
if (pos == 1 || pos == -ring->length)
return Ring_addlo(ring, x);
else if (pos == 0 || pos == ring->length + 1)
return Ring_addhi(ring, x);
else {
struct node *p, *q;
int i = pos < 0 ? pos + ring->length : pos - 1;
{
int n;
q = ring->head;
if (i <= ring->length/2)
for (n = i; n-- > 0; )
q = q->rlink;
else
for (n = ring->length - i; n-- > 0; )
q = q->llink;
}
NEW(p);
{
p->llink = q->llink;
q->llink->rlink = p;
p->rlink = q;
q->llink = p;
}
ring->length++;
return p->value = x;
}
}
void *Ring_remove(T ring, int i) {
void *x;
struct node *q;
assert(ring);
assert(ring->length > 0);
assert(i >= 0 && i < ring->length);
{
int n;
q = ring->head;
if (i <= ring->length/2)
for (n = i; n-- > 0; )
q = q->rlink;
else
for (n = ring->length - i; n-- > 0; )
q = q->llink;
}
if (i == 0)
ring->head = ring->head->rlink;
x = q->value;
q->llink->rlink = q->rlink;
q->rlink->llink = q->llink;
FREE(q);
if (--ring->length == 0)
ring->head = NULL;
return x;
}
void *Ring_remhi(T ring) {
void *x;
struct node *q;
assert(ring);
assert(ring->length > 0);
q = ring->head->llink;
x = q->value;
q->llink->rlink = q->rlink;
q->rlink->llink = q->llink;
FREE(q);
if (--ring->length == 0)
ring->head = NULL;
return x;
}
void *Ring_remlo(T ring) {
assert(ring);
assert(ring->length > 0);
ring->head = ring->head->rlink;
return Ring_remhi(ring);
}
void Ring_rotate(T ring, int n) {
struct node *q;
int i;
assert(ring);
assert(n >= -ring->length && n <= ring->length);
if (n >= 0)
i = n%ring->length;
else
i = n + ring->length;
{
int n;
q = ring->head;
if (i <= ring->length/2)
for (n = i; n-- > 0; )
q = q->rlink;
else
for (n = ring->length - i; n-- > 0; )
q = q->llink;
}
ring->head = q;
}
第13章 位向量
bit.h
#ifndef BIT_INCLUDED
#define BIT_INCLUDED
#define T Bit_T
typedef struct T *T;
extern T Bit_new (int length);
extern int Bit_length(T set);
extern int Bit_count (T set);
extern void Bit_free(T *set);
extern int Bit_get(T set, int n);
extern int Bit_put(T set, int n, int bit);
extern void Bit_clear(T set, int lo, int hi);
extern void Bit_set (T set, int lo, int hi);
extern void Bit_not (T set, int lo, int hi);
extern int Bit_lt (T s, T t);
extern int Bit_eq (T s, T t);
extern int Bit_leq(T s, T t);
extern void Bit_map(T set,
void apply(int n, int bit, void *cl), void *cl);
extern T Bit_union(T s, T t);
extern T Bit_inter(T s, T t);
extern T Bit_minus(T s, T t);
extern T Bit_diff (T s, T t);
#undef T
#endif
bit.c
#include <stdarg.h>
#include <string.h>
#include "assert.h"
#include "bit.h"
#include "mem.h"
#define T Bit_T
struct T {
int length;
unsigned char *bytes;
unsigned long *words;
};
#define BPW (8*sizeof (unsigned long))
#define nwords(len) ((((len) + BPW - 1)&(~(BPW-1)))/BPW)
#define nbytes(len) ((((len) + 8 - 1)&(~(8-1)))/8)
#define setop(sequal, snull, tnull, op) \
if (s == t) { assert(s); return sequal; } \
else if (s == NULL) { assert(t); return snull; } \
else if (t == NULL) return tnull; \
else { \
int i; T set; \
assert(s->length == t->length); \
set = Bit_new(s->length); \
for (i = nwords(s->length); --i >= 0; ) \
set->words[i] = s->words[i] op t->words[i]; \
return set; }
unsigned char msbmask[] = {
0xFF, 0xFE, 0xFC, 0xF8,
0xF0, 0xE0, 0xC0, 0x80
};
unsigned char lsbmask[] = {
0x01, 0x03, 0x07, 0x0F,
0x1F, 0x3F, 0x7F, 0xFF
};
static T copy(T t) {
T set;
assert(t);
set = Bit_new(t->length);
if (t->length > 0)
memcpy(set->bytes, t->bytes, nbytes(t->length));
return set;
}
T Bit_new(int length) {
T set;
assert(length >= 0);
NEW(set);
if (length > 0)
set->words = CALLOC(nwords(length),
sizeof (unsigned long));
else
set->words = NULL;
set->bytes = (unsigned char *)set->words;
set->length = length;
return set;
}
void Bit_free(T *set) {
assert(set && *set);
FREE((*set)->words);
FREE(*set);
}
int Bit_length(T set) {
assert(set);
return set->length;
}
int Bit_count(T set) {
int length = 0, n;
static char count[] = {
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
assert(set);
for (n = nbytes(set->length); --n >= 0; ) {
unsigned char c = set->bytes[n];
length += count[c&0xF] + count[c>>4];
}
return length;
}
int Bit_get(T set, int n) {
assert(set);
assert(0 <= n && n < set->length);
return ((set->bytes[n/8]>>(n%8))&1);
}
int Bit_put(T set, int n, int bit) {
int prev;
assert(set);
assert(bit == 0 || bit == 1);
assert(0 <= n && n < set->length);
prev = ((set->bytes[n/8]>>(n%8))&1);
if (bit == 1)
set->bytes[n/8] |= 1<<(n%8);
else
set->bytes[n/8] &= ~(1<<(n%8));
return prev;
}
void Bit_set(T set, int lo, int hi) {
assert(set);
assert(0 <= lo && hi < set->length);
assert(lo <= hi);
if (lo/8 < hi/8) {
set->bytes[lo/8] |= msbmask[lo%8];
{
int i;
for (i = lo/8+1; i < hi/8; i++)
set->bytes[i] = 0xFF;
}
set->bytes[hi/8] |= lsbmask[hi%8];
} else
set->bytes[lo/8] |= (msbmask[lo%8]&lsbmask[hi%8]);
}
void Bit_clear(T set, int lo, int hi) {
assert(set);
assert(0 <= lo && hi < set->length);
assert(lo <= hi);
if (lo/8 < hi/8) {
int i;
set->bytes[lo/8] &= ~msbmask[lo%8];
for (i = lo/8+1; i < hi/8; i++)
set->bytes[i] = 0;
set->bytes[hi/8] &= ~lsbmask[hi%8];
} else
set->bytes[lo/8] &= ~(msbmask[lo%8]&lsbmask[hi%8]);
}
void Bit_not(T set, int lo, int hi) {
assert(set);
assert(0 <= lo && hi < set->length);
assert(lo <= hi);
if (lo/8 < hi/8) {
int i;
set->bytes[lo/8] ^= msbmask[lo%8];
for (i = lo/8+1; i < hi/8; i++)
set->bytes[i] ^= 0xFF;
set->bytes[hi/8] ^= lsbmask[hi%8];
} else
set->bytes[lo/8] ^= (msbmask[lo%8]&lsbmask[hi%8]);
}
void Bit_map(T set,
void apply(int n, int bit, void *cl), void *cl) {
int n;
assert(set);
for (n = 0; n < set->length; n++)
apply(n, ((set->bytes[n/8]>>(n%8))&1), cl);
}
int Bit_eq(T s, T t) {
int i;
assert(s && t);
assert(s->length == t->length);
for (i = nwords(s->length); --i >= 0; )
if (s->words[i] != t->words[i])
return 0;
return 1;
}
int Bit_leq(T s, T t) {
int i;
assert(s && t);
assert(s->length == t->length);
for (i = nwords(s->length); --i >= 0; )
if ((s->words[i]&~t->words[i]) != 0)
return 0;
return 1;
}
int Bit_lt(T s, T t) {
int i, lt = 0;
assert(s && t);
assert(s->length == t->length);
for (i = nwords(s->length); --i >= 0; )
if ((s->words[i]&~t->words[i]) != 0)
return 0;
else if (s->words[i] != t->words[i])
lt |= 1;
return lt;
}
T Bit_union(T s, T t) {
setop(copy(t), copy(t), copy(s), |)
}
T Bit_inter(T s, T t) {
setop(copy(t),
Bit_new(t->length), Bit_new(s->length), &)
}
T Bit_minus(T s, T t) {
setop(Bit_new(s->length),
Bit_new(t->length), copy(s), & ~)
}
T Bit_diff(T s, T t) {
setop(Bit_new(s->length), copy(t), copy(s), ^)
}
fmt.h
#ifndef FMT_INCLUDED
#define FMT_INCLUDED
#include <stdarg.h>
#include <stdio.h>
#include "except.h"
#define T Fmt_T
typedef void (*T)(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[256], int width, int precision);
extern char *Fmt_flags;
extern const Except_T Fmt_Overflow;
extern void Fmt_fmt (int put(int c, void *cl), void *cl,
const char *fmt, ...);
extern void Fmt_vfmt(int put(int c, void *cl), void *cl,
const char *fmt, va_list ap);
extern void Fmt_print (const char *fmt, ...);
extern void Fmt_fprint(FILE *stream,
const char *fmt, ...);
extern int Fmt_sfmt (char *buf, int size,
const char *fmt, ...);
extern int Fmt_vsfmt(char *buf, int size,
const char *fmt, va_list ap);
extern char *Fmt_string (const char *fmt, ...);
extern char *Fmt_vstring(const char *fmt, va_list ap);
extern T Fmt_register(int code, T cvt);
extern void Fmt_putd(const char *str, int len,
int put(int c, void *cl), void *cl,
unsigned char flags[256], int width, int precision);
extern void Fmt_puts(const char *str, int len,
int put(int c, void *cl), void *cl,
unsigned char flags[256], int width, int precision);
#undef T
#endif
fmt.c
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <float.h>
#include <ctype.h>
#include <math.h>
#include "assert.h"
#include "except.h"
#include "fmt.h"
#include "mem.h"
#define T Fmt_T
struct buf {
char *buf;
char *bp;
int size;
};
#define pad(n,c) do { int nn = (n); \
while (nn-- > 0) \
put((c), cl); } while (0)
static void cvt_s(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
char *str = va_arg(*app, char *);
assert(str);
Fmt_puts(str, strlen(str), put, cl, flags,
width, precision);
}
static void cvt_d(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
int val = va_arg(*app, int);
unsigned m;
char buf[43];
char *p = buf + sizeof buf;
if (val == INT_MIN)
m = INT_MAX + 1U;
else if (val < 0)
m = -val;
else
m = val;
do
*--p = m%10 + '0';
while ((m /= 10) > 0);
if (val < 0)
*--p = '-';
Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
width, precision);
}
static void cvt_u(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
unsigned m = va_arg(*app, unsigned);
char buf[43];
char *p = buf + sizeof buf;
do
*--p = m%10 + '0';
while ((m /= 10) > 0);
Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
width, precision);
}
static void cvt_o(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
unsigned m = va_arg(*app, unsigned);
char buf[43];
char *p = buf + sizeof buf;
do
*--p = (m&0x7) + '0';
while ((m>>= 3) != 0);
Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
width, precision);
}
static void cvt_x(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
unsigned m = va_arg(*app, unsigned);
char buf[43];
char *p = buf + sizeof buf;
do
*--p = "0123456789abcdef"[m&0xf];
while ((m>>= 4) != 0);
Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
width, precision);
}
static void cvt_p(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
unsigned long m = (unsigned long)va_arg(*app, void*);
char buf[43];
char *p = buf + sizeof buf;
precision = INT_MIN;
do
*--p = "0123456789abcdef"[m&0xf];
while ((m>>= 4) != 0);
Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
width, precision);
}
static void cvt_c(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
if (width == INT_MIN)
width = 0;
if (width < 0) {
flags['-'] = 1;
width = -width;
}
if (!flags['-'])
pad(width - 1, ' ');
put((unsigned char)va_arg(*app, int), cl);
if ( flags['-'])
pad(width - 1, ' ');
}
static void cvt_f(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
char buf[DBL_MAX_10_EXP+1+1+99+1];
if (precision < 0)
precision = 6;
if (code == 'g' && precision == 0)
precision = 1;
{
static char fmt[] = "%.dd?";
assert(precision <= 99);
fmt[4] = code;
fmt[3] = precision%10 + '0';
fmt[2] = (precision/10)%10 + '0';
sprintf(buf, fmt, va_arg(*app, double));
}
Fmt_putd(buf, strlen(buf), put, cl, flags,
width, precision);
}
const Except_T Fmt_Overflow = { "Formatting Overflow" };
static T cvt[256] = {
/* 0- 7 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 8- 15 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 16- 23 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 24- 31 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 32- 39 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 40- 47 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 48- 55 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 56- 63 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 64- 71 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 72- 79 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 80- 87 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 88- 95 */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 96-103 */ 0, 0, 0, cvt_c, cvt_d, cvt_f, cvt_f, cvt_f,
/* 104-111 */ 0, 0, 0, 0, 0, 0, 0, cvt_o,
/* 112-119 */ cvt_p, 0, 0, cvt_s, 0, cvt_u, 0, 0,
/* 120-127 */ cvt_x, 0, 0, 0, 0, 0, 0, 0
};
char *Fmt_flags = "-+ 0";
static int outc(int c, void *cl) {
FILE *f = cl;
return putc(c, f);
}
static int insert(int c, void *cl) {
struct buf *p = cl;
if (p->bp >= p->buf + p->size)
RAISE(Fmt_Overflow);
*p->bp++ = c;
return c;
}
static int append(int c, void *cl) {
struct buf *p = cl;
if (p->bp >= p->buf + p->size) {
RESIZE(p->buf, 2*p->size);
p->bp = p->buf + p->size;
p->size *= 2;
}
*p->bp++ = c;
return c;
}
void Fmt_puts(const char *str, int len,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
assert(str);
assert(len >= 0);
assert(flags);
if (width == INT_MIN)
width = 0;
if (width < 0) {
flags['-'] = 1;
width = -width;
}
if (precision >= 0)
flags['0'] = 0;
if (precision >= 0 && precision < len)
len = precision;
if (!flags['-'])
pad(width - len, ' ');
{
int i;
for (i = 0; i < len; i++)
put((unsigned char)*str++, cl);
}
if ( flags['-'])
pad(width - len, ' ');
}
void Fmt_fmt(int put(int c, void *), void *cl,
const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
Fmt_vfmt(put, cl, fmt, ap);
va_end(ap);
}
void Fmt_print(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
Fmt_vfmt(outc, stdout, fmt, ap);
va_end(ap);
}
void Fmt_fprint(FILE *stream, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
Fmt_vfmt(outc, stream, fmt, ap);
va_end(ap);
}
int Fmt_sfmt(char *buf, int size, const char *fmt, ...) {
va_list ap;
int len;
va_start(ap, fmt);
len = Fmt_vsfmt(buf, size, fmt, ap);
va_end(ap);
return len;
}
int Fmt_vsfmt(char *buf, int size, const char *fmt,
va_list ap) {
struct buf cl;
assert(buf);
assert(size > 0);
assert(fmt);
cl.buf = cl.bp = buf;
cl.size = size;
Fmt_vfmt(insert, &cl, fmt, ap);
insert(0, &cl);
return cl.bp - cl.buf - 1;
}
char *Fmt_string(const char *fmt, ...) {
char *str;
va_list ap;
assert(fmt);
va_start(ap, fmt);
str = Fmt_vstring(fmt, ap);
va_end(ap);
return str;
}
char *Fmt_vstring(const char *fmt, va_list ap) {
struct buf cl;
assert(fmt);
cl.size = 256;
cl.buf = cl.bp = ALLOC(cl.size);
Fmt_vfmt(append, &cl, fmt, ap);
append(0, &cl);
return RESIZE(cl.buf, cl.bp - cl.buf);
}
void Fmt_vfmt(int put(int c, void *cl), void *cl,
const char *fmt, va_list ap) {
assert(put);
assert(fmt);
while (*fmt)
if (*fmt != '%' || *++fmt == '%')
put((unsigned char)*fmt++, cl);
else
{
unsigned char c, flags[256];
int width = INT_MIN, precision = INT_MIN;
memset(flags, '\0', sizeof flags);
if (Fmt_flags) {
unsigned char c = *fmt;
for ( ; c && strchr(Fmt_flags, c); c = *++fmt) {
assert(flags[c] < 255);
flags[c]++;
}
}
if (*fmt == '*' || isdigit(*fmt)) {
int n;
if (*fmt == '*') {
n = va_arg(ap, int);
assert(n != INT_MIN);
fmt++;
} else
for (n = 0; isdigit(*fmt); fmt++) {
int d = *fmt - '0';
assert(n <= (INT_MAX - d)/10);
n = 10*n + d;
}
width = n;
}
if (*fmt == '.' && (*++fmt == '*' || isdigit(*fmt))) {
int n;
if (*fmt == '*') {
n = va_arg(ap, int);
assert(n != INT_MIN);
fmt++;
} else
for (n = 0; isdigit(*fmt); fmt++) {
int d = *fmt - '0';
assert(n <= (INT_MAX - d)/10);
n = 10*n + d;
}
precision = n;
}
c = *fmt++;
assert(cvt[c]);
(*cvt[c])(c, &ap, put, cl, flags, width, precision);
}
}
T Fmt_register(int code, T newcvt) {
T old;
assert(0 < code
&& code < (int)(sizeof (cvt)/sizeof (cvt[0])));
old = cvt[code];
cvt[code] = newcvt;
return old;
}
void Fmt_putd(const char *str, int len,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
int sign;
assert(str);
assert(len >= 0);
assert(flags);
if (width == INT_MIN)
width = 0;
if (width < 0) {
flags['-'] = 1;
width = -width;
}
if (precision >= 0)
flags['0'] = 0;
if (len > 0 && (*str == '-' || *str == '+')) {
sign = *str++;
len--;
} else if (flags['+'])
sign = '+';
else if (flags[' '])
sign = ' ';
else
sign = 0;
{ int n;
if (precision < 0)
precision = 1;
if (len < precision)
n = precision;
else if (precision == 0 && len == 1 && str[0] == '0')
n = 0;
else
n = len;
if (sign)
n++;
if (flags['-']) {
if (sign)
put(sign, cl);
} else if (flags['0']) {
if (sign)
put(sign, cl);
pad(width - n, '0');
} else {
pad(width - n, ' ');
if (sign)
put(sign, cl);
}
pad(precision - len, '0');
{
int i;
for (i = 0; i < len; i++)
put((unsigned char)*str++, cl);
}
if (flags['-'])
pad(width - n, ' '); }
}
str.h
#ifndef STR_INCLUDED
#define STR_INCLUDED
#include <stdarg.h>
extern char *Str_sub(const char *s, int i, int j);
extern char *Str_dup(const char *s, int i, int j, int n);
extern char *Str_cat(const char *s1, int i1, int j1,
const char *s2, int i2, int j2);
extern char *Str_catv (const char *s, ...);
extern char *Str_reverse(const char *s, int i, int j);
extern char *Str_map (const char *s, int i, int j,
const char *from, const char *to);
extern int Str_pos(const char *s, int i);
extern int Str_len(const char *s, int i, int j);
extern int Str_cmp(const char *s1, int i1, int j1,
const char *s2, int i2, int j2);
extern int Str_chr (const char *s, int i, int j, int c);
extern int Str_rchr (const char *s, int i, int j, int c);
extern int Str_upto (const char *s, int i, int j,
const char *set);
extern int Str_rupto(const char *s, int i, int j,
const char *set);
extern int Str_find (const char *s, int i, int j,
const char *str);
extern int Str_rfind(const char *s, int i, int j,
const char *str);
extern int Str_any (const char *s, int i,
const char *set);
extern int Str_many (const char *s, int i, int j,
const char *set);
extern int Str_rmany (const char *s, int i, int j,
const char *set);
extern int Str_match (const char *s, int i, int j,
const char *str);
extern int Str_rmatch(const char *s, int i, int j,
const char *str);
extern void Str_fmt(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision);
#undef T
#endif
str.c
#include <string.h>
#include <limits.h>
#include "assert.h"
#include "fmt.h"
#include "str.h"
#include "mem.h"
#define idx(i, len) ((i) <= 0 ? (i) + (len) : (i) - 1)
#define convert(s, i, j) do { int len; \
assert(s); len = strlen(s); \
i = idx(i, len); j = idx(j, len); \
if (i > j) { int t = i; i = j; j = t; } \
assert(i >= 0 && j <= len); } while (0)
char *Str_sub(const char *s, int i, int j) {
char *str, *p;
convert(s, i, j);
p = str = ALLOC(j - i + 1);
while (i < j)
*p++ = s[i++];
*p = '\0';
return str;
}
char *Str_dup(const char *s, int i, int j, int n) {
int k;
char *str, *p;
assert(n >= 0);
convert(s, i, j);
p = str = ALLOC(n*(j - i) + 1);
if (j - i > 0)
while (n-- > 0)
for (k = i; k < j; k++)
*p++ = s[k];
*p = '\0';
return str;
}
char *Str_reverse(const char *s, int i, int j) {
char *str, *p;
convert(s, i, j);
p = str = ALLOC(j - i + 1);
while (j > i)
*p++ = s[--j];
*p = '\0';
return str;
}
char *Str_cat(const char *s1, int i1, int j1,
const char *s2, int i2, int j2) {
char *str, *p;
convert(s1, i1, j1);
convert(s2, i2, j2);
p = str = ALLOC(j1 - i1 + j2 - i2 + 1);
while (i1 < j1)
*p++ = s1[i1++];
while (i2 < j2)
*p++ = s2[i2++];
*p = '\0';
return str;
}
char *Str_catv(const char *s, ...) {
char *str, *p;
const char *save = s;
int i, j, len = 0;
va_list ap;
va_start(ap, s);
while (s) {
i = va_arg(ap, int);
j = va_arg(ap, int);
convert(s, i, j);
len += j - i;
s = va_arg(ap, const char *);
}
va_end(ap);
p = str = ALLOC(len + 1);
s = save;
va_start(ap, s);
while (s) {
i = va_arg(ap, int);
j = va_arg(ap, int);
convert(s, i, j);
while (i < j)
*p++ = s[i++];
s = va_arg(ap, const char *);
}
va_end(ap);
*p = '\0';
return str;
}
char *Str_map(const char *s, int i, int j,
const char *from, const char *to) {
static char map[256] = { 0 };
if (from && to) {
unsigned c;
for (c = 0; c < sizeof map; c++)
map[c] = c;
while (*from && *to)
map[(unsigned char)*from++] = *to++;
assert(*from == 0 && *to == 0);
} else {
assert(from == NULL && to == NULL && s);
assert(map['a']);
}
if (s) {
char *str, *p;
convert(s, i, j);
p = str = ALLOC(j - i + 1);
while (i < j)
*p++ = map[(unsigned char)s[i++]];
*p = '\0';
return str;
} else
return NULL;
}
int Str_pos(const char *s, int i) {
int len;
assert(s);
len = strlen(s);
i = idx(i, len);
assert(i >= 0 && i <= len);
return i + 1;
}
int Str_len(const char *s, int i, int j) {
convert(s, i, j);
return j - i;
}
int Str_cmp(const char *s1, int i1, int j1,
const char *s2, int i2, int j2) {
convert(s1, i1, j1);
convert(s2, i2, j2);
s1 += i1;
s2 += i2;
if (j1 - i1 < j2 - i2) {
int cond = strncmp(s1, s2, j1 - i1);
return cond == 0 ? -1 : cond;
} else if (j1 - i1 > j2 - i2) {
int cond = strncmp(s1, s2, j2 - i2);
return cond == 0 ? +1 : cond;
} else
return strncmp(s1, s2, j1 - i1);
}
int Str_chr(const char *s, int i, int j, int c) {
convert(s, i, j);
for ( ; i < j; i++)
if (s[i] == c)
return i + 1;
return 0;
}
int Str_rchr(const char *s, int i, int j, int c) {
convert(s, i, j);
while (j > i)
if (s[--j] == c)
return j + 1;
return 0;
}
int Str_upto(const char *s, int i, int j,
const char *set) {
assert(set);
convert(s, i, j);
for ( ; i < j; i++)
if (strchr(set, s[i]))
return i + 1;
return 0;
}
int Str_rupto(const char *s, int i, int j,
const char *set) {
assert(set);
convert(s, i, j);
while (j > i)
if (strchr(set, s[--j]))
return j + 1;
return 0;
}
int Str_find(const char *s, int i, int j,
const char *str) {
int len;
convert(s, i, j);
assert(str);
len = strlen(str);
if (len == 0)
return i + 1;
else if (len == 1) {
for ( ; i < j; i++)
if (s[i] == *str)
return i + 1;
} else
for ( ; i + len <= j; i++)
if ((strncmp(&s[i], str, len) == 0))
return i + 1;
return 0;
}
int Str_rfind(const char *s, int i, int j,
const char *str) {
int len;
convert(s, i, j);
assert(str);
len = strlen(str);
if (len == 0)
return j + 1;
else if (len == 1) {
while (j > i)
if (s[--j] == *str)
return j + 1;
} else
for ( ; j - len >= i; j--)
if (strncmp(&s[j-len], str, len) == 0)
return j - len + 1;
return 0;
}
int Str_any(const char *s, int i, const char *set) {
int len;
assert(s);
assert(set);
len = strlen(s);
i = idx(i, len);
assert(i >= 0 && i <= len);
if (i < len && strchr(set, s[i]))
return i + 2;
return 0;
}
int Str_many(const char *s, int i, int j,
const char *set) {
assert(set);
convert(s, i, j);
if (i < j && strchr(set, s[i])) {
do
i++;
while (i < j && strchr(set, s[i]));
return i + 1;
}
return 0;
}
int Str_rmany(const char *s, int i, int j,
const char *set) {
assert(set);
convert(s, i, j);
if (j > i && strchr(set, s[j-1])) {
do
--j;
while (j >= i && strchr(set, s[j]));
return j + 2;
}
return 0;
}
int Str_match(const char *s, int i, int j,
const char *str) {
int len;
convert(s, i, j);
assert(str);
len = strlen(str);
if (len == 0)
return i + 1;
else if (len == 1) {
if (i < j && s[i] == *str)
return i + 2;
} else if (i + len <= j && (strncmp(&s[i], str, len) == 0))
return i + len + 1;
return 0;
}
int Str_rmatch(const char *s, int i, int j,
const char *str) {
int len;
convert(s, i, j);
assert(str);
len = strlen(str);
if (len == 0)
return j + 1;
else if (len == 1) {
if (j > i && s[j-1] == *str)
return j;
} else if (j - len >= i
&& strncmp(&s[j-len], str, len) == 0)
return j - len + 1;
return 0;
}
void Str_fmt(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
char *s;
int i, j;
assert(app && flags);
s = va_arg(*app, char *);
i = va_arg(*app, int);
j = va_arg(*app, int);
convert(s, i, j);
Fmt_puts(s + i, j - i, put, cl, flags,
width, precision);
}
ids.c
#include <stdlib.h>
#include <stdio.h>
#include "fmt.h"
#include "str.h"
int main(int argc, char *argv[]) {
char line[512];
static char set[] = "0123456789_"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
Fmt_register('S', Str_fmt);
while (fgets(line, sizeof line, stdin) != NULL) {
int i = 1, j;
while ((i = Str_upto(line, i, 0, &set[10])) > 0){
j = Str_many(line, i, 0, set);
Fmt_print("%S\n", line, i, j);
i = j;
}
}
return EXIT_SUCCESS;
}
text.h
#ifndef TEXT_INCLUDED
#define TEXT_INCLUDED
#include <stdarg.h>
#define T Text_T
typedef struct T {
int len;
const char *str;
} T;
typedef struct Text_save_T *Text_save_T;
extern const T Text_cset;
extern const T Text_ascii;
extern const T Text_ucase;
extern const T Text_lcase;
extern const T Text_digits;
extern const T Text_null;
extern T Text_put(const char *str);
extern char *Text_get(char *str, int size, T s);
extern T Text_box(const char *str, int len);
extern T Text_sub(T s, int i, int j);
extern int Text_pos(T s, int i);
extern T Text_cat (T s1, T s2);
extern T Text_dup (T s, int n);
extern T Text_reverse(T s);
extern T Text_map(T s, const T *from, const T *to);
extern int Text_cmp(T s1, T s2);
extern int Text_chr (T s, int i, int j, int c);
extern int Text_rchr (T s, int i, int j, int c);
extern int Text_upto (T s, int i, int j, T set);
extern int Text_rupto(T s, int i, int j, T set);
extern int Text_any (T s, int i, T set);
extern int Text_many (T s, int i, int j, T set);
extern int Text_rmany(T s, int i, int j, T set);
extern int Text_find (T s, int i, int j, T str);
extern int Text_rfind (T s, int i, int j, T str);
extern int Text_match (T s, int i, int j, T str);
extern int Text_rmatch(T s, int i, int j, T str);
extern void Text_fmt(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision);
extern Text_save_T Text_save(void);
extern void Text_restore(Text_save_T *save);
#undef T
#endif
text.c
#include <string.h>
#include <limits.h>
#include "assert.h"
#include "fmt.h"
#include "text.h"
#include "mem.h"
#define T Text_T
#define idx(i, len) ((i) <= 0 ? (i) + (len) : (i) - 1)
#define isatend(s, n) ((s).str+(s).len == current->avail\
&& current->avail + (n) <= current->limit)
#define equal(s, i, t) \
(memcmp(&(s).str[i], (t).str, (t).len) == 0)
struct Text_save_T {
struct chunk *current;
char *avail;
};
static char cset[] =
"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
"\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
"\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
"\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
"\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
"\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
"\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
;
const T Text_cset = { 256, cset };
const T Text_ascii = { 127, cset };
const T Text_ucase = { 26, cset + 'A' };
const T Text_lcase = { 26, cset + 'a' };
const T Text_digits = { 10, cset + '0' };
const T Text_null = { 0, cset };
static struct chunk {
struct chunk *link;
char *avail;
char *limit;
} head = { NULL, NULL, NULL }, *current = &head;
static char *alloc(int len) {
assert(len >= 0);
if (current->avail + len > current->limit) {
current = current->link =
ALLOC(sizeof (*current) + 10*1024 + len);
current->avail = (char *)(current + 1);
current->limit = current->avail + 10*1024 + len;
current->link = NULL;
}
current->avail += len;
return current->avail - len;
}
int Text_pos(T s, int i) {
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
assert(i >= 0 && i <= s.len);
return i + 1;
}
T Text_box(const char *str, int len) {
T text;
assert(str);
assert(len >= 0);
text.str = str;
text.len = len;
return text;
}
T Text_sub(T s, int i, int j) {
T text;
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
text.len = j - i;
text.str = s.str + i;
return text;
}
T Text_put(const char *str) {
T text;
assert(str);
text.len = strlen(str);
text.str = memcpy(alloc(text.len), str, text.len);
return text;
}
char *Text_get(char *str, int size, T s) {
assert(s.len >= 0 && s.str);
if (str == NULL)
str = ALLOC(s.len + 1);
else
assert(size >= s.len + 1);
memcpy(str, s.str, s.len);
str[s.len] = '\0';
return str;
}
T Text_dup(T s, int n) {
assert(s.len >= 0 && s.str);
assert(n >= 0);
if (n == 0 || s.len == 0)
return Text_null;
if (n == 1)
return s;
{
T text;
char *p;
text.len = n*s.len;
if (isatend(s, text.len - s.len)) {
text.str = s.str;
p = alloc(text.len - s.len);
n--;
} else
text.str = p = alloc(text.len);
for ( ; n-- > 0; p += s.len)
memcpy(p, s.str, s.len);
return text;
}
}
T Text_cat(T s1, T s2) {
assert(s1.len >= 0 && s1.str);
assert(s2.len >= 0 && s2.str);
if (s1.len == 0)
return s2;
if (s2.len == 0)
return s1;
if (s1.str + s1.len == s2.str) {
s1.len += s2.len;
return s1;
}
{
T text;
text.len = s1.len + s2.len;
if (isatend(s1, s2.len)) {
text.str = s1.str;
memcpy(alloc(s2.len), s2.str, s2.len);
} else {
char *p;
text.str = p = alloc(s1.len + s2.len);
memcpy(p, s1.str, s1.len);
memcpy(p + s1.len, s2.str, s2.len);
}
return text;
}
}
T Text_reverse(T s) {
assert(s.len >= 0 && s.str);
if (s.len == 0)
return Text_null;
else if (s.len == 1)
return s;
else {
T text;
char *p;
int i = s.len;
text.len = s.len;
text.str = p = alloc(s.len);
while (--i >= 0)
*p++ = s.str[i];
return text;
}
}
T Text_map(T s, const T *from, const T *to) {
static char map[256];
static int inited = 0;
assert(s.len >= 0 && s.str);
if (from && to) {
int k;
for (k = 0; k < (int)sizeof map; k++)
map[k] = k;
assert(from->len == to->len);
for (k = 0; k < from->len; k++)
map[from->str[k]] = to->str[k];
inited = 1;
} else {
assert(from == NULL && to == NULL);
assert(inited);
}
if (s.len == 0)
return Text_null;
else {
T text;
int i;
char *p;
text.len = s.len;
text.str = p = alloc(s.len);
for (i = 0; i < s.len; i++)
*p++ = map[s.str[i]];
return text;
}
}
int Text_cmp(T s1, T s2) {
assert(s1.len >= 0 && s1.str);
assert(s2.len >= 0 && s2.str);
if (s1.str == s2.str)
return s1.len - s2.len;
else if (s1.len < s2.len) {
int cond = memcmp(s1.str, s2.str, s1.len);
return cond == 0 ? -1 : cond;
} else if (s1.len > s2.len) {
int cond = memcmp(s1.str, s2.str, s2.len);
return cond == 0 ? +1 : cond;
} else
return memcmp(s1.str, s2.str, s1.len);
}
Text_save_T Text_save(void) {
Text_save_T save;
NEW(save);
save->current = current;
save->avail = current->avail;
alloc(1);
return save;
}
void Text_restore(Text_save_T *save) {
struct chunk *p, *q;
assert(save && *save);
current = (*save)->current;
current->avail = (*save)->avail;
FREE(*save);
for (p = current->link; p; p = q) {
q = p->link;
FREE(p);
}
current->link = NULL;
}
int Text_chr(T s, int i, int j, int c) {
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
for ( ; i < j; i++)
if (s.str[i] == c)
return i + 1;
return 0;
}
int Text_rchr(T s, int i, int j, int c) {
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
while (j > i)
if (s.str[--j] == c)
return j + 1;
return 0;
}
int Text_upto(T s, int i, int j, T set) {
assert(set.len >= 0 && set.str);
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
for ( ; i < j; i++)
if (memchr(set.str, s.str[i], set.len))
return i + 1;
return 0;
}
int Text_rupto(T s, int i, int j, T set) {
assert(set.len >= 0 && set.str);
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
while (j > i)
if (memchr(set.str, s.str[--j], set.len))
return j + 1;
return 0;
}
int Text_find(T s, int i, int j, T str) {
assert(str.len >= 0 && str.str);
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
if (str.len == 0)
return i + 1;
else if (str.len == 1) {
for ( ; i < j; i++)
if (s.str[i] == *str.str)
return i + 1;
} else
for ( ; i + str.len <= j; i++)
if (equal(s, i, str))
return i + 1;
return 0;
}
int Text_rfind(T s, int i, int j, T str) {
assert(str.len >= 0 && str.str);
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
if (str.len == 0)
return j + 1;
else if (str.len == 1) {
while (j > i)
if (s.str[--j] == *str.str)
return j + 1;
} else
for ( ; j - str.len >= i; j--)
if (equal(s, j - str.len, str))
return j - str.len + 1;
return 0;
}
int Text_any(T s, int i, T set) {
assert(s.len >= 0 && s.str);
assert(set.len >= 0 && set.str);
i = idx(i, s.len);
assert(i >= 0 && i <= s.len);
if (i < s.len && memchr(set.str, s.str[i], set.len))
return i + 2;
return 0;
}
int Text_many(T s, int i, int j, T set) {
assert(set.len >= 0 && set.str);
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
if (i < j && memchr(set.str, s.str[i], set.len)) {
do
i++;
while (i < j
&& memchr(set.str, s.str[i], set.len));
return i + 1;
}
return 0;
}
int Text_rmany(T s, int i, int j, T set) {
assert(set.len >= 0 && set.str);
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
if (j > i && memchr(set.str, s.str[j-1], set.len)) {
do
--j;
while (j >= i
&& memchr(set.str, s.str[j], set.len));
return j + 2;
}
return 0;
}
int Text_match(T s, int i, int j, T str) {
assert(str.len >= 0 && str.str);
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
if (str.len == 0)
return i + 1;
else if (str.len == 1) {
if (i < j && s.str[i] == *str.str)
return i + 2;
} else if (i + str.len <= j && equal(s, i, str))
return i + str.len + 1;
return 0;
}
int Text_rmatch(T s, int i, int j, T str) {
assert(str.len >= 0 && str.str);
assert(s.len >= 0 && s.str);
i = idx(i, s.len);
j = idx(j, s.len);
if (i > j) { int t = i; i = j; j = t; }
assert(i >= 0 && j <= s.len);
if (str.len == 0)
return j + 1;
else if (str.len == 1) {
if (j > i && s.str[j-1] == *str.str)
return j;
} else if (j - str.len >= i
&& equal(s, j - str.len, str))
return j - str.len + 1;
return 0;
}
void Text_fmt(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
T *s;
assert(app && flags);
s = va_arg(*app, T*);
assert(s && s->len >= 0 && s->str);
Fmt_puts(s->str, s->len, put, cl, flags,
width, precision);
}
xp.h
#ifndef XP_INCLUDED
#define XP_INCLUDED
#define T XP_T
typedef unsigned char *T;
extern int XP_add(int n, T z, T x, T y, int carry);
extern int XP_sub(int n, T z, T x, T y, int borrow);
extern int XP_mul(T z, int n, T x, int m, T y);
extern int XP_div(int n, T q, T x, int m, T y, T r,T tmp);
extern int XP_sum (int n, T z, T x, int y);
extern int XP_diff (int n, T z, T x, int y);
extern int XP_product (int n, T z, T x, int y);
extern int XP_quotient(int n, T z, T x, int y);
extern int XP_neg(int n, T z, T x, int carry);
extern int XP_cmp(int n, T x, T y);
extern void XP_lshift(int n, T z, int m, T x,
int s, int fill);
extern void XP_rshift(int n, T z, int m, T x,
int s, int fill);
extern int XP_length (int n, T x);
extern unsigned long XP_fromint(int n, T z,
unsigned long u);
extern unsigned long XP_toint (int n, T x);
extern int XP_fromstr(int n, T z, const char *str,
int base, char **end);
extern char *XP_tostr (char *str, int size, int base,
int n, T x);
#undef T
#endif
xp.c
#include <ctype.h>
#include <string.h>
#include "assert.h"
#include "xp.h"
#define T XP_T
#define BASE (1<<8)
static char map[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
36, 36, 36, 36, 36, 36, 36,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 36, 36, 36, 36, 36,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
};
unsigned long XP_fromint(int n, T z, unsigned long u) {
int i = 0;
do
z[i++] = u%BASE;
while ((u /= BASE) > 0 && i < n);
for ( ; i < n; i++)
z[i] = 0;
return u;
}
unsigned long XP_toint(int n, T x) {
unsigned long u = 0;
int i = (int)sizeof u;
if (i > n)
i = n;
while (--i >= 0)
u = BASE*u + x[i];
return u;
}
int XP_length(int n, T x) {
while (n > 1 && x[n-1] == 0)
n--;
return n;
}
int XP_add(int n, T z, T x, T y, int carry) {
int i;
for (i = 0; i < n; i++) {
carry += x[i] + y[i];
z[i] = carry%BASE;
carry /= BASE;
}
return carry;
}
int XP_sub(int n, T z, T x, T y, int borrow) {
int i;
for (i = 0; i < n; i++) {
int d = (x[i] + BASE) - borrow - y[i];
z[i] = d%BASE;
borrow = 1 - d/BASE;
}
return borrow;
}
int XP_sum(int n, T z, T x, int y) {
int i;
for (i = 0; i < n; i++) {
y += x[i];
z[i] = y%BASE;
y /= BASE;
}
return y;
}
int XP_diff(int n, T z, T x, int y) {
int i;
for (i = 0; i < n; i++) {
int d = (x[i] + BASE) - y;
z[i] = d%BASE;
y = 1 - d/BASE;
}
return y;
}
int XP_neg(int n, T z, T x, int carry) {
int i;
for (i = 0; i < n; i++) {
carry += (unsigned char)~x[i];
z[i] = carry%BASE;
carry /= BASE;
}
return carry;
}
int XP_mul(T z, int n, T x, int m, T y) {
int i, j, carryout = 0;
for (i = 0; i < n; i++) {
unsigned carry = 0;
for (j = 0; j < m; j++) {
carry += x[i]*y[j] + z[i+j];
z[i+j] = carry%BASE;
carry /= BASE;
}
for ( ; j < n + m - i; j++) {
carry += z[i+j];
z[i+j] = carry%BASE;
carry /= BASE;
}
carryout |= carry;
}
return carryout;
}
int XP_product(int n, T z, T x, int y) {
int i;
unsigned carry = 0;
for (i = 0; i < n; i++) {
carry += x[i]*y;
z[i] = carry%BASE;
carry /= BASE;
}
return carry;
}
int XP_div(int n, T q, T x, int m, T y, T r, T tmp) {
int nx = n, my = m;
n = XP_length(n, x);
m = XP_length(m, y);
if (m == 1) {
if (y[0] == 0)
return 0;
r[0] = XP_quotient(nx, q, x, y[0]);
memset(r + 1, '\0', my - 1);
} else if (m > n) {
memset(q, '\0', nx);
memcpy(r, x, n);
memset(r + n, '\0', my - n);
} else {
int k;
unsigned char *rem = tmp, *dq = tmp + n + 1;
assert(2 <= m && m <= n);
memcpy(rem, x, n);
rem[n] = 0;
for (k = n - m; k >= 0; k--) {
int qk;
{
int i;
assert(2 <= m && m <= k+m && k+m <= n);
{
int km = k + m;
unsigned long y2 = y[m-1]*BASE + y[m-2];
unsigned long r3 = rem[km]*(BASE*BASE) +
rem[km-1]*BASE + rem[km-2];
qk = r3/y2;
if (qk >= BASE)
qk = BASE - 1;
}
dq[m] = XP_product(m, dq, y, qk);
for (i = m; i > 0; i--)
if (rem[i+k] != dq[i])
break;
if (rem[i+k] < dq[i])
dq[m] = XP_product(m, dq, y, --qk);
}
q[k] = qk;
{
int borrow;
assert(0 <= k && k <= k+m);
borrow = XP_sub(m + 1, &rem[k], &rem[k], dq, 0);
assert(borrow == 0);
}
}
memcpy(r, rem, m);
{
int i;
for (i = n-m+1; i < nx; i++)
q[i] = 0;
for (i = m; i < my; i++)
r[i] = 0;
}
}
return 1;
}
int XP_quotient(int n, T z, T x, int y) {
int i;
unsigned carry = 0;
for (i = n - 1; i >= 0; i--) {
carry = carry*BASE + x[i];
z[i] = carry/y;
carry %= y;
}
return carry;
}
int XP_cmp(int n, T x, T y) {
int i = n - 1;
while (i > 0 && x[i] == y[i])
i--;
return x[i] - y[i];
}
void XP_lshift(int n, T z, int m, T x, int s, int fill) {
fill = fill ? 0xFF : 0;
{
int i, j = n - 1;
if (n > m)
i = m - 1;
else
i = n - s/8 - 1;
for ( ; j >= m + s/8; j--)
z[j] = 0;
for ( ; i >= 0; i--, j--)
z[j] = x[i];
for ( ; j >= 0; j--)
z[j] = fill;
}
s %= 8;
if (s > 0)
{
XP_product(n, z, z, 1<<s);
z[0] |= fill>>(8-s);
}
}
void XP_rshift(int n, T z, int m, T x, int s, int fill) {
fill = fill ? 0xFF : 0;
{
int i, j = 0;
for (i = s/8; i < m && j < n; i++, j++)
z[j] = x[i];
for ( ; j < n; j++)
z[j] = fill;
}
s %= 8;
if (s > 0)
{
XP_quotient(n, z, z, 1<<s);
z[n-1] |= fill<<(8-s);
}
}
int XP_fromstr(int n, T z, const char *str,
int base, char **end) {
const char *p = str;
assert(p);
assert(base >= 2 && base <= 36);
while (*p && isspace(*p))
p++;
if ((*p && isalnum(*p) && map[*p-'0'] < base)) {
int carry;
for ( ; (*p && isalnum(*p) && map[*p-'0'] < base); p++) {
carry = XP_product(n, z, z, base);
if (carry)
break;
XP_sum(n, z, z, map[*p-'0']);
}
if (end)
*end = (char *)p;
return carry;
} else {
if (end)
*end = (char *)str;
return 0;
}
}
char *XP_tostr(char *str, int size, int base,
int n, T x) {
int i = 0;
assert(str);
assert(base >= 2 && base <= 36);
do {
int r = XP_quotient(n, x, x, base);
assert(i < size);
str[i++] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[r];
while (n > 1 && x[n-1] == 0)
n--;
} while (n > 1 || x[0] != 0);
assert(i < size);
str[i] = '\0';
{
int j;
for (j = 0; j < --i; j++) {
char c = str[j];
str[j] = str[i];
str[i] = c;
}
}
return str;
}
ap.h
#ifndef AP_INCLUDED
#define AP_INCLUDED
#include <stdarg.h>
#define T AP_T
typedef struct T *T;
extern T AP_new (long int n);
extern T AP_fromstr(const char *str, int base,
char **end);
extern long int AP_toint(T x);
extern char *AP_tostr(char *str, int size,
int base, T x);
extern void AP_fmt(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision);
extern void AP_free(T *z);
extern T AP_neg(T x);
extern T AP_add(T x, T y);
extern T AP_sub(T x, T y);
extern T AP_mul(T x, T y);
extern T AP_div(T x, T y);
extern T AP_mod(T x, T y);
extern T AP_pow(T x, T y, T p);
extern T AP_addi(T x, long int y);
extern T AP_subi(T x, long int y);
extern T AP_muli(T x, long int y);
extern T AP_divi(T x, long int y);
extern long AP_modi(T x, long int y);
extern T AP_lshift(T x, int s);
extern T AP_rshift(T x, int s);
extern int AP_cmp (T x, T y);
extern int AP_cmpi(T x, long int y);
#undef T
#endif
ap.c
#include <ctype.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "assert.h"
#include "ap.h"
#include "fmt.h"
#include "xp.h"
#include "mem.h"
#define T AP_T
struct T {
int sign;
int ndigits;
int size;
XP_T digits;
};
#define iszero(x) ((x)->ndigits==1 && (x)->digits[0]==0)
#define maxdigits(x,y) ((x)->ndigits > (y)->ndigits ? \
(x)->ndigits : (y)->ndigits)
#define isone(x) ((x)->ndigits==1 && (x)->digits[0]==1)
static T normalize(T z, int n);
static int cmp(T x, T y);
static T mk(int size) {
T z = CALLOC(1, sizeof (*z) + size);
assert(size > 0);
z->sign = 1;
z->size = size;
z->ndigits = 1;
z->digits = (XP_T)(z + 1);
return z;
}
static T set(T z, long int n) {
if (n == LONG_MIN)
XP_fromint(z->size, z->digits, LONG_MAX + 1UL);
else if (n < 0)
XP_fromint(z->size, z->digits, -n);
else
XP_fromint(z->size, z->digits, n);
z->sign = n < 0 ? -1 : 1;
return normalize(z, z->size);
}
static T normalize(T z, int n) {
z->ndigits = XP_length(n, z->digits);
return z;
}
static T add(T z, T x, T y) {
int n = y->ndigits;
if (x->ndigits < n)
return add(z, y, x);
else if (x->ndigits > n) {
int carry = XP_add(n, z->digits, x->digits,
y->digits, 0);
z->digits[z->size-1] = XP_sum(x->ndigits - n,
&z->digits[n], &x->digits[n], carry);
} else
z->digits[n] = XP_add(n, z->digits, x->digits,
y->digits, 0);
return normalize(z, z->size);
}
static T sub(T z, T x, T y) {
int borrow, n = y->ndigits;
borrow = XP_sub(n, z->digits, x->digits,
y->digits, 0);
if (x->ndigits > n)
borrow = XP_diff(x->ndigits - n, &z->digits[n],
&x->digits[n], borrow);
assert(borrow == 0);
return normalize(z, z->size);
}
static T mulmod(T x, T y, T p) {
T z, xy = AP_mul(x, y);
z = AP_mod(xy, p);
AP_free(&xy);
return z;
}
static int cmp(T x, T y) {
if (x->ndigits != y->ndigits)
return x->ndigits - y->ndigits;
else
return XP_cmp(x->ndigits, x->digits, y->digits);
}
T AP_new(long int n) {
return set(mk(sizeof (long int)), n);
}
void AP_free(T *z) {
assert(z && *z);
FREE(*z);
}
T AP_neg(T x) {
T z;
assert(x);
z = mk(x->ndigits);
memcpy(z->digits, x->digits, x->ndigits);
z->ndigits = x->ndigits;
z->sign = iszero(z) ? 1 : -x->sign;
return z;
}
T AP_mul(T x, T y) {
T z;
assert(x);
assert(y);
z = mk(x->ndigits + y->ndigits);
XP_mul(z->digits, x->ndigits, x->digits, y->ndigits,
y->digits);
normalize(z, z->size);
z->sign = iszero(z)
|| ((x->sign^y->sign) == 0) ? 1 : -1;
return z;
}
T AP_add(T x, T y) {
T z;
assert(x);
assert(y);
if (((x->sign^y->sign) == 0)) {
z = add(mk(maxdigits(x,y) + 1), x, y);
z->sign = iszero(z) ? 1 : x->sign;
} else
if (cmp(x, y) > 0) {
z = sub(mk(x->ndigits), x, y);
z->sign = iszero(z) ? 1 : x->sign;
}
else {
z = sub(mk(y->ndigits), y, x);
z->sign = iszero(z) ? 1 : -x->sign;
}
return z;
}
T AP_sub(T x, T y) {
T z;
assert(x);
assert(y);
if (!((x->sign^y->sign) == 0)) {
z = add(mk(maxdigits(x,y) + 1), x, y);
z->sign = iszero(z) ? 1 : x->sign;
} else
if (cmp(x, y) > 0) {
z = sub(mk(x->ndigits), x, y);
z->sign = iszero(z) ? 1 : x->sign;
} else {
z = sub(mk(y->ndigits), y, x);
z->sign = iszero(z) ? 1 : -x->sign;
}
return z;
}
T AP_div(T x, T y) {
T q, r;
assert(x);
assert(y);
assert(!iszero(y));
q = mk(x->ndigits);
r = mk(y->ndigits);
{
XP_T tmp = ALLOC(x->ndigits + y->ndigits + 2);
XP_div(x->ndigits, q->digits, x->digits,
y->ndigits, y->digits, r->digits, tmp);
FREE(tmp);
}
normalize(q, q->size);
normalize(r, r->size);
q->sign = iszero(q)
|| ((x->sign^y->sign) == 0) ? 1 : -1;
if (!((x->sign^y->sign) == 0) && !iszero(r)) {
int carry = XP_sum(q->size, q->digits,
q->digits, 1);
assert(carry == 0);
normalize(q, q->size);
}
AP_free(&r);
return q;
}
T AP_mod(T x, T y) {
T q, r;
assert(x);
assert(y);
assert(!iszero(y));
q = mk(x->ndigits);
r = mk(y->ndigits);
{
XP_T tmp = ALLOC(x->ndigits + y->ndigits + 2);
XP_div(x->ndigits, q->digits, x->digits,
y->ndigits, y->digits, r->digits, tmp);
FREE(tmp);
}
normalize(q, q->size);
normalize(r, r->size);
q->sign = iszero(q)
|| ((x->sign^y->sign) == 0) ? 1 : -1;
if (!((x->sign^y->sign) == 0) && !iszero(r)) {
int borrow = XP_sub(r->size, r->digits,
y->digits, r->digits, 0);
assert(borrow == 0);
normalize(r, r->size);
}
AP_free(&q);
return r;
}
T AP_pow(T x, T y, T p) {
T z;
assert(x);
assert(y);
assert(y->sign == 1);
assert(!p || p->sign==1 && !iszero(p) && !isone(p));
if (iszero(x))
return AP_new(0);
if (iszero(y))
return AP_new(1);
if (isone(x))
return AP_new((((y)->digits[0]&1) == 0) ? 1 : x->sign);
if (p)
if (isone(y))
z = AP_mod(x, p);
else {
T y2 = AP_rshift(y, 1), t = AP_pow(x, y2, p);
z = mulmod(t, t, p);
AP_free(&y2);
AP_free(&t);
if (!(((y)->digits[0]&1) == 0)) {
z = mulmod(y2 = AP_mod(x, p), t = z, p);
AP_free(&y2);
AP_free(&t);
}
}
else
if (isone(y))
z = AP_addi(x, 0);
else {
T y2 = AP_rshift(y, 1), t = AP_pow(x, y2, NULL);
z = AP_mul(t, t);
AP_free(&y2);
AP_free(&t);
if (!(((y)->digits[0]&1) == 0)) {
z = AP_mul(x, t = z);
AP_free(&t);
}
}
return z;
}
int AP_cmp(T x, T y) {
assert(x);
assert(y);
if (!((x->sign^y->sign) == 0))
return x->sign;
else if (x->sign == 1)
return cmp(x, y);
else
return cmp(y, x);
}
T AP_addi(T x, long int y) {
unsigned char d[sizeof (unsigned long)];
struct T t;
t.size = sizeof d;
t.digits = d;
return AP_add(x, set(&t, y));
}
T AP_subi(T x, long int y) {
unsigned char d[sizeof (unsigned long)];
struct T t;
t.size = sizeof d;
t.digits = d;
return AP_sub(x, set(&t, y));
}
T AP_muli(T x, long int y) {
unsigned char d[sizeof (unsigned long)];
struct T t;
t.size = sizeof d;
t.digits = d;
return AP_mul(x, set(&t, y));
}
T AP_divi(T x, long int y) {
unsigned char d[sizeof (unsigned long)];
struct T t;
t.size = sizeof d;
t.digits = d;
return AP_div(x, set(&t, y));
}
int AP_cmpi(T x, long int y) {
unsigned char d[sizeof (unsigned long)];
struct T t;
t.size = sizeof d;
t.digits = d;
return AP_cmp(x, set(&t, y));
}
long int AP_modi(T x, long int y) {
long int rem;
T r;
unsigned char d[sizeof (unsigned long)];
struct T t;
t.size = sizeof d;
t.digits = d;
r = AP_mod(x, set(&t, y));
rem = XP_toint(r->ndigits, r->digits);
AP_free(&r);
return rem;
}
T AP_lshift(T x, int s) {
T z;
assert(x);
assert(s >= 0);
z = mk(x->ndigits + ((s+7)&~7)/8);
XP_lshift(z->size, z->digits, x->ndigits,
x->digits, s, 0);
z->sign = x->sign;
return normalize(z, z->size);
}
T AP_rshift(T x, int s) {
assert(x);
assert(s >= 0);
if (s >= 8*x->ndigits)
return AP_new(0);
else {
T z = mk(x->ndigits - s/8);
XP_rshift(z->size, z->digits, x->ndigits,
x->digits, s, 0);
normalize(z, z->size);
z->sign = iszero(z) ? 1 : x->sign;
return z;
}
}
long int AP_toint(T x) {
unsigned long u;
assert(x);
u = XP_toint(x->ndigits, x->digits)%(LONG_MAX + 1UL);
if (x->sign == -1)
return -(long)u;
else
return (long)u;
}
T AP_fromstr(const char *str, int base, char **end) {
T z;
const char *p = str;
char *endp, sign = '\0';
int carry;
assert(p);
assert(base >= 2 && base <= 36);
while (*p && isspace(*p))
p++;
if (*p == '-' || *p == '+')
sign = *p++;
{
const char *start;
int k, n = 0;
for ( ; *p == '0' && p[1] == '0'; p++)
;
start = p;
for ( ; ( '0' <= *p && *p <= '9' && *p < '0' + base
|| 'a' <= *p && *p <= 'z' && *p < 'a' + base - 10
|| 'A' <= *p && *p <= 'Z' && *p < 'A' + base - 10); p++)
n++;
for (k = 1; (1<<k) < base; k++)
;
z = mk(((k*n + 7)&~7)/8);
p = start;
}
carry = XP_fromstr(z->size, z->digits, p,
base, &endp);
assert(carry == 0);
normalize(z, z->size);
if (endp == p) {
endp = (char *)str;
z = AP_new(0);
} else
z->sign = iszero(z) || sign != '-' ? 1 : -1;
if (end)
*end = (char *)endp;
return z;
}
char *AP_tostr(char *str, int size, int base, T x) {
XP_T q;
assert(x);
assert(base >= 2 && base <= 36);
assert(str == NULL || size > 1);
if (str == NULL) {
{
int k;
for (k = 5; (1<<k) > base; k--)
;
size = (8*x->ndigits)/k + 1 + 1;
if (x->sign == 1)
size++;
}
str = ALLOC(size);
}
q = ALLOC(x->ndigits);
memcpy(q, x->digits, x->ndigits);
if (x->sign == -1) {
str[0] = '-';
XP_tostr(str + 1, size - 1, base, x->ndigits, q);
} else
XP_tostr(str, size, base, x->ndigits, q);
FREE(q);
return str;
}
void AP_fmt(int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision) {
T x;
char *buf;
assert(app && flags);
x = va_arg(*app, T);
assert(x);
buf = AP_tostr(NULL, 0, 10, x);
Fmt_putd(buf, strlen(buf), put, cl, flags,
width, precision);
FREE(buf);
}
calc.c
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "stack.h"
#include "ap.h"
#include "fmt.h"
Stack_T sp;
AP_T pop(void) {
if (!Stack_empty(sp))
return Stack_pop(sp);
else {
Fmt_fprint(stderr, "?stack underflow\n");
return AP_new(0);
}
}
int main(int argc, char *argv[]) {
int c;
sp = Stack_new();
Fmt_register('D', AP_fmt);
while ((c = getchar()) != EOF)
switch (c) {
case ' ': case '\t': case '\n': case '\f': case '\r':
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
char buf[512];
{
int i = 0;
for ( ; c != EOF && isdigit(c); c = getchar(), i++)
if (i < (int)sizeof (buf) - 1)
buf[i] = c;
if (i > (int)sizeof (buf) - 1) {
i = (int)sizeof (buf) - 1;
Fmt_fprint(stderr,
"?integer constant exceeds %d digits\n", i);
}
buf[i] = 0;
if (c != EOF)
ungetc(c, stdin);
}
Stack_push(sp, AP_fromstr(buf, 10, NULL));
break;
}
case '+': {
AP_T y = pop(), x = pop();
Stack_push(sp, AP_add(x, y));
AP_free(&x);
AP_free(&y);
break;
}
case '-': {
AP_T y = pop(), x = pop();
Stack_push(sp, AP_sub(x, y));
AP_free(&x);
AP_free(&y);
break;
}
case '*': {
AP_T y = pop(), x = pop();
Stack_push(sp, AP_mul(x, y));
AP_free(&x);
AP_free(&y);
break;
}
case '/': {
AP_T y = pop(), x = pop();
if (AP_cmpi(y, 0) == 0) {
Fmt_fprint(stderr, "?/ by 0\n");
Stack_push(sp, AP_new(0));
} else
Stack_push(sp, AP_div(x, y));
AP_free(&x);
AP_free(&y);
break;
}
case '%': {
AP_T y = pop(), x = pop();
if (AP_cmpi(y, 0) == 0) {
Fmt_fprint(stderr, "?%% by 0\n");
Stack_push(sp, AP_new(0));
} else
Stack_push(sp, AP_mod(x, y));
AP_free(&x);
AP_free(&y);
break;
}
case '^': {
AP_T y = pop(), x = pop();
if (AP_cmpi(y, 0) <= 0) {
Fmt_fprint(stderr, "?nonpositive power\n");
Stack_push(sp, AP_new(0));
} else
Stack_push(sp, AP_pow(x, y, NULL));
AP_free(&x);
AP_free(&y);
break;
}
case 'd': {
AP_T x = pop();
Stack_push(sp, x);
Stack_push(sp, AP_addi(x, 0));
break;
}
case 'p': {
AP_T x = pop();
Fmt_print("%D\n", x);
Stack_push(sp, x);
break;
}
case 'f':
if (!Stack_empty(sp)) {
Stack_T tmp = Stack_new();
while (!Stack_empty(sp)) {
AP_T x = pop();
Fmt_print("%D\n", x);
Stack_push(tmp, x);
}
while (!Stack_empty(tmp))
Stack_push(sp, Stack_pop(tmp));
Stack_free(&tmp);
}
break;
case '~': {
AP_T x = pop();
Stack_push(sp, AP_neg(x));
AP_free(&x);
break;
}
case 'c': while (!Stack_empty(sp)) {
AP_T x = Stack_pop(sp);
AP_free(&x);
} break;
case 'q': while (!Stack_empty(sp)) {
AP_T x = Stack_pop(sp);
AP_free(&x);
}
Stack_free(&sp);
return EXIT_SUCCESS;
default:
if (isprint(c))
Fmt_fprint(stderr, "?'%c'", c);
else
Fmt_fprint(stderr, "?'\\%03o'", c);
Fmt_fprint(stderr, " is unimplemented\n");
break;
}
while (!Stack_empty(sp)) {
AP_T x = Stack_pop(sp);
AP_free(&x);
}
Stack_free(&sp);
return EXIT_SUCCESS;
}
mp.h
#ifndef MP_INCLUDED
#define MP_INCLUDED
#include <stdarg.h>
#include <stddef.h>
#include "except.h"
#define T MP_T
typedef unsigned char *T;
extern const Except_T MP_Overflow;
extern const Except_T MP_Dividebyzero;
extern int MP_set(int n);
extern T MP_new(unsigned long u);
extern T MP_fromint (T z, long v);
extern T MP_fromintu(T z, unsigned long u);
extern unsigned long MP_tointu(T x);
extern long MP_toint (T x);
extern T MP_cvt (int m, T z, T x);
extern T MP_cvtu(int m, T z, T x);
extern T MP_add (T z, T x, T y);
extern T MP_sub (T z, T x, T y);
extern T MP_mul (T z, T x, T y);
extern T MP_div (T z, T x, T y);
extern T MP_mod (T z, T x, T y);
extern T MP_neg (T z, T x);
extern T MP_addu(T z, T x, T y);
extern T MP_subu(T z, T x, T y);
extern T MP_mulu(T z, T x, T y);
extern T MP_divu(T z, T x, T y);
extern T MP_modu(T z, T x, T y);
extern T MP_mul2u(T z, T x, T y);
extern T MP_mul2 (T z, T x, T y);
extern T MP_addi (T z, T x, long y);
extern T MP_subi (T z, T x, long y);
extern T MP_muli (T z, T x, long y);
extern T MP_divi (T z, T x, long y);
extern T MP_addui(T z, T x, unsigned long y);
extern T MP_subui(T z, T x, unsigned long y);
extern T MP_mului(T z, T x, unsigned long y);
extern T MP_divui(T z, T x, unsigned long y);
extern long MP_modi (T x, long y);
extern unsigned long MP_modui(T x, unsigned long y);
extern int MP_cmp (T x, T y);
extern int MP_cmpi (T x, long y);
extern int MP_cmpu (T x, T y);
extern int MP_cmpui(T x, unsigned long y);
extern T MP_and (T z, T x, T y);
extern T MP_or (T z, T x, T y);
extern T MP_xor (T z, T x, T y);
extern T MP_not (T z, T x);
extern T MP_andi(T z, T x, unsigned long y);
extern T MP_ori (T z, T x, unsigned long y);
extern T MP_xori(T z, T x, unsigned long y);
extern T MP_lshift(T z, T x, int s);
extern T MP_rshift(T z, T x, int s);
extern T MP_ashift(T z, T x, int s);
extern T MP_fromstr(T z, const char *str,
int base, char **end);
extern char *MP_tostr (char *str, int size,
int base, T x);
extern void MP_fmt (int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision);
extern void MP_fmtu (int code, va_list *app,
int put(int c, void *cl), void *cl,
unsigned char flags[], int width, int precision);
#undef T
#endif
mpcalc.c
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include "mem.h"
#include "seq.h"
#include "fmt.h"
#include "mp.h"
Seq_T sp;
int ibase = 10;
int obase = 10;
struct {
char *fmt;
MP_T (*add)(MP_T, MP_T, MP_T);
MP_T (*sub)(MP_T, MP_T, MP_T);
MP_T (*mul)(MP_T, MP_T, MP_T);
MP_T (*div)(MP_T, MP_T, MP_T);
MP_T (*mod)(MP_T, MP_T, MP_T);
} s = { "%D\n",
MP_add, MP_sub, MP_mul, MP_div, MP_mod },
u = { "%U\n",
MP_addu, MP_subu, MP_mulu, MP_divu, MP_modu },
*f = &s;
MP_T pop(void) {
if (Seq_length(sp) > 0)
return Seq_remhi(sp);
else {
Fmt_fprint(stderr, "?stack underflow\n");
return MP_new(0);
}
}
int main(int argc, char *argv[]) {
int c;
sp = Seq_new(0);
Fmt_register('D', MP_fmt);
Fmt_register('U', MP_fmtu);
while ((c = getchar()) != EOF) {
MP_T x = NULL, y = NULL, z = NULL;
TRY
switch (c) {
default:
if (isprint(c))
Fmt_fprint(stderr, "?'%c'", c);
else
Fmt_fprint(stderr, "?'\\%03o'", c);
Fmt_fprint(stderr, " is unimplemented\n");
break;
case ' ': case '\t': case '\n': case '\f': case '\r':
break;
case 'c': while (Seq_length(sp) > 0) {
MP_T x = Seq_remhi(sp);
FREE(x);
} break;
case 'q': while (Seq_length(sp) > 0) {
MP_T x = Seq_remhi(sp);
FREE(x);
}
Seq_free(&sp);
return EXIT_SUCCESS;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
char buf[512];
z = MP_new(0);
{
int i = 0;
for ( ; strchr(&"zyxwvutsrqponmlkjihgfedcba9876543210"[36-ibase],
tolower(c)); c = getchar(), i++)
if (i < (int)sizeof (buf) - 1)
buf[i] = c;
if (i > (int)sizeof (buf) - 1) {
i = (int)sizeof (buf) - 1;
Fmt_fprint(stderr,
"?integer constant exceeds %d digits\n", i);
}
buf[i] = '\0';
if (c != EOF)
ungetc(c, stdin);
}
MP_fromstr(z, buf, ibase, NULL);
break;
}
case '+': y = pop(); x = pop();
z = MP_new(0); (*f->add)(z, x, y); break;
case '-': y = pop(); x = pop();
z = MP_new(0); (*f->sub)(z, x, y); break;
case '*': y = pop(); x = pop();
z = MP_new(0); (*f->mul)(z, x, y); break;
case '/': y = pop(); x = pop();
z = MP_new(0); (*f->div)(z, x, y); break;
case '%': y = pop(); x = pop();
z = MP_new(0); (*f->mod)(z, x, y); break;
case '&': y = pop(); x = pop();
z = MP_new(0); MP_and(z, x, y); break;
case '|': y = pop(); x = pop();
z = MP_new(0); MP_or (z, x, y); break;
case '^': y = pop(); x = pop();
z = MP_new(0); MP_xor(z, x, y); break;
case '!': z = pop(); MP_not(z, z); break;
case '~': z = pop(); MP_neg(z, z); break;
case 'i': case 'o': {
long n;
x = pop();
n = MP_toint(x);
if (n < 2 || n > 36)
Fmt_fprint(stderr, "?%d is an illegal base\n",n);
else if (c == 'i')
ibase = n;
else
obase = n;
if (obase == 2 || obase == 8 || obase == 16)
f = &u;
else
f = &s;
break;
}
case 'p':
Fmt_print(f->fmt, z = pop(), obase);
break;
case 'f': {
int n = Seq_length(sp);
while (--n > 0)
Fmt_print(f->fmt, Seq_get(sp, n), obase);
break;
}
case '<': { long s;
y = pop();
z = pop();
s = MP_toint(y);
if (s < 0 || s > INT_MAX) {
Fmt_fprint(stderr,
"?%d is an illegal shift amount\n", s);
break;
}; MP_lshift(z, z, s); break; }
case '>': { long s;
y = pop();
z = pop();
s = MP_toint(y);
if (s < 0 || s > INT_MAX) {
Fmt_fprint(stderr,
"?%d is an illegal shift amount\n", s);
break;
}; MP_rshift(z, z, s); break; }
case 'k': {
long n;
x = pop();
n = MP_toint(x);
if (n < 2 || n > INT_MAX)
Fmt_fprint(stderr,
"?%d is an illegal precision\n", n);
else if (Seq_length(sp) > 0)
Fmt_fprint(stderr, "?nonempty stack\n");
else
MP_set(n);
break;
}
case 'd': {
MP_T x = pop();
z = MP_new(0);
Seq_addhi(sp, x);
MP_addui(z, x, 0);
break;
}
}
EXCEPT(MP_Overflow)
Fmt_fprint(stderr, "?overflow\n");
EXCEPT(MP_Dividebyzero)
Fmt_fprint(stderr, "?divide by 0\n");
END_TRY;
if (z)
Seq_addhi(sp, z);
FREE(x);
FREE(y);
}
while (Seq_length(sp) > 0) {
MP_T x = Seq_remhi(sp);
FREE(x);
}
Seq_free(&sp);
return EXIT_SUCCESS;
}
thread.h
#ifndef THREAD_INCLUDED
#define THREAD_INCLUDED
#include "except.h"
#define T Thread_T
typedef struct T *T;
extern const Except_T Thread_Failed;
extern const Except_T Thread_Alerted;
extern int Thread_init (int preempt, ...);
extern T Thread_new (int apply(void *),
void *args, int nbytes, ...);
extern void Thread_exit (int code);
extern void Thread_alert(T t);
extern T Thread_self (void);
extern int Thread_join (T t);
extern void Thread_pause(void);
#undef T
#endif
sem.h
#ifndef SEM_INCLUDED
#define SEM_INCLUDED
#define T Sem_T
typedef struct T {
int count;
void *queue;
} T;
#define LOCK(mutex) do { Sem_T *_yymutex = &(mutex); \
Sem_wait(_yymutex);
#define END_LOCK Sem_signal(_yymutex); } while (0)
extern void Sem_init (T *s, int count);
extern T *Sem_new (int count);
extern void Sem_wait (T *s);
extern void Sem_signal(T *s);
#undef T
#endif
thread.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include </usr/include/signal.h>
#include <sys/time.h>
#include "assert.h"
#include "mem.h"
#include "thread.h"
#include "sem.h"
void _MONITOR(void) {}
extern void _ENDMONITOR(void);
#define T Thread_T
#define isempty(q) ((q) == NULL)
struct T {
unsigned long *sp; /* must be first */
T link;
T *inqueue;
T handle;
Except_Frame *estack;
int code;
T join;
T next;
int alerted;
};
static T ready = NULL;
static T current;
static int nthreads;
static struct Thread_T root;
static T join0;
static T freelist;
const Except_T Thread_Alerted = { "Thread alerted" };
const Except_T Thread_Failed =
{ "Thread creation failed" };
static int critical;
extern void _swtch(T from, T to);
static void put(T t, T *q) {
assert(t);
assert(t->inqueue == NULL && t->link == NULL);
if (*q) {
t->link = (*q)->link;
(*q)->link = t;
} else
t->link = t;
*q = t;
t->inqueue = q;
}
static T get(T *q) {
T t;
assert(!isempty(*q));
t = (*q)->link;
if (t == *q)
*q = NULL;
else
(*q)->link = t->link;
assert(t->inqueue == q);
t->link = NULL;
t->inqueue = NULL;
return t;
}
static void delete(T t, T *q) {
T p;
assert(t->link && t->inqueue == q);
assert(!isempty(*q));
for (p = *q; p->link != t; p = p->link)
;
if (p == t)
*q = NULL;
else {
p->link = t->link;
if (*q == t)
*q = p;
}
t->link = NULL;
t->inqueue = NULL;
}
static void run(void) {
T t = current;
current = get(&ready);
t->estack = Except_stack;
Except_stack = current->estack;
_swtch(t, current);
}
static void testalert(void) {
if (current->alerted) {
current->alerted = 0;
RAISE(Thread_Alerted);
}
}
static void release(void) {
T t;
do { critical++;
while ((t = freelist) != NULL) {
freelist = t->next;
FREE(t);
}
critical--; } while (0);
}
#if linux
#include <asm/sigcontext.h>
static int interrupt(int sig, struct sigcontext_struct sc) {
if (critical ||
sc.eip >= (unsigned long)_MONITOR
&& sc.eip <= (unsigned long)_ENDMONITOR)
return 0;
put(current, &ready);
do { critical++;
sigsetmask(sc.oldmask);
critical--; } while (0);
run();
return 0;
}
#else
static int interrupt(int sig, int code,
struct sigcontext *scp) {
if (critical ||
scp->sc_pc >= (unsigned long)_MONITOR
&& scp->sc_pc <= (unsigned long)_ENDMONITOR)
return 0;
put(current, &ready);
sigsetmask(scp->sc_mask);
run();
return 0;
}
#endif
int Thread_init(int preempt, ...) {
assert(preempt == 0 || preempt == 1);
assert(current == NULL);
root.handle = &root;
current = &root;
nthreads = 1;
if (preempt) {
{
struct sigaction sa;
memset(&sa, '\0', sizeof sa);
sa.sa_handler = (void (*)())interrupt;
if (sigaction(SIGVTALRM, &sa, NULL) < 0)
return 0;
}
{
struct itimerval it;
it.it_value.tv_sec = 0;
it.it_value.tv_usec = 50;
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 50;
if (setitimer(ITIMER_VIRTUAL, &it, NULL) < 0)
return 0;
}
}
return 1;
}
T Thread_self(void) {
assert(current);
return current;
}
void Thread_pause(void) {
assert(current);
put(current, &ready);
run();
}
int Thread_join(T t) {
assert(current && t != current);
testalert();
if (t) {
if (t->handle == t) {
put(current, &t->join);
run();
testalert();
return current->code;
} else
return -1;
} else {
assert(isempty(join0));
if (nthreads > 1) {
put(current, &join0);
run();
testalert();
}
return 0;
}
}
void Thread_exit(int code) {
assert(current);
release();
if (current != &root) {
current->next = freelist;
freelist = current;
}
current->handle = NULL;
while (!isempty(current->join)) {
T t = get(¤t->join);
t->code = code;
put(t, &ready);
}
if (!isempty(join0) && nthreads == 2) {
assert(isempty(ready));
put(get(&join0), &ready);
}
if (--nthreads == 0)
exit(code);
else
run();
}
void Thread_alert(T t) {
assert(current);
assert(t && t->handle == t);
t->alerted = 1;
if (t->inqueue) {
delete(t, t->inqueue);
put(t, &ready);
}
}
T Thread_new(int apply(void *), void *args,
int nbytes, ...) {
T t;
assert(current);
assert(apply);
assert(args && nbytes >= 0 || args == NULL);
if (args == NULL)
nbytes = 0;
{
int stacksize = (16*1024+sizeof (*t)+nbytes+15)&~15;
release();
do { critical++;
TRY
t = ALLOC(stacksize);
memset(t, '\0', sizeof *t);
EXCEPT(Mem_Failed)
t = NULL;
END_TRY;
critical--; } while (0);
if (t == NULL)
RAISE(Thread_Failed);
t->sp = (void *)((char *)t + stacksize);
while (((unsigned long)t->sp)&15)
t->sp--;
}
t->handle = t;
if (nbytes > 0) {
t->sp -= ((nbytes + 15U)&~15)/sizeof (*t->sp);
do { critical++;
memcpy(t->sp, args, nbytes);
critical--; } while (0);
args = t->sp;
}
#if alpha
{ extern void _start(void);
t->sp -= 112/8;
t->sp[(48+24)/8] = (unsigned long)Thread_exit;
t->sp[(48+16)/8] = (unsigned long)args;
t->sp[(48+ 8)/8] = (unsigned long)apply;
t->sp[(48+ 0)/8] = (unsigned long)_start; }
#elif mips
{ extern void _start(void);
t->sp -= 16/4;
t->sp -= 88/4;
t->sp[(48+20)/4] = (unsigned long)Thread_exit;
t->sp[(48+28)/4] = (unsigned long)args;
t->sp[(48+32)/4] = (unsigned long)apply;
t->sp[(48+36)/4] = (unsigned long)_start; }
#elif sparc
{ int i; void *fp; extern void _start(void);
for (i = 0; i < 8; i++)
*--t->sp = 0;
*--t->sp = (unsigned long)args;
*--t->sp = (unsigned long)apply;
t->sp -= 64/4;
fp = t->sp;
*--t->sp = (unsigned long)_start - 8;
*--t->sp = (unsigned long)fp;
t->sp -= 64/4; }
#elif linux && i386
{ extern void _thrstart(void);
t->sp -= 4/4;
*t->sp = (unsigned long)_thrstart;
t->sp -= 16/4;
t->sp[4/4] = (unsigned long)apply;
t->sp[8/4] = (unsigned long)args;
t->sp[12/4] = (unsigned long)t->sp + (4+16)/4; }
#else
Unsupported platform
#endif
nthreads++;
put(t, &ready);
return t;
}
#undef T
#define T Sem_T
T *Sem_new(int count) {
T *s;
NEW(s);
Sem_init(s, count);
return s;
}
void Sem_init(T *s, int count) {
assert(current);
assert(s);
s->count = count;
s->queue = NULL;
}
void Sem_wait(T *s) {
assert(current);
assert(s);
testalert();
if (s->count <= 0) {
put(current, (Thread_T *)&s->queue);
run();
testalert();
} else
--s->count;
}
void Sem_signal(T *s) {
assert(current);
assert(s);
if (s->count == 0 && !isempty(s->queue)) {
Thread_T t = get((Thread_T *)&s->queue);
assert(!t->alerted);
put(t, &ready);
} else
++s->count;
}
#undef T
thread-nt.c
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <windows.h>
#include <process.h>
#include "assert.h"
#include "mem.h"
#include "thread.h"
#include "sem.h"
static char rcsid[] = "$Id: thread-nt.c,v 1.5 1997/07/29 17:10:25 drh Exp $";
#define T Thread_T
struct T {
DWORD IDThread; /* Win 32 thread identifier */
T handle; /* self pointer */
int code; /* exit code */
HANDLE join; /* join semaphore */
T joinlist; /* threads waiting on join */
T link; /* next thread on this join list */
T next; /* next thread on this hash chain */
int alerted; /* 1 if this thread has been alerted */
int (*apply)(void *); /* initial function for this thread */
void *args; /* argument for apply */
};
const Except_T Thread_Alerted = { "Thread alerted" };
const Except_T Thread_Failed = { "Thread creation failed" };
static T allthreads[317];
#define HASH(id) ((int)((id)%(sizeof allthreads/sizeof allthreads[0])))
static int nthreads; /* number of threads in allthreads */
static T root;
static HANDLE join0; /* Thread_join(NULL) semaphore */
static int join0count; /* number of threads waiting on join0; always 0 or 1 */
static int critical;
static CRITICAL_SECTION csection;
#define ENTERCRITICAL EnterCriticalSection(&csection); assert(critical == 0); critical++
#define LEAVECRITICAL critical--; assert(critical == 0); LeaveCriticalSection(&csection)
static T getThreadByID(DWORD id) {
T t;
ENTERCRITICAL;
for (t = allthreads[HASH(id)]; t != NULL; t = t->next)
if (t->IDThread == id)
break;
LEAVECRITICAL;
assert(t);
return t;
}
static void removeThread(T t) {
T *q;
ENTERCRITICAL;
q = &allthreads[HASH(t->IDThread)];
for ( ; *q != NULL && *q != t; q = &(*q)->next)
;
assert(*q == t);
*q = t->next;
nthreads--;
t->handle = NULL;
LEAVECRITICAL;
}
static void addThread(T t) {
T *q;
ENTERCRITICAL;
q = &allthreads[HASH(t->IDThread)];
t->next = *q;
*q = t;
nthreads++;
t->handle = t;
LEAVECRITICAL;
}
static void testalert(T t) {
ENTERCRITICAL;
if (t->alerted) {
t->alerted = 0;
LEAVECRITICAL;
RAISE(Thread_Alerted);
}
LEAVECRITICAL;
}
int Thread_init(int preempt, ...) {
assert(preempt == 0 || preempt == 1);
assert(root == NULL);
TRY
NEW0(root);
EXCEPT(Mem_Failed)
return -1;
END_TRY;
join0 = CreateSemaphore(NULL, 0, 1, NULL);
if (join0 == NULL)
return -1;
root->join = CreateSemaphore(NULL, 0, INT_MAX, NULL);
if (root->join == NULL) {
BOOL result = CloseHandle(join0);
assert(result == TRUE);
return -1;
}
InitializeCriticalSection(&csection);
root->IDThread = GetCurrentThreadId();
addThread(root);
/* handle preempt == 0 */
return 1;
}
T Thread_self(void) {
assert(root);
return getThreadByID(GetCurrentThreadId());
}
void Thread_pause(void) {
assert(root);
Sleep(0);
}
int Thread_join(T t) {
T current = Thread_self();
assert(root);
assert(t != current);
testalert(current);
if (t != NULL) {
ENTERCRITICAL;
if (t->handle == t) {
HANDLE join = t->join;
DWORD result;
assert(current->link == NULL);
current->link = t->joinlist;
t->joinlist = current;
LEAVECRITICAL;
result = WaitForSingleObject(join, INFINITE);
assert(result != WAIT_FAILED);
testalert(current);
return current->code;
} else {
LEAVECRITICAL;
return -1;
}
}
ENTERCRITICAL;
if (nthreads > 1) {
DWORD result;
assert(join0count == 0);
join0count++;
LEAVECRITICAL;
result = WaitForSingleObject(join0, INFINITE);
assert(result != WAIT_FAILED);
ENTERCRITICAL;
join0count--;
LEAVECRITICAL;
testalert(current);
} else {
assert(join0count == 0);
LEAVECRITICAL;
return 0;
}
}
void Thread_exit(int code) {
BOOL result;
T current = Thread_self();
removeThread(current);
ENTERCRITICAL;
if (current->joinlist != NULL) {
T t, n;
int count = 0;
assert(current->join);
for (t = current->joinlist; t != NULL; t = n) {
t->code = code;
n = t->link;
t->link = NULL;
count++;
}
current->joinlist = NULL;
result = ReleaseSemaphore(current->join, count, NULL);
assert(result == TRUE);
}
result = CloseHandle(current->join);
assert(result == TRUE);
current->join = NULL;
if (join0count > 0 && nthreads == 1) {
assert(join0count == 1);
result = ReleaseSemaphore(join0, 1, NULL);
assert(result == TRUE);
}
if (nthreads == 0) {
result = CloseHandle(join0);
assert(result == TRUE);
}
FREE(current);
LEAVECRITICAL;
_endthreadex(code);
}
void Thread_alert(T t) {
assert(root);
ENTERCRITICAL;
assert(t && t->handle == t);
t->alerted = 1;
LEAVECRITICAL;
}
static unsigned __stdcall start(void *p) {
T t = p;
Except_stack = NULL;
Thread_exit((*t->apply)(t->args));
return 0;
}
T Thread_new(int apply(void *), void *args, int nbytes, ...) {
T t;
HANDLE hThread;
assert(root);
assert(apply);
assert(args && nbytes >= 0 || args == NULL);
if (args == NULL)
nbytes = 0;
TRY
t = ALLOC((sizeof (*t) + nbytes + 15)&~15);
memset(t, '\0', sizeof *t);
EXCEPT(Mem_Failed)
RAISE(Thread_Failed);
END_TRY;
t->join = CreateSemaphore(NULL, 0, INT_MAX, NULL);
if (t->join == NULL) {
FREE(t);
RAISE(Thread_Failed);
}
if (nbytes > 0) {
t->args = t + 1;
memcpy(t->args, args, nbytes);
} else
t->args = args;
t->apply = apply;
hThread = (HANDLE)_beginthreadex(
NULL, /* default security attributes */
0, /* default stack size */
start, /* initial function */
t, /* start's argument */
0, /* default thread creation flags */
&t->IDThread /* where to store the thread id */
);
if (hThread == NULL) {
CloseHandle(t->join);
FREE(t);
RAISE(Thread_Failed);
}
CloseHandle(hThread);
addThread(t);
return t;
}
#undef T
#define T Sem_T
T *Sem_new(int count) {
T *s;
NEW(s);
Sem_init(s, count);
return s;
}
void Sem_init(T *s, int count) {
assert(root);
assert(s);
assert(count >= 0);
s->count = 0;
s->queue = CreateSemaphore(NULL, count, INT_MAX, NULL);
assert(s->queue);
}
void Sem_wait(T *s) {
DWORD result;
Thread_T current = Thread_self();
assert(s);
testalert(current);
result = WaitForSingleObject(s->queue, INFINITE);
assert(result != WAIT_FAILED);
ENTERCRITICAL;
if (current->alerted) {
BOOL result;
current->alerted = 0;
LEAVECRITICAL;
result = ReleaseSemaphore(s->queue, 1, NULL);
assert(result == TRUE);
RAISE(Thread_Alerted);
}
LEAVECRITICAL;
}
void Sem_signal(T *s) {
BOOL result;
assert(root);
assert(s);
result = ReleaseSemaphore(s->queue, 1, NULL);
assert(result == TRUE);
}
#undef T
chan.h
#ifndef CHAN_INCLUDED
#define CHAN_INCLUDED
#define T Chan_T
typedef struct T *T;
extern T Chan_new (void);
extern int Chan_send (T c, const void *ptr, int size);
extern int Chan_receive(T c, void *ptr, int size);
#undef T
#endif
chain.c
#include <string.h>
#include "assert.h"
#include "mem.h"
#include "chan.h"
#include "sem.h"
#define T Chan_T
struct T {
const void *ptr;
int *size;
Sem_T send, recv, sync;
};
T Chan_new(void) {
T c;
NEW(c);
Sem_init(&c->send, 1);
Sem_init(&c->recv, 0);
Sem_init(&c->sync, 0);
return c;
}
int Chan_send(Chan_T c, const void *ptr, int size) {
assert(c);
assert(ptr);
assert(size >= 0);
Sem_wait(&c->send);
c->ptr = ptr;
c->size = &size;
Sem_signal(&c->recv);
Sem_wait(&c->sync);
return size;
}
int Chan_receive(Chan_T c, void *ptr, int size) {
int n;
assert(c);
assert(ptr);
assert(size >= 0);
Sem_wait(&c->recv);
n = *c->size;
if (size < n)
n = size;
*c->size = n;
if (n > 0)
memcpy(ptr, c->ptr, n);
Sem_signal(&c->sync);
Sem_signal(&c->send);
return n;
}
sort.c
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "assert.h"
#include "fmt.h"
#include "thread.h"
#include "mem.h"
struct args {
int *a;
int lb, ub;
};
int cutoff = 10000;
int partition(int a[], int i, int j) {
int v, k, t;
j++;
k = i;
v = a[k];
while (i < j) {
i++; while (a[i] < v && i < j) i++;
j--; while (a[j] > v ) j--;
if (i < j) { t = a[i]; a[i] = a[j]; a[j] = t; }
}
t = a[k]; a[k] = a[j]; a[j] = t;
return j;
}
int quick(void *cl) {
struct args *p = cl;
int lb = p->lb, ub = p->ub;
if (lb < ub) {
int k = partition(p->a, lb, ub);
p->lb = lb;
p->ub = k - 1;
if (k - lb > cutoff) {
Thread_T t;
t = Thread_new(quick, p, sizeof *p, NULL);
Fmt_print("thread %p sorted %d..%d\n", t, lb, k - 1);
} else
quick(p);
p->lb = k + 1;
p->ub = ub;
if (ub - k > cutoff) {
Thread_T t;
t = Thread_new(quick, p, sizeof *p, NULL);
Fmt_print("thread %p sorted %d..%d\n", t, k + 1, ub);
} else
quick(p);
}
return EXIT_SUCCESS;
}
void sort(int *x, int n, int argc, char *argv[]) {
struct args args;
if (argc >= 3)
cutoff = atoi(argv[2]);
args.a = x;
args.lb = 0;
args.ub = n - 1;
quick(&args);
Thread_join(NULL);
}
main(int argc, char *argv[]) {
int i, n = 100000, *x, preempt;
preempt = Thread_init(1, NULL);
assert(preempt == 1);
if (argc >= 2)
n = atoi(argv[1]);
x = CALLOC(n, sizeof (int));
srand(time(NULL));
for (i = 0; i < n; i++)
x[i] = rand();
sort(x, n, argc, argv);
for (i = 1; i < n; i++)
if (x[i] < x[i-1])
break;
assert(i == n);
Thread_exit(EXIT_SUCCESS);
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
#include "assert.h"
#include "fmt.h"
#include "thread.h"
#include "sem.h"
#define NBUMP 30000
struct args {
Sem_T *mutex;
int *ip;
};
int unsafe(void *cl) {
int i, *ip = cl;
for (i = 0; i < NBUMP; i++)
*ip = *ip + 1;
return EXIT_SUCCESS;
}
int safe(void *cl) {
struct args *p = cl;
int i;
for (i = 0; i < NBUMP; i++)
LOCK(*p->mutex)
*p->ip = *p->ip + 1;
END_LOCK;
return EXIT_SUCCESS;
}
int n;
int main(int argc, char *argv[]) {
int m = 5, preempt;
preempt = Thread_init(1, NULL);
assert(preempt == 1);
if (argc >= 2)
m = atoi(argv[1]);
n = 0;
{
int i;
for (i = 0; i < m; i++)
Thread_new(unsafe, &n, 0, NULL);
Thread_join(NULL);
}
Fmt_print("%d == %d\n", n, NBUMP*m);
n = 0;
{
int i;
struct args args;
Sem_T mutex;
Sem_init(&mutex, 1);
args.mutex = &mutex;
args.ip = &n;
for (i = 0; i < m; i++)
Thread_new(safe, &args, sizeof args, NULL);
Thread_join(NULL);
}
Fmt_print("%d == %d\n", n, NBUMP*m);
Thread_exit(EXIT_SUCCESS);
return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
#include "assert.h"
#include "fmt.h"
#include "thread.h"
#include "chan.h"
struct args {
Chan_T c;
int n, last;
};
int source(void *cl) {
struct args *p = cl;
int i = 2;
if (Chan_send(p->c, &i, sizeof i))
for (i = 3; Chan_send(p->c, &i, sizeof i); )
i += 2;
return EXIT_SUCCESS;
}
void filter(int primes[], Chan_T input, Chan_T output) {
int j, x;
for (;;) {
Chan_receive(input, &x, sizeof x);
for (j = 0; primes[j] != 0 && x%primes[j] != 0; j++)
;
if (primes[j] == 0)
if (Chan_send(output, &x, sizeof x) == 0)
break;
}
Chan_receive(input, &x, 0);
}
int sink(void *cl) {
struct args *p = cl;
Chan_T input = p->c;
int i = 0, j, x, primes[256];
primes[0] = 0;
for (;;) {
Chan_receive(input, &x, sizeof x);
for (j = 0; primes[j] != 0 && x%primes[j] != 0; j++)
;
if (primes[j] == 0) {
if (x > p->last)
break;
Fmt_print(" %d", x);
primes[i++] = x;
primes[i] = 0;
if (i == p->n)
{
p->c = Chan_new();
Thread_new(sink, p, sizeof *p, NULL);
filter(primes, input, p->c);
return EXIT_SUCCESS;
}
}
}
Fmt_print("\n");
Chan_receive(input, &x, 0);
return EXIT_SUCCESS;
}
int main(int argc, char *argv[]) {
struct args args;
Thread_init(1, NULL);
args.c = Chan_new();
Thread_new(source, &args, sizeof args, NULL);
args.n = argc > 2 ? atoi(argv[2]) : 5;
args.last = argc > 1 ? atoi(argv[1]) : 1000;
Thread_new(sink, &args, sizeof args, NULL);
Thread_exit(EXIT_SUCCESS);
return EXIT_SUCCESS;
}