2 * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
4 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
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.
13 * Author: Hans-J. Boehm (boehm@parc.xerox.com)
15 /* Boehm, October 3, 1994 5:19 pm PDT */
22 /* An implementation of the cord primitives. These are the only */
23 /* Functions that understand the representation. We perform only */
24 /* minimal checks on arguments to these functions. Out of bounds */
25 /* arguments to the iteration functions may result in client functions */
26 /* invoked on garbage data. In most cases, client functions should be */
27 /* programmed defensively enough that this does not result in memory */
30 typedef void (* oom_fn
)(void);
32 oom_fn CORD_oom_fn
= (oom_fn
) 0;
34 # define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
35 ABORT("Out of memory\n"); }
36 # define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
38 typedef unsigned long word
;
41 struct Concatenation
{
44 char depth
; /* concatenation nesting depth. */
45 unsigned char left_len
;
46 /* Length of left child if it is sufficiently */
47 /* short; 0 otherwise. */
48 # define MAX_LEFT_LEN 255
50 CORD left
; /* length(left) > 0 */
51 CORD right
; /* length(right) > 0 */
56 char depth
; /* always 0 */
57 char left_len
; /* always 0 */
76 /* Substring nodes are a special case of function nodes. */
77 /* The client_data field is known to point to a substr_args */
78 /* structure, and the function is either CORD_apply_access_fn */
79 /* or CORD_index_access_fn. */
81 /* The following may be applied only to function and concatenation nodes: */
82 #define IS_CONCATENATION(s) (((CordRep *)s)->generic.header == CONCAT_HDR)
84 #define IS_FUNCTION(s) ((((CordRep *)s)->generic.header & FN_HDR) != 0)
86 #define IS_SUBSTR(s) (((CordRep *)s)->generic.header == SUBSTR_HDR)
88 #define LEN(s) (((CordRep *)s) -> generic.len)
89 #define DEPTH(s) (((CordRep *)s) -> generic.depth)
90 #define GEN_LEN(s) (CORD_IS_STRING(s) ? strlen(s) : LEN(s))
92 #define LEFT_LEN(c) ((c) -> left_len != 0? \
94 : (CORD_IS_STRING((c) -> left) ? \
95 (c) -> len - GEN_LEN((c) -> right) \
98 #define SHORT_LIMIT (sizeof(CordRep) - 1)
99 /* Cords shorter than this are C strings */
102 /* Dump the internal representation of x to stdout, with initial */
103 /* indentation level n. */
104 void CORD_dump_inner(CORD x
, unsigned n
)
108 for (i
= 0; i
< (size_t)n
; i
++) {
112 fputs("NIL\n", stdout
);
113 } else if (CORD_IS_STRING(x
)) {
114 for (i
= 0; i
<= SHORT_LIMIT
; i
++) {
115 if (x
[i
] == '\0') break;
118 if (x
[i
] != '\0') fputs("...", stdout
);
120 } else if (IS_CONCATENATION(x
)) {
121 register struct Concatenation
* conc
=
122 &(((CordRep
*)x
) -> concatenation
);
123 printf("Concatenation: %p (len: %d, depth: %d)\n",
124 x
, (int)(conc
-> len
), (int)(conc
-> depth
));
125 CORD_dump_inner(conc
-> left
, n
+1);
126 CORD_dump_inner(conc
-> right
, n
+1);
127 } else /* function */{
128 register struct Function
* func
=
129 &(((CordRep
*)x
) -> function
);
130 if (IS_SUBSTR(x
)) printf("(Substring) ");
131 printf("Function: %p (len: %d): ", x
, (int)(func
-> len
));
132 for (i
= 0; i
< 20 && i
< func
-> len
; i
++) {
133 putchar((*(func
-> fn
))(i
, func
-> client_data
));
135 if (i
< func
-> len
) fputs("...", stdout
);
140 /* Dump the internal representation of x to stdout */
141 void CORD_dump(CORD x
)
143 CORD_dump_inner(x
, 0);
147 CORD
CORD_cat_char_star(CORD x
, const char * y
, size_t leny
)
149 register size_t result_len
;
150 register size_t lenx
;
153 if (x
== CORD_EMPTY
) return(y
);
154 if (leny
== 0) return(x
);
155 if (CORD_IS_STRING(x
)) {
157 result_len
= lenx
+ leny
;
158 if (result_len
<= SHORT_LIMIT
) {
159 register char * result
= GC_MALLOC_ATOMIC(result_len
+1);
161 if (result
== 0) OUT_OF_MEMORY
;
162 memcpy(result
, x
, lenx
);
163 memcpy(result
+ lenx
, y
, leny
);
164 result
[result_len
] = '\0';
165 return((CORD
) result
);
172 register char * new_right
;
173 register size_t right_len
;
177 if (leny
<= SHORT_LIMIT
/2
178 && IS_CONCATENATION(x
)
179 && CORD_IS_STRING(right
= ((CordRep
*)x
) -> concatenation
.right
)) {
180 /* Merge y into right part of x. */
181 if (!CORD_IS_STRING(left
= ((CordRep
*)x
) -> concatenation
.left
)) {
182 right_len
= lenx
- LEN(left
);
183 } else if (((CordRep
*)x
) -> concatenation
.left_len
!= 0) {
184 right_len
= lenx
- ((CordRep
*)x
) -> concatenation
.left_len
;
186 right_len
= strlen(right
);
188 result_len
= right_len
+ leny
; /* length of new_right */
189 if (result_len
<= SHORT_LIMIT
) {
190 new_right
= GC_MALLOC_ATOMIC(result_len
+ 1);
191 memcpy(new_right
, right
, right_len
);
192 memcpy(new_right
+ right_len
, y
, leny
);
193 new_right
[result_len
] = '\0';
198 /* Now fall through to concatenate the two pieces: */
200 if (CORD_IS_STRING(x
)) {
203 depth
= DEPTH(x
) + 1;
206 depth
= DEPTH(x
) + 1;
208 result_len
= lenx
+ leny
;
211 /* The general case; lenx, result_len is known: */
212 register struct Concatenation
* result
;
214 result
= GC_NEW(struct Concatenation
);
215 if (result
== 0) OUT_OF_MEMORY
;
216 result
->header
= CONCAT_HDR
;
217 result
->depth
= depth
;
218 if (lenx
<= MAX_LEFT_LEN
) result
->left_len
= lenx
;
219 result
->len
= result_len
;
222 if (depth
>= MAX_DEPTH
) {
223 return(CORD_balance((CORD
)result
));
225 return((CORD
) result
);
231 CORD
CORD_cat(CORD x
, CORD y
)
233 register size_t result_len
;
235 register size_t lenx
;
237 if (x
== CORD_EMPTY
) return(y
);
238 if (y
== CORD_EMPTY
) return(x
);
239 if (CORD_IS_STRING(y
)) {
240 return(CORD_cat_char_star(x
, y
, strlen(y
)));
241 } else if (CORD_IS_STRING(x
)) {
243 depth
= DEPTH(y
) + 1;
245 register int depthy
= DEPTH(y
);
248 depth
= DEPTH(x
) + 1;
249 if (depthy
>= depth
) depth
= depthy
+ 1;
251 result_len
= lenx
+ LEN(y
);
253 register struct Concatenation
* result
;
255 result
= GC_NEW(struct Concatenation
);
256 if (result
== 0) OUT_OF_MEMORY
;
257 result
->header
= CONCAT_HDR
;
258 result
->depth
= depth
;
259 if (lenx
<= MAX_LEFT_LEN
) result
->left_len
= lenx
;
260 result
->len
= result_len
;
263 if (depth
>= MAX_DEPTH
) {
264 return(CORD_balance((CORD
)result
));
266 return((CORD
) result
);
273 CORD
CORD_from_fn(CORD_fn fn
, void * client_data
, size_t len
)
275 if (len
<= 0) return(0);
276 if (len
<= SHORT_LIMIT
) {
277 register char * result
;
279 char buf
[SHORT_LIMIT
+1];
282 for (i
= 0; i
< len
; i
++) {
283 c
= (*fn
)(i
, client_data
);
284 if (c
== '\0') goto gen_case
;
288 result
= GC_MALLOC_ATOMIC(len
+1);
289 if (result
== 0) OUT_OF_MEMORY
;
292 return((CORD
) result
);
296 register struct Function
* result
;
298 result
= GC_NEW(struct Function
);
299 if (result
== 0) OUT_OF_MEMORY
;
300 result
->header
= FN_HDR
;
301 /* depth is already 0 */
304 result
->client_data
= client_data
;
305 return((CORD
) result
);
309 size_t CORD_len(CORD x
)
323 char CORD_index_access_fn(size_t i
, void * client_data
)
325 register struct substr_args
*descr
= (struct substr_args
*)client_data
;
327 return(((char *)(descr
->sa_cord
))[i
+ descr
->sa_index
]);
330 char CORD_apply_access_fn(size_t i
, void * client_data
)
332 register struct substr_args
*descr
= (struct substr_args
*)client_data
;
333 register struct Function
* fn_cord
= &(descr
->sa_cord
->function
);
335 return((*(fn_cord
->fn
))(i
+ descr
->sa_index
, fn_cord
->client_data
));
338 /* A version of CORD_substr that simply returns a function node, thus */
339 /* postponing its work. The fourth argument is a function that may */
340 /* be used for efficient access to the ith character. */
341 /* Assumes i >= 0 and i + n < length(x). */
342 CORD
CORD_substr_closure(CORD x
, size_t i
, size_t n
, CORD_fn f
)
344 register struct substr_args
* sa
= GC_NEW(struct substr_args
);
347 if (sa
== 0) OUT_OF_MEMORY
;
348 sa
->sa_cord
= (CordRep
*)x
;
350 result
= CORD_from_fn(f
, (void *)sa
, n
);
351 ((CordRep
*)result
) -> function
.header
= SUBSTR_HDR
;
355 # define SUBSTR_LIMIT (10 * SHORT_LIMIT)
356 /* Substrings of function nodes and flat strings shorter than */
357 /* this are flat strings. Othewise we use a functional */
358 /* representation, which is significantly slower to access. */
360 /* A version of CORD_substr that assumes i >= 0, n > 0, and i + n < length(x).*/
361 CORD
CORD_substr_checked(CORD x
, size_t i
, size_t n
)
363 if (CORD_IS_STRING(x
)) {
364 if (n
> SUBSTR_LIMIT
) {
365 return(CORD_substr_closure(x
, i
, n
, CORD_index_access_fn
));
367 register char * result
= GC_MALLOC_ATOMIC(n
+1);
369 if (result
== 0) OUT_OF_MEMORY
;
370 strncpy(result
, x
+i
, n
);
374 } else if (IS_CONCATENATION(x
)) {
375 register struct Concatenation
* conc
376 = &(((CordRep
*)x
) -> concatenation
);
377 register size_t left_len
;
378 register size_t right_len
;
380 left_len
= LEFT_LEN(conc
);
381 right_len
= conc
-> len
- left_len
;
383 if (n
== right_len
) return(conc
-> right
);
384 return(CORD_substr_checked(conc
-> right
, i
- left_len
, n
));
385 } else if (i
+n
<= left_len
) {
386 if (n
== left_len
) return(conc
-> left
);
387 return(CORD_substr_checked(conc
-> left
, i
, n
));
389 /* Need at least one character from each side. */
390 register CORD left_part
;
391 register CORD right_part
;
392 register size_t left_part_len
= left_len
- i
;
395 left_part
= conc
-> left
;
397 left_part
= CORD_substr_checked(conc
-> left
, i
, left_part_len
);
399 if (i
+ n
== right_len
+ left_len
) {
400 right_part
= conc
-> right
;
402 right_part
= CORD_substr_checked(conc
-> right
, 0,
405 return(CORD_cat(left_part
, right_part
));
407 } else /* function */ {
408 if (n
> SUBSTR_LIMIT
) {
410 /* Avoid nesting substring nodes. */
411 register struct Function
* f
= &(((CordRep
*)x
) -> function
);
412 register struct substr_args
*descr
=
413 (struct substr_args
*)(f
-> client_data
);
415 return(CORD_substr_closure((CORD
)descr
->sa_cord
,
419 return(CORD_substr_closure(x
, i
, n
, CORD_apply_access_fn
));
423 register struct Function
* f
= &(((CordRep
*)x
) -> function
);
424 char buf
[SUBSTR_LIMIT
+1];
425 register char * p
= buf
;
428 register int lim
= i
+ n
;
430 for (j
= i
; j
< lim
; j
++) {
431 c
= (*(f
-> fn
))(j
, f
-> client_data
);
433 return(CORD_substr_closure(x
, i
, n
, CORD_apply_access_fn
));
438 result
= GC_MALLOC_ATOMIC(n
+1);
439 if (result
== 0) OUT_OF_MEMORY
;
446 CORD
CORD_substr(CORD x
, size_t i
, size_t n
)
448 register size_t len
= CORD_len(x
);
450 if (i
>= len
|| n
<= 0) return(0);
451 /* n < 0 is impossible in a correct C implementation, but */
452 /* quite possible under SunOS 4.X. */
453 if (i
+ n
> len
) n
= len
- i
;
455 if (i
< 0) ABORT("CORD_substr: second arg. negative");
456 /* Possible only if both client and C implementation are buggy. */
457 /* But empirically this happens frequently. */
459 return(CORD_substr_checked(x
, i
, n
));
462 /* See cord.h for definition. We assume i is in range. */
463 int CORD_iter5(CORD x
, size_t i
, CORD_iter_fn f1
,
464 CORD_batched_iter_fn f2
, void * client_data
)
466 if (x
== 0) return(0);
467 if (CORD_IS_STRING(x
)) {
468 register const char *p
= x
+i
;
470 if (*p
== '\0') ABORT("2nd arg to CORD_iter5 too big");
471 if (f2
!= CORD_NO_FN
) {
472 return((*f2
)(p
, client_data
));
475 if ((*f1
)(*p
, client_data
)) return(1);
480 } else if (IS_CONCATENATION(x
)) {
481 register struct Concatenation
* conc
482 = &(((CordRep
*)x
) -> concatenation
);
486 register size_t left_len
= LEFT_LEN(conc
);
489 return(CORD_iter5(conc
-> right
, i
- left_len
, f1
, f2
,
493 if (CORD_iter5(conc
-> left
, i
, f1
, f2
, client_data
)) {
496 return(CORD_iter5(conc
-> right
, 0, f1
, f2
, client_data
));
497 } else /* function */ {
498 register struct Function
* f
= &(((CordRep
*)x
) -> function
);
500 register size_t lim
= f
-> len
;
502 for (j
= i
; j
< lim
; j
++) {
503 if ((*f1
)((*(f
-> fn
))(j
, f
-> client_data
), client_data
)) {
512 int CORD_iter(CORD x
, CORD_iter_fn f1
, void * client_data
)
514 return(CORD_iter5(x
, 0, f1
, CORD_NO_FN
, client_data
));
517 int CORD_riter4(CORD x
, size_t i
, CORD_iter_fn f1
, void * client_data
)
519 if (x
== 0) return(0);
520 if (CORD_IS_STRING(x
)) {
521 register const char *p
= x
+ i
;
526 if (c
== '\0') ABORT("2nd arg to CORD_riter4 too big");
527 if ((*f1
)(c
, client_data
)) return(1);
532 } else if (IS_CONCATENATION(x
)) {
533 register struct Concatenation
* conc
534 = &(((CordRep
*)x
) -> concatenation
);
535 register CORD left_part
= conc
-> left
;
536 register size_t left_len
;
538 left_len
= LEFT_LEN(conc
);
540 if (CORD_riter4(conc
-> right
, i
- left_len
, f1
, client_data
)) {
543 return(CORD_riter4(left_part
, left_len
- 1, f1
, client_data
));
545 return(CORD_riter4(left_part
, i
, f1
, client_data
));
547 } else /* function */ {
548 register struct Function
* f
= &(((CordRep
*)x
) -> function
);
552 if ((*f1
)((*(f
-> fn
))(j
, f
-> client_data
), client_data
)) {
555 if (j
== 0) return(0);
560 int CORD_riter(CORD x
, CORD_iter_fn f1
, void * client_data
)
562 return(CORD_riter4(x
, CORD_len(x
) - 1, f1
, client_data
));
566 * The following functions are concerned with balancing cords.
568 * Scan the cord from left to right, keeping the cord scanned so far
569 * as a forest of balanced trees of exponentialy decreasing length.
570 * When a new subtree needs to be added to the forest, we concatenate all
571 * shorter ones to the new tree in the appropriate order, and then insert
572 * the result into the forest.
573 * Crucial invariants:
574 * 1. The concatenation of the forest (in decreasing order) with the
575 * unscanned part of the rope is equal to the rope being balanced.
576 * 2. All trees in the forest are balanced.
577 * 3. forest[i] has depth at most i.
582 size_t len
; /* Actual length of c */
585 static size_t min_len
[ MAX_DEPTH
];
587 static int min_len_init
= 0;
591 typedef ForestElement Forest
[ MAX_DEPTH
];
592 /* forest[i].len >= fib(i+1) */
593 /* The string is the concatenation */
594 /* of the forest in order of DECREASING */
597 void CORD_init_min_len()
600 register size_t last
, previous
, current
;
602 min_len
[0] = previous
= 1;
603 min_len
[1] = last
= 2;
604 for (i
= 2; i
< MAX_DEPTH
; i
++) {
605 current
= last
+ previous
;
606 if (current
< last
) /* overflow */ current
= last
;
607 min_len
[i
] = current
;
611 CORD_max_len
= last
- 1;
616 void CORD_init_forest(ForestElement
* forest
, size_t max_len
)
620 for (i
= 0; i
< MAX_DEPTH
; i
++) {
622 if (min_len
[i
] > max_len
) return;
624 ABORT("Cord too long");
627 /* Add a leaf to the appropriate level in the forest, cleaning */
628 /* out lower levels as necessary. */
629 /* Also works if x is a balanced tree of concatenations; however */
630 /* in this case an extra concatenation node may be inserted above x; */
631 /* This node should not be counted in the statement of the invariants. */
632 void CORD_add_forest(ForestElement
* forest
, CORD x
, size_t len
)
635 register CORD sum
= CORD_EMPTY
;
636 register size_t sum_len
= 0;
638 while (len
> min_len
[i
+ 1]) {
639 if (forest
[i
].c
!= 0) {
640 sum
= CORD_cat(forest
[i
].c
, sum
);
641 sum_len
+= forest
[i
].len
;
646 /* Sum has depth at most 1 greter than what would be required */
648 sum
= CORD_cat(sum
, x
);
650 /* If x was a leaf, then sum is now balanced. To see this */
651 /* consider the two cases in which forest[i-1] either is or is */
653 while (sum_len
>= min_len
[i
]) {
654 if (forest
[i
].c
!= 0) {
655 sum
= CORD_cat(forest
[i
].c
, sum
);
656 sum_len
+= forest
[i
].len
;
657 /* This is again balanced, since sum was balanced, and has */
658 /* allowable depth that differs from i by at most 1. */
665 forest
[i
].len
= sum_len
;
668 CORD
CORD_concat_forest(ForestElement
* forest
, size_t expected_len
)
674 while (sum_len
!= expected_len
) {
675 if (forest
[i
].c
!= 0) {
676 sum
= CORD_cat(forest
[i
].c
, sum
);
677 sum_len
+= forest
[i
].len
;
684 /* Insert the frontier of x into forest. Balanced subtrees are */
685 /* treated as leaves. This potentially adds one to the depth */
686 /* of the final tree. */
687 void CORD_balance_insert(CORD x
, size_t len
, ForestElement
* forest
)
691 if (CORD_IS_STRING(x
)) {
692 CORD_add_forest(forest
, x
, len
);
693 } else if (IS_CONCATENATION(x
)
694 && ((depth
= DEPTH(x
)) >= MAX_DEPTH
695 || len
< min_len
[depth
])) {
696 register struct Concatenation
* conc
697 = &(((CordRep
*)x
) -> concatenation
);
698 size_t left_len
= LEFT_LEN(conc
);
700 CORD_balance_insert(conc
-> left
, left_len
, forest
);
701 CORD_balance_insert(conc
-> right
, len
- left_len
, forest
);
702 } else /* function or balanced */ {
703 CORD_add_forest(forest
, x
, len
);
708 CORD
CORD_balance(CORD x
)
713 if (x
== 0) return(0);
714 if (CORD_IS_STRING(x
)) return(x
);
715 if (!min_len_init
) CORD_init_min_len();
717 CORD_init_forest(forest
, len
);
718 CORD_balance_insert(x
, len
, forest
);
719 return(CORD_concat_forest(forest
, len
));
723 /* Position primitives */
725 /* Private routines to deal with the hard cases only: */
727 /* P contains a prefix of the path to cur_pos. Extend it to a full */
728 /* path and set up leaf info. */
729 /* Return 0 if past the end of cord, 1 o.w. */
730 void CORD__extend_path(register CORD_pos p
)
732 register struct CORD_pe
* current_pe
= &(p
[0].path
[p
[0].path_len
]);
733 register CORD top
= current_pe
-> pe_cord
;
734 register size_t pos
= p
[0].cur_pos
;
735 register size_t top_pos
= current_pe
-> pe_start_pos
;
736 register size_t top_len
= GEN_LEN(top
);
738 /* Fill in the rest of the path. */
739 while(!CORD_IS_STRING(top
) && IS_CONCATENATION(top
)) {
740 register struct Concatenation
* conc
=
741 &(((CordRep
*)top
) -> concatenation
);
742 register size_t left_len
;
744 left_len
= LEFT_LEN(conc
);
746 if (pos
>= top_pos
+ left_len
) {
747 current_pe
-> pe_cord
= top
= conc
-> right
;
748 current_pe
-> pe_start_pos
= top_pos
= top_pos
+ left_len
;
751 current_pe
-> pe_cord
= top
= conc
-> left
;
752 current_pe
-> pe_start_pos
= top_pos
;
757 /* Fill in leaf description for fast access. */
758 if (CORD_IS_STRING(top
)) {
760 p
[0].cur_start
= top_pos
;
761 p
[0].cur_end
= top_pos
+ top_len
;
765 if (pos
>= top_pos
+ top_len
) p
[0].path_len
= CORD_POS_INVALID
;
768 char CORD__pos_fetch(register CORD_pos p
)
770 /* Leaf is a function node */
771 struct CORD_pe
* pe
= &((p
)[0].path
[(p
)[0].path_len
]);
772 CORD leaf
= pe
-> pe_cord
;
773 register struct Function
* f
= &(((CordRep
*)leaf
) -> function
);
775 if (!IS_FUNCTION(leaf
)) ABORT("CORD_pos_fetch: bad leaf");
776 return ((*(f
-> fn
))(p
[0].cur_pos
- pe
-> pe_start_pos
, f
-> client_data
));
779 void CORD__next(register CORD_pos p
)
781 register size_t cur_pos
= p
[0].cur_pos
+ 1;
782 register struct CORD_pe
* current_pe
= &((p
)[0].path
[(p
)[0].path_len
]);
783 register CORD leaf
= current_pe
-> pe_cord
;
785 /* Leaf is not a string or we're at end of leaf */
786 p
[0].cur_pos
= cur_pos
;
787 if (!CORD_IS_STRING(leaf
)) {
789 register struct Function
* f
= &(((CordRep
*)leaf
) -> function
);
790 register size_t start_pos
= current_pe
-> pe_start_pos
;
791 register size_t end_pos
= start_pos
+ f
-> len
;
793 if (cur_pos
< end_pos
) {
794 /* Fill cache and return. */
796 register size_t limit
= cur_pos
+ FUNCTION_BUF_SZ
;
797 register CORD_fn fn
= f
-> fn
;
798 register void * client_data
= f
-> client_data
;
800 if (limit
> end_pos
) {
803 for (i
= cur_pos
; i
< limit
; i
++) {
804 p
[0].function_buf
[i
- cur_pos
] =
805 (*fn
)(i
- start_pos
, client_data
);
807 p
[0].cur_start
= cur_pos
;
808 p
[0].cur_leaf
= p
[0].function_buf
;
809 p
[0].cur_end
= limit
;
814 /* Pop the stack until we find two concatenation nodes with the */
815 /* same start position: this implies we were in left part. */
817 while (p
[0].path_len
> 0
818 && current_pe
[0].pe_start_pos
!= current_pe
[-1].pe_start_pos
) {
822 if (p
[0].path_len
== 0) {
823 p
[0].path_len
= CORD_POS_INVALID
;
828 CORD__extend_path(p
);
831 void CORD__prev(register CORD_pos p
)
833 register struct CORD_pe
* pe
= &(p
[0].path
[p
[0].path_len
]);
835 if (p
[0].cur_pos
== 0) {
836 p
[0].path_len
= CORD_POS_INVALID
;
840 if (p
[0].cur_pos
>= pe
-> pe_start_pos
) return;
842 /* Beginning of leaf */
844 /* Pop the stack until we find two concatenation nodes with the */
845 /* different start position: this implies we were in right part. */
847 register struct CORD_pe
* current_pe
= &((p
)[0].path
[(p
)[0].path_len
]);
849 while (p
[0].path_len
> 0
850 && current_pe
[0].pe_start_pos
== current_pe
[-1].pe_start_pos
) {
856 CORD__extend_path(p
);
859 #undef CORD_pos_fetch
862 #undef CORD_pos_to_index
863 #undef CORD_pos_to_cord
864 #undef CORD_pos_valid
866 char CORD_pos_fetch(register CORD_pos p
)
868 if (p
[0].cur_start
<= p
[0].cur_pos
&& p
[0].cur_pos
< p
[0].cur_end
) {
869 return(p
[0].cur_leaf
[p
[0].cur_pos
- p
[0].cur_start
]);
871 return(CORD__pos_fetch(p
));
875 void CORD_next(CORD_pos p
)
877 if (p
[0].cur_pos
< p
[0].cur_end
- 1) {
884 void CORD_prev(CORD_pos p
)
886 if (p
[0].cur_end
!= 0 && p
[0].cur_pos
> p
[0].cur_start
) {
893 size_t CORD_pos_to_index(CORD_pos p
)
895 return(p
[0].cur_pos
);
898 CORD
CORD_pos_to_cord(CORD_pos p
)
900 return(p
[0].path
[0].pe_cord
);
903 int CORD_pos_valid(CORD_pos p
)
905 return(p
[0].path_len
!= CORD_POS_INVALID
);
908 void CORD_set_pos(CORD_pos p
, CORD x
, size_t i
)
910 if (x
== CORD_EMPTY
) {
911 p
[0].path_len
= CORD_POS_INVALID
;
914 p
[0].path
[0].pe_cord
= x
;
915 p
[0].path
[0].pe_start_pos
= 0;
918 CORD__extend_path(p
);