/* * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. * * Permission is hereby granted to use or copy this program * for any purpose, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice.
*/
/* * These are functions on cords that do not need to understand their * implementation. They serve also serve as example client code for * cord_basics.
*/
# include <stdio.h> # include <string.h> # include <stdlib.h> # include <stdarg.h>
# include "cord.h" # include "ec.h"
# define I_HIDE_POINTERS /* So we get access to allocation lock. */ /* We use this for lazy file reading, */ /* so that we remain independent */ /* of the threads primitives. */ # include "gc.h"
/* For now we assume that pointer reads and writes are atomic, */ /* i.e. another thread always sees the state before or after */ /* a write. This might be false on a Motorola M68K with */ /* pointers that are not 32-bit aligned. But there probably */ /* aren't too many threads packages running on those. */ # define ATOMIC_WRITE(x,y) (x) = (y) # define ATOMIC_READ(x) (*(x))
/* The standard says these are in stdio.h, but they aren't always: */ # ifndef SEEK_SET # define SEEK_SET 0 # endif # ifndef SEEK_END # define SEEK_END 2 # endif
# define BUFSZ 2048 /* Size of stack allocated buffers when */ /* we want large buffers. */
CORD CORD_catn(int nargs, ...)
{
CORD result = CORD_EMPTY;
va_list args; int i;
va_start(args, nargs); for (i = 0; i < nargs; i++) {
CORD next = va_arg(args, CORD);
result = CORD_cat(result, next);
}
va_end(args); return(result);
}
int CORD_fill_proc(char c, void * client_data)
{
CORD_fill_data * d = (CORD_fill_data *)client_data;
size_t count = d -> count;
(d -> buf)[count] = c;
d -> count = ++count; if (count >= d -> len) { return(1);
} else { return(0);
}
}
int CORD_batched_fill_proc(constchar * s, void * client_data)
{
CORD_fill_data * d = (CORD_fill_data *)client_data;
size_t count = d -> count;
size_t max = d -> len; char * buf = d -> buf; constchar * t = s;
while((buf[count] = *t++) != '\0') {
count++; if (count >= max) {
d -> count = count; return(1);
}
}
d -> count = count; return(0);
}
/* Fill buf with len characters starting at i. */ /* Assumes len characters are available in buf. */ /* Return 1 if buf is filled fully (and len is */ /* non-zero), 0 otherwise. */ int CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
{
CORD_fill_data fd;
int CORD_cmp(CORD x, CORD y)
{
CORD_pos xpos;
CORD_pos ypos;
if (y == CORD_EMPTY) return(x != CORD_EMPTY); if (x == CORD_EMPTY) return(-1); if (CORD_IS_STRING(y) && CORD_IS_STRING(x)) return(strcmp(x,y));
CORD_set_pos(xpos, x, 0);
CORD_set_pos(ypos, y, 0); for(;;) {
size_t avail, yavail;
if (!CORD_pos_valid(xpos)) { if (CORD_pos_valid(ypos)) { return(-1);
} else { return(0);
}
} if (!CORD_pos_valid(ypos)) { return(1);
}
avail = CORD_pos_chars_left(xpos); if (avail == 0
|| (yavail = CORD_pos_chars_left(ypos)) == 0) { char xcurrent = CORD_pos_fetch(xpos); char ycurrent = CORD_pos_fetch(ypos); if (xcurrent != ycurrent) return(xcurrent - ycurrent);
CORD_next(xpos);
CORD_next(ypos);
} else { /* process as many characters as we can */ int result;
if (avail > yavail) avail = yavail;
result = strncmp(CORD_pos_cur_char_addr(xpos),
CORD_pos_cur_char_addr(ypos), avail); if (result != 0) return(result);
CORD_pos_advance(xpos, avail);
CORD_pos_advance(ypos, avail);
}
}
}
int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
{
CORD_pos xpos;
CORD_pos ypos;
size_t count;
CORD_set_pos(xpos, x, x_start);
CORD_set_pos(ypos, y, y_start); for(count = 0; count < len;) { long avail, yavail;
if (!CORD_pos_valid(xpos)) { if (CORD_pos_valid(ypos)) { return(-1);
} else { return(0);
}
} if (!CORD_pos_valid(ypos)) { return(1);
} if ((avail = CORD_pos_chars_left(xpos)) <= 0
|| (yavail = CORD_pos_chars_left(ypos)) <= 0) { char xcurrent = CORD_pos_fetch(xpos); char ycurrent = CORD_pos_fetch(ypos);
if (xcurrent != ycurrent) return(xcurrent - ycurrent);
CORD_next(xpos);
CORD_next(ypos);
count++;
} else { /* process as many characters as we can */ int result;
if (avail > yavail) avail = yavail;
count += avail; if (count > len)
avail -= (long)(count - len);
result = strncmp(CORD_pos_cur_char_addr(xpos),
CORD_pos_cur_char_addr(ypos), (size_t)avail); if (result != 0) return(result);
CORD_pos_advance(xpos, (size_t)avail);
CORD_pos_advance(ypos, (size_t)avail);
}
} return(0);
}
char * CORD_to_char_star(CORD x)
{
size_t len = CORD_len(x); char * result = (char *)GC_MALLOC_ATOMIC(len + 1);
typedefstruct {
size_t pos; /* Current position in the cord */ char target; /* Character we're looking for */
} chr_data;
int CORD_chr_proc(char c, void * client_data)
{
chr_data * d = (chr_data *)client_data;
if (c == d -> target) return(1);
(d -> pos) ++; return(0);
}
int CORD_rchr_proc(char c, void * client_data)
{
chr_data * d = (chr_data *)client_data;
if (c == d -> target) return(1);
(d -> pos) --; return(0);
}
int CORD_batched_chr_proc(constchar *s, void * client_data)
{
chr_data * d = (chr_data *)client_data; constchar * occ = strchr(s, d -> target);
if (NULL == occ) {
d -> pos += strlen(s); return(0);
} else {
d -> pos += occ - s; return(1);
}
}
size_t CORD_chr(CORD x, size_t i, int c)
{
chr_data d;
d.pos = i;
d.target = (char)c; if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) { return(d.pos);
} else { return(CORD_NOT_FOUND);
}
}
size_t CORD_rchr(CORD x, size_t i, int c)
{
chr_data d;
d.pos = i;
d.target = (char)c; if (CORD_riter4(x, i, CORD_rchr_proc, &d)) { return(d.pos);
} else { return(CORD_NOT_FOUND);
}
}
/* Find the first occurrence of s in x at position start or later. */ /* This uses an asymptotically poor algorithm, which should typically */ /* perform acceptably. We compare the first few characters directly, */ /* and call CORD_ncmp whenever there is a partial match. */ /* This has the advantage that we allocate very little, or not at all. */ /* It's very fast if there are few close misses. */
size_t CORD_str(CORD x, size_t start, CORD s)
{
CORD_pos xpos;
size_t xlen = CORD_len(x);
size_t slen;
size_t start_len; constchar * s_start; unsignedlong s_buf = 0; /* The first few characters of s */ unsignedlong x_buf = 0; /* Start of candidate substring. */ /* Initialized only to make compilers */ /* happy. */ unsignedlong mask = 0;
size_t i;
size_t match_pos;
if (c == 0) { /* Append the right number of NULs */ /* Note that any string of NULs is represented in 4 words, */ /* independent of its length. */
size_t count = 1;
/* The state maintained for a lazily read file consists primarily */ /* of a large direct-mapped cache of previously read values. */ /* We could rely more on stdio buffering. That would have 2 */ /* disadvantages: */ /* 1) Empirically, not all fseek implementations preserve the */ /* buffer whenever they could. */ /* 2) It would fail if 2 different sections of a long cord */ /* were being read alternately. */ /* We do use the stdio buffer for read ahead. */ /* To guarantee thread safety in the presence of atomic pointer */ /* writes, cache lines are always replaced, and never modified in */ /* place. */
CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
{
lf_state * state = GC_NEW(lf_state); int i;
if (state == 0) OUT_OF_MEMORY; if (len != 0) { /* Dummy read to force buffer allocation. */ /* This greatly increases the probability */ /* of avoiding deadlock if buffer allocation */ /* is redirected to GC_malloc and the */ /* world is multi-threaded. */ char buf[1];
if (fread(buf, 1, 1, f) > 1
|| fseek(f, 0l, SEEK_SET) != 0) {
ABORT("Bad f argument or I/O failure");
}
}
state -> lf_file = f; for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
state -> lf_cache[i] = 0;
}
state -> lf_current = 0; # ifndef GC_NO_FINALIZATION
GC_REGISTER_FINALIZER(state, CORD_lf_close_proc, 0, 0, 0); # endif return(CORD_from_fn(CORD_lf_func, state, len));
}
CORD CORD_from_file_lazy(FILE * f)
{ long len;
if (fseek(f, 0l, SEEK_END) != 0
|| (len = ftell(f)) < 0
|| fseek(f, 0l, SEEK_SET) != 0) {
ABORT("Bad f argument or I/O failure");
} return(CORD_from_file_lazy_inner(f, (size_t)len));
}
# define LAZY_THRESHOLD (128*1024 + 1)
CORD CORD_from_file(FILE * f)
{ long len;
if (fseek(f, 0l, SEEK_END) != 0
|| (len = ftell(f)) < 0
|| fseek(f, 0l, SEEK_SET) != 0) {
ABORT("Bad f argument or I/O failure");
} if (len < LAZY_THRESHOLD) { return(CORD_from_file_eager(f));
} else { return(CORD_from_file_lazy_inner(f, (size_t)len));
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.