cordxtra.c
上传用户:fbh598
上传日期:2007-07-05
资源大小:5960k
文件大小:17k
源码类别:

Java编程

开发平台:

Unix_Linux

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