1 /* Copyright David Abrahams 2004. Distributed under the Boost */
2 /* Software License, Version 1.0. (See accompanying */
3 /* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
14 # define JAM_STRING_MAGIC ((char)0xcf)
15 # define JAM_STRING_MAGIC_SIZE 4
16 static void AssertInvariants (tKString
*self
) {
19 if (self
->value
== 0) {
20 assert(self
->size
== 0);
21 assert(self
->capacity
== 0);
22 assert(self
->opt
[0] == 0);
26 assert(self
->size
< self
->capacity
);
27 assert((self
->capacity
<= sizeof(self
->opt
)) == (self
->value
== self
->opt
));
28 assert(strlen(self
->value
) == self
->size
);
30 for (i
= 0; i
< 4; ++i
) {
31 assert(self
->magic
[i
] == JAM_STRING_MAGIC
);
32 assert(self
->value
[self
->capacity
+i
] == JAM_STRING_MAGIC
);
36 # define JAM_STRING_MAGIC_SIZE 0
37 # define AssertInvariants(x) do {} while (0)
41 void kStringNew (tKString
*s
) {
44 s
->capacity
= sizeof(s
->opt
);
47 memset(s
->magic
, JAM_STRING_MAGIC
, sizeof(s
->magic
));
53 void kStringFree (tKString
*s
) {
55 if (s
->value
!= s
->opt
) free(s
->value
);
60 static void kStringReserveInternal (tKString
*self
, size_t capacity
) {
61 if (self
->value
== self
->opt
) {
62 self
->value
= (char *)malloc(capacity
+JAM_STRING_MAGIC_SIZE
);
65 strncat(self
->value
, self
->opt
, sizeof(self
->opt
));
66 assert(strlen(self
->value
) <= self
->capacity
); /* This is a regression test */
68 self
->value
= (char *)realloc(self
->value
, capacity
+JAM_STRING_MAGIC_SIZE
);
72 memcpy(self
->value
+capacity
, self
->magic
, JAM_STRING_MAGIC_SIZE
);
74 self
->capacity
= capacity
;
78 void kStringReserve (tKString
*self
, size_t capacity
) {
79 AssertInvariants(self
);
80 if (capacity
<= self
->capacity
) return;
81 kStringReserveInternal(self
, capacity
);
82 AssertInvariants(self
);
86 static void kStringExtendFull (tKString
*self
, char const *start
, char const *finish
) {
87 size_t new_size
= self
->capacity
+(finish
-start
);
88 size_t new_capacity
= self
->capacity
;
89 size_t old_size
= self
->capacity
;
90 while (new_capacity
< new_size
+1) new_capacity
<<= 1;
91 kStringReserveInternal(self
, new_capacity
);
92 memcpy(self
->value
+old_size
, start
, new_size
-old_size
);
93 self
->value
[new_size
] = 0;
94 self
->size
= new_size
;
98 void kStringAppend (tKString
*self
, char const *rhs
) {
99 char *p
= self
->value
+self
->size
;
100 char *end
= self
->value
+self
->capacity
;
101 AssertInvariants(self
);
103 while (*rhs
&& p
!= end
) *p
++ = *rhs
++;
106 self
->size
= p
-self
->value
;
107 } else kStringExtendFull(self
, rhs
, rhs
+strlen(rhs
));
108 AssertInvariants(self
);
112 void kStringAppendRange (tKString
*self
, char const *start
, char const *finish
) {
113 char *p
= self
->value
+self
->size
;
114 char *end
= self
->value
+self
->capacity
;
115 AssertInvariants(self
);
117 while (p
!= end
&& start
!= finish
) *p
++ = *start
++;
120 self
->size
= p
-self
->value
;
121 } else kStringExtendFull(self
, start
, finish
);
122 AssertInvariants(self
);
126 void kStringCopy (tKString
*s
, char const *rhs
) {
128 kStringAppend(s
, rhs
);
132 void kStringTruncate (tKString
*self
, size_t n
) {
133 AssertInvariants(self
);
134 assert(n
<= self
->capacity
);
135 self
->value
[self
->size
= n
] = 0;
136 AssertInvariants(self
);
140 void kStringPopBack (tKString
*self
) {
141 kStringTruncate(self
, self
->size
-1);
145 void kStringPushBack (tKString
*self
, char x
) {
146 kStringAppendRange(self
, &x
, &x
+1);
150 char kStringBack (tKString
*self
) {
151 AssertInvariants(self
);
152 return self
->value
[self
->size
-1];
157 void kStringUnitTest (void) {
160 char buffer
[sizeof(s
->opt
)*2+2];
161 int limit
= sizeof(buffer
)>254?254:sizeof(buffer
);
164 for (i
= 0; i
< limit
; ++i
) {
165 kStringPushBack(s
, (char)(i
+1));
168 for (i
= 0; i
< limit
; ++i
) {
170 assert(s
->value
[i
] == (char)(i
+1));