cord_pos.h raw

   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  
  14  /* This should never be included directly; included only from `cord.h` file. */
  15  #if !defined(CORD_POSITION_H) && defined(CORD_H)
  16  #  define CORD_POSITION_H
  17  
  18  #  ifdef __cplusplus
  19  extern "C" {
  20  #  endif
  21  
  22  /*
  23   * The representation of `CORD_position`.  This is private to the
  24   * implementation, but the size is known to clients.  Also the implementation
  25   * of some exported macros relies on it.  Do not use anything defined here
  26   * and not in `cord.h` file.
  27   */
  28  
  29  /**
  30   * The maximum depth of a balanced cord plus one.  We do not let cords get
  31   * deeper than this maximum.
  32   */
  33  #  define CORD_MAX_DEPTH 48
  34  
  35  struct CORD_pe {
  36    CORD pe_cord;
  37    size_t pe_start_pos;
  38  };
  39  
  40  /**
  41   * A structure describing an entry on the path from the root to current
  42   * position.
  43   */
  44  typedef struct CORD_Pos {
  45    size_t cur_pos;
  46  
  47    int path_len;
  48  
  49    /* `path_len` is `CORD_POS_INVALID` if and only if position is invalid. */
  50  #  define CORD_POS_INVALID 0x55555555
  51  
  52    /*
  53     * Current leaf, if it is a string.  If the current leaf is a function,
  54     * then this may point to `function_buf` containing the next few characters.
  55     * Always points to a valid string containing the current character
  56     * unless `cur_end` is zero.
  57     */
  58    const char *cur_leaf;
  59  
  60    /* Start position of `cur_leaf`. */
  61    size_t cur_start;
  62  
  63    /* Ending position of `cur_leaf`; zero if `cur_leaf` is invalid. */
  64    size_t cur_end;
  65  
  66    /*
  67     * `path[path_len]` is the leaf corresponding to `cur_pos`;
  68     * `path[0].pe_cord` is the cord we point to.
  69     */
  70    struct CORD_pe path[CORD_MAX_DEPTH + 1];
  71  
  72  #  define CORD_FUNCTION_BUF_SZ 8
  73  
  74    /* Space for next few chars from function node. */
  75    char function_buf[CORD_FUNCTION_BUF_SZ];
  76  } CORD_pos[1];
  77  
  78  /** Extract the cord from a position. */
  79  CORD_API CORD CORD_pos_to_cord(CORD_pos);
  80  
  81  /** Extract the current index from a position. */
  82  CORD_API size_t CORD_pos_to_index(CORD_pos);
  83  
  84  /** Fetch the character located at the given position. */
  85  CORD_API char CORD_pos_fetch(CORD_pos);
  86  
  87  /**
  88   * Initialize the position to refer to the given cord and `index`.
  89   * Note that this is the most expensive function on positions.
  90   */
  91  CORD_API void CORD_set_pos(CORD_pos, CORD, size_t /* `index` */);
  92  
  93  /**
  94   * Advance the position to the next character.  `p` must be initialized
  95   * and valid.  Invalidates `p` if past end.
  96   */
  97  CORD_API void CORD_next(CORD_pos /* `p` */);
  98  
  99  /**
 100   * Move the position to the preceding character.  `p` must be initialized
 101   * and valid.  Invalidates `p` if past beginning.
 102   */
 103  CORD_API void CORD_prev(CORD_pos /* `p` */);
 104  
 105  /** Is the position valid, i.e. inside the cord? */
 106  CORD_API int CORD_pos_valid(CORD_pos);
 107  
 108  CORD_API char CORD__pos_fetch(CORD_pos);
 109  CORD_API void CORD__next(CORD_pos);
 110  CORD_API void CORD__prev(CORD_pos);
 111  
 112  #  define CORD_pos_fetch(p)                                                   \
 113      ((p)[0].cur_end != 0 ? (p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \
 114                           : CORD__pos_fetch(p))
 115  
 116  #  define CORD_next(p)                                      \
 117      ((p)[0].cur_pos + 1 < (p)[0].cur_end ? (p)[0].cur_pos++ \
 118                                           : (CORD__next(p), 0U))
 119  
 120  #  define CORD_prev(p)                                        \
 121      ((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start \
 122           ? (p)[0].cur_pos--                                   \
 123           : (CORD__prev(p), 0U))
 124  
 125  #  define CORD_pos_to_index(p) ((p)[0].cur_pos)
 126  
 127  #  define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord)
 128  
 129  #  define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID)
 130  
 131  /* Some grubby stuff for performance-critical friends. */
 132  
 133  /** Number of characters in cache.  A non-positive value means none. */
 134  #  define CORD_pos_chars_left(p) ((long)(p)[0].cur_end - (long)(p)[0].cur_pos)
 135  
 136  /**
 137   * Advance position by `n` characters; `n` should be positive and less
 138   * than `CORD_pos_chars_left(p)`.
 139   */
 140  #  define CORD_pos_advance(p, n) \
 141      ((p)[0].cur_pos += (n) - (size_t)1, CORD_next(p))
 142  
 143  /** Address of the current character in cache. */
 144  #  define CORD_pos_cur_char_addr(p) \
 145      ((p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start))
 146  
 147  #  ifdef __cplusplus
 148  } /* extern "C" */
 149  #  endif
 150  
 151  #endif
 152