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