OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [boehm-gc/] [cord/] [cordxtra.c] - Blame information for rev 780

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 721 jeremybenn
/*
2
 * Copyright (c) 1993-1994 by Xerox Corporation.  All rights reserved.
3
 *
4
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
6
 *
7
 * Permission is hereby granted to use or copy this program
8
 * for any purpose,  provided the above notices are retained on all copies.
9
 * Permission to modify the code and to distribute modified code is granted,
10
 * provided the above notices are retained, and a notice that the code was
11
 * modified is included with the above copyright notice.
12
 *
13
 * Author: Hans-J. Boehm (boehm@parc.xerox.com)
14
 */
15
/*
16
 * These are functions on cords that do not need to understand their
17
 * implementation.  They serve also serve as example client code for
18
 * cord_basics.
19
 */
20
/* Boehm, December 8, 1995 1:53 pm PST */
21
# include <stdio.h>
22
# include <string.h>
23
# include <stdlib.h>
24
# include <stdarg.h>
25
# include "cord.h"
26
# include "ec.h"
27
# define I_HIDE_POINTERS        /* So we get access to allocation lock. */
28
                                /* We use this for lazy file reading,   */
29
                                /* so that we remain independent        */
30
                                /* of the threads primitives.           */
31
# include "gc.h"
32
 
33
/* For now we assume that pointer reads and writes are atomic,  */
34
/* i.e. another thread always sees the state before or after    */
35
/* a write.  This might be false on a Motorola M68K with        */
36
/* pointers that are not 32-bit aligned.  But there probably    */
37
/* aren't too many threads packages running on those.           */
38
# define ATOMIC_WRITE(x,y) (x) = (y)
39
# define ATOMIC_READ(x) (*(x))
40
 
41
/* The standard says these are in stdio.h, but they aren't always: */
42
# ifndef SEEK_SET
43
#   define SEEK_SET 0
44
# endif
45
# ifndef SEEK_END
46
#   define SEEK_END 2
47
# endif
48
 
49
# define BUFSZ 2048     /* Size of stack allocated buffers when         */
50
                        /* we want large buffers.                       */
51
 
52
typedef void (* oom_fn)(void);
53
 
54
# define OUT_OF_MEMORY {  if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
55
                          ABORT("Out of memory\n"); }
56
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
57
 
58
CORD CORD_cat_char(CORD x, char c)
59
{
60
    register char * string;
61
 
62
    if (c == '\0') return(CORD_cat(x, CORD_nul(1)));
63
    string = GC_MALLOC_ATOMIC(2);
64
    if (string == 0) OUT_OF_MEMORY;
65
    string[0] = c;
66
    string[1] = '\0';
67
    return(CORD_cat_char_star(x, string, 1));
68
}
69
 
70
CORD CORD_catn(int nargs, ...)
71
{
72
    register CORD result = CORD_EMPTY;
73
    va_list args;
74
    register int i;
75
 
76
    va_start(args, nargs);
77
    for (i = 0; i < nargs; i++) {
78
        register CORD next = va_arg(args, CORD);
79
        result = CORD_cat(result, next);
80
    }
81
    va_end(args);
82
    return(result);
83
}
84
 
85
typedef struct {
86
        size_t len;
87
        size_t count;
88
        char * buf;
89
} CORD_fill_data;
90
 
91
int CORD_fill_proc(char c, void * client_data)
92
{
93
    register CORD_fill_data * d = (CORD_fill_data *)client_data;
94
    register size_t count = d -> count;
95
 
96
    (d -> buf)[count] = c;
97
    d -> count = ++count;
98
    if (count >= d -> len) {
99
        return(1);
100
    } else {
101
        return(0);
102
    }
103
}
104
 
105
int CORD_batched_fill_proc(const char * s, void * client_data)
106
{
107
    register CORD_fill_data * d = (CORD_fill_data *)client_data;
108
    register size_t count = d -> count;
109
    register size_t max = d -> len;
110
    register char * buf = d -> buf;
111
    register const char * t = s;
112
 
113
    while((buf[count] = *t++) != '\0') {
114
        count++;
115
        if (count >= max) {
116
            d -> count = count;
117
            return(1);
118
        }
119
    }
120
    d -> count = count;
121
    return(0);
122
}
123
 
124
/* Fill buf with len characters starting at i.                          */
125
/* Assumes len characters are available.                                */
126
void CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
127
{
128
    CORD_fill_data fd;
129
 
130
    fd.len = len;
131
    fd.buf = buf;
132
    fd.count = 0;
133
    (void)CORD_iter5(x, i, CORD_fill_proc, CORD_batched_fill_proc, &fd);
134
}
135
 
136
int CORD_cmp(CORD x, CORD y)
137
{
138
    CORD_pos xpos;
139
    CORD_pos ypos;
140
    register size_t avail, yavail;
141
 
142
    if (y == CORD_EMPTY) return(x != CORD_EMPTY);
143
    if (x == CORD_EMPTY) return(-1);
144
    if (CORD_IS_STRING(y) && CORD_IS_STRING(x)) return(strcmp(x,y));
145
    CORD_set_pos(xpos, x, 0);
146
    CORD_set_pos(ypos, y, 0);
147
    for(;;) {
148
        if (!CORD_pos_valid(xpos)) {
149
            if (CORD_pos_valid(ypos)) {
150
                return(-1);
151
            } else {
152
                return(0);
153
            }
154
        }
155
        if (!CORD_pos_valid(ypos)) {
156
            return(1);
157
        }
158
        if ((avail = CORD_pos_chars_left(xpos)) <= 0
159
            || (yavail = CORD_pos_chars_left(ypos)) <= 0) {
160
            register char xcurrent = CORD_pos_fetch(xpos);
161
            register char ycurrent = CORD_pos_fetch(ypos);
162
            if (xcurrent != ycurrent) return(xcurrent - ycurrent);
163
            CORD_next(xpos);
164
            CORD_next(ypos);
165
        } else {
166
            /* process as many characters as we can     */
167
            register int result;
168
 
169
            if (avail > yavail) avail = yavail;
170
            result = strncmp(CORD_pos_cur_char_addr(xpos),
171
                             CORD_pos_cur_char_addr(ypos), avail);
172
            if (result != 0) return(result);
173
            CORD_pos_advance(xpos, avail);
174
            CORD_pos_advance(ypos, avail);
175
        }
176
    }
177
}
178
 
179
int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
180
{
181
    CORD_pos xpos;
182
    CORD_pos ypos;
183
    register size_t count;
184
    register long avail, yavail;
185
 
186
    CORD_set_pos(xpos, x, x_start);
187
    CORD_set_pos(ypos, y, y_start);
188
    for(count = 0; count < len;) {
189
        if (!CORD_pos_valid(xpos)) {
190
            if (CORD_pos_valid(ypos)) {
191
                return(-1);
192
            } else {
193
                return(0);
194
            }
195
        }
196
        if (!CORD_pos_valid(ypos)) {
197
            return(1);
198
        }
199
        if ((avail = CORD_pos_chars_left(xpos)) <= 0
200
            || (yavail = CORD_pos_chars_left(ypos)) <= 0) {
201
            register char xcurrent = CORD_pos_fetch(xpos);
202
            register char ycurrent = CORD_pos_fetch(ypos);
203
            if (xcurrent != ycurrent) return(xcurrent - ycurrent);
204
            CORD_next(xpos);
205
            CORD_next(ypos);
206
            count++;
207
        } else {
208
            /* process as many characters as we can     */
209
            register int result;
210
 
211
            if (avail > yavail) avail = yavail;
212
            count += avail;
213
            if (count > len) avail -= (count - len);
214
            result = strncmp(CORD_pos_cur_char_addr(xpos),
215
                             CORD_pos_cur_char_addr(ypos), (size_t)avail);
216
            if (result != 0) return(result);
217
            CORD_pos_advance(xpos, (size_t)avail);
218
            CORD_pos_advance(ypos, (size_t)avail);
219
        }
220
    }
221
    return(0);
222
}
223
 
224
char * CORD_to_char_star(CORD x)
225
{
226
    register size_t len = CORD_len(x);
227
    char * result = GC_MALLOC_ATOMIC(len + 1);
228
 
229
    if (result == 0) OUT_OF_MEMORY;
230
    CORD_fill_buf(x, 0, len, result);
231
    result[len] = '\0';
232
    return(result);
233
}
234
 
235
CORD CORD_from_char_star(const char *s)
236
{
237
    char * result;
238
    size_t len = strlen(s);
239
 
240
    if (0 == len) return(CORD_EMPTY);
241
    result = GC_MALLOC_ATOMIC(len + 1);
242
    if (result == 0) OUT_OF_MEMORY;
243
    memcpy(result, s, len+1);
244
    return(result);
245
}
246
 
247
const char * CORD_to_const_char_star(CORD x)
248
{
249
    if (x == 0) return("");
250
    if (CORD_IS_STRING(x)) return((const char *)x);
251
    return(CORD_to_char_star(x));
252
}
253
 
254
char CORD_fetch(CORD x, size_t i)
255
{
256
    CORD_pos xpos;
257
 
258
    CORD_set_pos(xpos, x, i);
259
    if (!CORD_pos_valid(xpos)) ABORT("bad index?");
260
    return(CORD_pos_fetch(xpos));
261
}
262
 
263
 
264
int CORD_put_proc(char c, void * client_data)
265
{
266
    register FILE * f = (FILE *)client_data;
267
 
268
    return(putc(c, f) == EOF);
269
}
270
 
271
int CORD_batched_put_proc(const char * s, void * client_data)
272
{
273
    register FILE * f = (FILE *)client_data;
274
 
275
    return(fputs(s, f) == EOF);
276
}
277
 
278
 
279
int CORD_put(CORD x, FILE * f)
280
{
281
    if (CORD_iter5(x, 0, CORD_put_proc, CORD_batched_put_proc, f)) {
282
        return(EOF);
283
    } else {
284
        return(1);
285
    }
286
}
287
 
288
typedef struct {
289
    size_t pos;         /* Current position in the cord */
290
    char target;        /* Character we're looking for  */
291
} chr_data;
292
 
293
int CORD_chr_proc(char c, void * client_data)
294
{
295
    register chr_data * d = (chr_data *)client_data;
296
 
297
    if (c == d -> target) return(1);
298
    (d -> pos) ++;
299
    return(0);
300
}
301
 
302
int CORD_rchr_proc(char c, void * client_data)
303
{
304
    register chr_data * d = (chr_data *)client_data;
305
 
306
    if (c == d -> target) return(1);
307
    (d -> pos) --;
308
    return(0);
309
}
310
 
311
int CORD_batched_chr_proc(const char *s, void * client_data)
312
{
313
    register chr_data * d = (chr_data *)client_data;
314
    register char * occ = strchr(s, d -> target);
315
 
316
    if (occ == 0) {
317
        d -> pos += strlen(s);
318
        return(0);
319
    } else {
320
        d -> pos += occ - s;
321
        return(1);
322
    }
323
}
324
 
325
size_t CORD_chr(CORD x, size_t i, int c)
326
{
327
    chr_data d;
328
 
329
    d.pos = i;
330
    d.target = c;
331
    if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) {
332
        return(d.pos);
333
    } else {
334
        return(CORD_NOT_FOUND);
335
    }
336
}
337
 
338
size_t CORD_rchr(CORD x, size_t i, int c)
339
{
340
    chr_data d;
341
 
342
    d.pos = i;
343
    d.target = c;
344
    if (CORD_riter4(x, i, CORD_rchr_proc, &d)) {
345
        return(d.pos);
346
    } else {
347
        return(CORD_NOT_FOUND);
348
    }
349
}
350
 
351
/* Find the first occurrence of s in x at position start or later.      */
352
/* This uses an asymptotically poor algorithm, which should typically   */
353
/* perform acceptably.  We compare the first few characters directly,   */
354
/* and call CORD_ncmp whenever there is a partial match.                */
355
/* This has the advantage that we allocate very little, or not at all.  */
356
/* It's very fast if there are few close misses.                        */
357
size_t CORD_str(CORD x, size_t start, CORD s)
358
{
359
    CORD_pos xpos;
360
    size_t xlen = CORD_len(x);
361
    size_t slen;
362
    register size_t start_len;
363
    const char * s_start;
364
    unsigned long s_buf = 0;     /* The first few characters of s        */
365
    unsigned long x_buf = 0;     /* Start of candidate substring.        */
366
                                /* Initialized only to make compilers   */
367
                                /* happy.                               */
368
    unsigned long mask = 0;
369
    register size_t i;
370
    register size_t match_pos;
371
 
372
    if (s == CORD_EMPTY) return(start);
373
    if (CORD_IS_STRING(s)) {
374
        s_start = s;
375
        slen = strlen(s);
376
    } else {
377
        s_start = CORD_to_char_star(CORD_substr(s, 0, sizeof(unsigned long)));
378
        slen = CORD_len(s);
379
    }
380
    if (xlen < start || xlen - start < slen) return(CORD_NOT_FOUND);
381
    start_len = slen;
382
    if (start_len > sizeof(unsigned long)) start_len = sizeof(unsigned long);
383
    CORD_set_pos(xpos, x, start);
384
    for (i = 0; i < start_len; i++) {
385
        mask <<= 8;
386
        mask |= 0xff;
387
        s_buf <<= 8;
388
        s_buf |= (unsigned char)s_start[i];
389
        x_buf <<= 8;
390
        x_buf |= (unsigned char)CORD_pos_fetch(xpos);
391
        CORD_next(xpos);
392
    }
393
    for (match_pos = start; ; match_pos++) {
394
        if ((x_buf & mask) == s_buf) {
395
            if (slen == start_len ||
396
                CORD_ncmp(x, match_pos + start_len,
397
                          s, start_len, slen - start_len) == 0) {
398
                return(match_pos);
399
            }
400
        }
401
        if ( match_pos == xlen - slen ) {
402
            return(CORD_NOT_FOUND);
403
        }
404
        x_buf <<= 8;
405
        x_buf |= (unsigned char)CORD_pos_fetch(xpos);
406
        CORD_next(xpos);
407
    }
408
}
409
 
410
void CORD_ec_flush_buf(CORD_ec x)
411
{
412
    register size_t len = x[0].ec_bufptr - x[0].ec_buf;
413
    char * s;
414
 
415
    if (len == 0) return;
416
    s = GC_MALLOC_ATOMIC(len+1);
417
    memcpy(s, x[0].ec_buf, len);
418
    s[len] = '\0';
419
    x[0].ec_cord = CORD_cat_char_star(x[0].ec_cord, s, len);
420
    x[0].ec_bufptr = x[0].ec_buf;
421
}
422
 
423
void CORD_ec_append_cord(CORD_ec x, CORD s)
424
{
425
    CORD_ec_flush_buf(x);
426
    x[0].ec_cord = CORD_cat(x[0].ec_cord, s);
427
}
428
 
429
/*ARGSUSED*/
430
char CORD_nul_func(size_t i, void * client_data)
431
{
432
    return((char)(unsigned long)client_data);
433
}
434
 
435
 
436
CORD CORD_chars(char c, size_t i)
437
{
438
    return(CORD_from_fn(CORD_nul_func, (void *)(unsigned long)c, i));
439
}
440
 
441
CORD CORD_from_file_eager(FILE * f)
442
{
443
    register int c;
444
    CORD_ec ecord;
445
 
446
    CORD_ec_init(ecord);
447
    for(;;) {
448
        c = getc(f);
449
        if (c == 0) {
450
          /* Append the right number of NULs    */
451
          /* Note that any string of NULs is rpresented in 4 words,     */
452
          /* independent of its length.                                 */
453
            register size_t count = 1;
454
 
455
            CORD_ec_flush_buf(ecord);
456
            while ((c = getc(f)) == 0) count++;
457
            ecord[0].ec_cord = CORD_cat(ecord[0].ec_cord, CORD_nul(count));
458
        }
459
        if (c == EOF) break;
460
        CORD_ec_append(ecord, c);
461
    }
462
    (void) fclose(f);
463
    return(CORD_balance(CORD_ec_to_cord(ecord)));
464
}
465
 
466
/* The state maintained for a lazily read file consists primarily       */
467
/* of a large direct-mapped cache of previously read values.            */
468
/* We could rely more on stdio buffering.  That would have 2            */
469
/* disadvantages:                                                       */
470
/*      1) Empirically, not all fseek implementations preserve the      */
471
/*         buffer whenever they could.                                  */
472
/*      2) It would fail if 2 different sections of a long cord         */
473
/*         were being read alternately.                                 */
474
/* We do use the stdio buffer for read ahead.                           */
475
/* To guarantee thread safety in the presence of atomic pointer         */
476
/* writes, cache lines are always replaced, and never modified in       */
477
/* place.                                                               */
478
 
479
# define LOG_CACHE_SZ 14
480
# define CACHE_SZ (1 << LOG_CACHE_SZ)
481
# define LOG_LINE_SZ 9
482
# define LINE_SZ (1 << LOG_LINE_SZ)
483
 
484
typedef struct {
485
    size_t tag;
486
    char data[LINE_SZ];
487
        /* data[i%LINE_SZ] = ith char in file if tag = i/LINE_SZ        */
488
} cache_line;
489
 
490
typedef struct {
491
    FILE * lf_file;
492
    size_t lf_current;  /* Current file pointer value */
493
    cache_line * volatile lf_cache[CACHE_SZ/LINE_SZ];
494
} lf_state;
495
 
496
# define MOD_CACHE_SZ(n) ((n) & (CACHE_SZ - 1))
497
# define DIV_CACHE_SZ(n) ((n) >> LOG_CACHE_SZ)
498
# define MOD_LINE_SZ(n) ((n) & (LINE_SZ - 1))
499
# define DIV_LINE_SZ(n) ((n) >> LOG_LINE_SZ)
500
# define LINE_START(n) ((n) & ~(LINE_SZ - 1))
501
 
502
typedef struct {
503
    lf_state * state;
504
    size_t file_pos;    /* Position of needed character. */
505
    cache_line * new_cache;
506
} refill_data;
507
 
508
/* Executed with allocation lock. */
509
static char refill_cache(client_data)
510
refill_data * client_data;
511
{
512
    register lf_state * state = client_data -> state;
513
    register size_t file_pos = client_data -> file_pos;
514
    FILE *f = state -> lf_file;
515
    size_t line_start = LINE_START(file_pos);
516
    size_t line_no = DIV_LINE_SZ(MOD_CACHE_SZ(file_pos));
517
    cache_line * new_cache = client_data -> new_cache;
518
 
519
    if (line_start != state -> lf_current
520
        && fseek(f, line_start, SEEK_SET) != 0) {
521
            ABORT("fseek failed");
522
    }
523
    if (fread(new_cache -> data, sizeof(char), LINE_SZ, f)
524
        <= file_pos - line_start) {
525
        ABORT("fread failed");
526
    }
527
    new_cache -> tag = DIV_LINE_SZ(file_pos);
528
    /* Store barrier goes here. */
529
    ATOMIC_WRITE(state -> lf_cache[line_no], new_cache);
530
    state -> lf_current = line_start + LINE_SZ;
531
    return(new_cache->data[MOD_LINE_SZ(file_pos)]);
532
}
533
 
534
char CORD_lf_func(size_t i, void * client_data)
535
{
536
    register lf_state * state = (lf_state *)client_data;
537
    register cache_line * volatile * cl_addr =
538
                &(state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))]);
539
    register cache_line * cl = (cache_line *)ATOMIC_READ(cl_addr);
540
 
541
    if (cl == 0 || cl -> tag != DIV_LINE_SZ(i)) {
542
        /* Cache miss */
543
        refill_data rd;
544
 
545
        rd.state = state;
546
        rd.file_pos =  i;
547
        rd.new_cache = GC_NEW_ATOMIC(cache_line);
548
        if (rd.new_cache == 0) OUT_OF_MEMORY;
549
        return((char)(GC_word)
550
                  GC_call_with_alloc_lock((GC_fn_type) refill_cache, &rd));
551
    }
552
    return(cl -> data[MOD_LINE_SZ(i)]);
553
}
554
 
555
/*ARGSUSED*/
556
void CORD_lf_close_proc(void * obj, void * client_data)
557
{
558
    if (fclose(((lf_state *)obj) -> lf_file) != 0) {
559
        ABORT("CORD_lf_close_proc: fclose failed");
560
    }
561
}
562
 
563
CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
564
{
565
    register lf_state * state = GC_NEW(lf_state);
566
    register int i;
567
 
568
    if (state == 0) OUT_OF_MEMORY;
569
    if (len != 0) {
570
        /* Dummy read to force buffer allocation.       */
571
        /* This greatly increases the probability       */
572
        /* of avoiding deadlock if buffer allocation    */
573
        /* is redirected to GC_malloc and the           */
574
        /* world is multithreaded.                      */
575
        char buf[1];
576
 
577
        (void) fread(buf, 1, 1, f);
578
        rewind(f);
579
    }
580
    state -> lf_file = f;
581
    for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
582
        state -> lf_cache[i] = 0;
583
    }
584
    state -> lf_current = 0;
585
    GC_REGISTER_FINALIZER(state, CORD_lf_close_proc, 0, 0, 0);
586
    return(CORD_from_fn(CORD_lf_func, state, len));
587
}
588
 
589
CORD CORD_from_file_lazy(FILE * f)
590
{
591
    register long len;
592
 
593
    if (fseek(f, 0l, SEEK_END) != 0) {
594
        ABORT("Bad fd argument - fseek failed");
595
    }
596
    if ((len = ftell(f)) < 0) {
597
        ABORT("Bad fd argument - ftell failed");
598
    }
599
    rewind(f);
600
    return(CORD_from_file_lazy_inner(f, (size_t)len));
601
}
602
 
603
# define LAZY_THRESHOLD (128*1024 + 1)
604
 
605
CORD CORD_from_file(FILE * f)
606
{
607
    register long len;
608
 
609
    if (fseek(f, 0l, SEEK_END) != 0) {
610
        ABORT("Bad fd argument - fseek failed");
611
    }
612
    if ((len = ftell(f)) < 0) {
613
        ABORT("Bad fd argument - ftell failed");
614
    }
615
    rewind(f);
616
    if (len < LAZY_THRESHOLD) {
617
        return(CORD_from_file_eager(f));
618
    } else {
619
        return(CORD_from_file_lazy_inner(f, (size_t)len));
620
    }
621
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.