]> gitweb.factorcode.org Git - factor.git/blob - vm/strings.cpp
Merge branch 'master' of git://factorcode.org/git/factor into constraints
[factor.git] / vm / strings.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 cell factorvm::string_nth(string* str, cell index)
7 {
8         /* If high bit is set, the most significant 16 bits of the char
9         come from the aux vector. The least significant bit of the
10         corresponding aux vector entry is negated, so that we can
11         XOR the two components together and get the original code point
12         back. */
13         cell lo_bits = str->data()[index];
14
15         if((lo_bits & 0x80) == 0)
16                 return lo_bits;
17         else
18         {
19                 byte_array *aux = untag<byte_array>(str->aux);
20                 cell hi_bits = aux->data<u16>()[index];
21                 return (hi_bits << 7) ^ lo_bits;
22         }
23 }
24
25
26 void factorvm::set_string_nth_fast(string *str, cell index, cell ch)
27 {
28         str->data()[index] = ch;
29 }
30
31
32 void factorvm::set_string_nth_slow(string *str_, cell index, cell ch)
33 {
34         gc_root<string> str(str_,this);
35
36         byte_array *aux;
37
38         str->data()[index] = ((ch & 0x7f) | 0x80);
39
40         if(str->aux == F)
41         {
42                 /* We don't need to pre-initialize the
43                 byte array with any data, since we
44                 only ever read from the aux vector
45                 if the most significant bit of a
46                 character is set. Initially all of
47                 the bits are clear. */
48                 aux = allot_array_internal<byte_array>(untag_fixnum(str->length) * sizeof(u16));
49
50                 write_barrier(str.untagged());
51                 str->aux = tag<byte_array>(aux);
52         }
53         else
54                 aux = untag<byte_array>(str->aux);
55
56         aux->data<u16>()[index] = ((ch >> 7) ^ 1);
57 }
58
59
60 /* allocates memory */
61 void factorvm::set_string_nth(string *str, cell index, cell ch)
62 {
63         if(ch <= 0x7f)
64                 set_string_nth_fast(str,index,ch);
65         else
66                 set_string_nth_slow(str,index,ch);
67 }
68
69
70 /* Allocates memory */
71 string *factorvm::allot_string_internal(cell capacity)
72 {
73         string *str = allot<string>(string_size(capacity));
74
75         str->length = tag_fixnum(capacity);
76         str->hashcode = F;
77         str->aux = F;
78
79         return str;
80 }
81
82
83 /* Allocates memory */
84 void factorvm::fill_string(string *str_, cell start, cell capacity, cell fill)
85 {
86         gc_root<string> str(str_,this);
87
88         if(fill <= 0x7f)
89                 memset(&str->data()[start],fill,capacity - start);
90         else
91         {
92                 cell i;
93
94                 for(i = start; i < capacity; i++)
95                         set_string_nth(str.untagged(),i,fill);
96         }
97 }
98
99
100 /* Allocates memory */
101 string *factorvm::allot_string(cell capacity, cell fill)
102 {
103         gc_root<string> str(allot_string_internal(capacity),this);
104         fill_string(str.untagged(),0,capacity,fill);
105         return str.untagged();
106 }
107
108
109 inline void factorvm::vmprim_string()
110 {
111         cell initial = to_cell(dpop());
112         cell length = unbox_array_size();
113         dpush(tag<string>(allot_string(length,initial)));
114 }
115
116 PRIMITIVE(string)
117 {
118         PRIMITIVE_GETVM()->vmprim_string();
119 }
120
121 bool factorvm::reallot_string_in_place_p(string *str, cell capacity)
122 {
123         return in_zone(&nursery,str)
124                 && (str->aux == F || in_zone(&nursery,untag<byte_array>(str->aux)))
125                 && capacity <= string_capacity(str);
126 }
127
128
129 string* factorvm::reallot_string(string *str_, cell capacity)
130 {
131         gc_root<string> str(str_,this);
132
133         if(reallot_string_in_place_p(str.untagged(),capacity))
134         {
135                 str->length = tag_fixnum(capacity);
136
137                 if(str->aux != F)
138                 {
139                         byte_array *aux = untag<byte_array>(str->aux);
140                         aux->capacity = tag_fixnum(capacity * 2);
141                 }
142
143                 return str.untagged();
144         }
145         else
146         {
147                 cell to_copy = string_capacity(str.untagged());
148                 if(capacity < to_copy)
149                         to_copy = capacity;
150
151                 gc_root<string> new_str(allot_string_internal(capacity),this);
152
153                 memcpy(new_str->data(),str->data(),to_copy);
154
155                 if(str->aux != F)
156                 {
157                         byte_array *new_aux = allot_byte_array(capacity * sizeof(u16));
158
159                         write_barrier(new_str.untagged());
160                         new_str->aux = tag<byte_array>(new_aux);
161
162                         byte_array *aux = untag<byte_array>(str->aux);
163                         memcpy(new_aux->data<u16>(),aux->data<u16>(),to_copy * sizeof(u16));
164                 }
165
166                 fill_string(new_str.untagged(),to_copy,capacity,'\0');
167                 return new_str.untagged();
168         }
169 }
170
171
172 inline void factorvm::vmprim_resize_string()
173 {
174         string* str = untag_check<string>(dpop());
175         cell capacity = unbox_array_size();
176         dpush(tag<string>(reallot_string(str,capacity)));
177 }
178
179 PRIMITIVE(resize_string)
180 {
181         PRIMITIVE_GETVM()->vmprim_resize_string();
182 }
183
184 inline void factorvm::vmprim_string_nth()
185 {
186         string *str = untag<string>(dpop());
187         cell index = untag_fixnum(dpop());
188         dpush(tag_fixnum(string_nth(str,index)));
189 }
190
191 PRIMITIVE(string_nth)
192 {
193         PRIMITIVE_GETVM()->vmprim_string_nth();
194 }
195
196 inline void factorvm::vmprim_set_string_nth_fast()
197 {
198         string *str = untag<string>(dpop());
199         cell index = untag_fixnum(dpop());
200         cell value = untag_fixnum(dpop());
201         set_string_nth_fast(str,index,value);
202 }
203
204 PRIMITIVE(set_string_nth_fast)
205 {
206         PRIMITIVE_GETVM()->vmprim_set_string_nth_fast();
207 }
208
209 inline void factorvm::vmprim_set_string_nth_slow()
210 {
211         string *str = untag<string>(dpop());
212         cell index = untag_fixnum(dpop());
213         cell value = untag_fixnum(dpop());
214         set_string_nth_slow(str,index,value);
215 }
216
217 PRIMITIVE(set_string_nth_slow)
218 {
219         PRIMITIVE_GETVM()->vmprim_set_string_nth_slow();
220 }
221
222 }