]> 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_FORWARD(string)
110
111 bool factor_vm::reallot_string_in_place_p(string *str, cell capacity)
112 {
113         return in_zone(&nursery,str)
114                 && (str->aux == F || in_zone(&nursery,untag<byte_array>(str->aux)))
115                 && capacity <= string_capacity(str);
116 }
117
118 string* factor_vm::reallot_string(string *str_, cell capacity)
119 {
120         gc_root<string> str(str_,this);
121
122         if(reallot_string_in_place_p(str.untagged(),capacity))
123         {
124                 str->length = tag_fixnum(capacity);
125
126                 if(str->aux != F)
127                 {
128                         byte_array *aux = untag<byte_array>(str->aux);
129                         aux->capacity = tag_fixnum(capacity * 2);
130                 }
131
132                 return str.untagged();
133         }
134         else
135         {
136                 cell to_copy = string_capacity(str.untagged());
137                 if(capacity < to_copy)
138                         to_copy = capacity;
139
140                 gc_root<string> new_str(allot_string_internal(capacity),this);
141
142                 memcpy(new_str->data(),str->data(),to_copy);
143
144                 if(str->aux != F)
145                 {
146                         byte_array *new_aux = allot_byte_array(capacity * sizeof(u16));
147
148                         write_barrier(new_str.untagged());
149                         new_str->aux = tag<byte_array>(new_aux);
150
151                         byte_array *aux = untag<byte_array>(str->aux);
152                         memcpy(new_aux->data<u16>(),aux->data<u16>(),to_copy * sizeof(u16));
153                 }
154
155                 fill_string(new_str.untagged(),to_copy,capacity,'\0');
156                 return new_str.untagged();
157         }
158 }
159
160 inline void factor_vm::primitive_resize_string()
161 {
162         string* str = untag_check<string>(dpop());
163         cell capacity = unbox_array_size();
164         dpush(tag<string>(reallot_string(str,capacity)));
165 }
166
167 PRIMITIVE_FORWARD(resize_string)
168
169 inline void factor_vm::primitive_string_nth()
170 {
171         string *str = untag<string>(dpop());
172         cell index = untag_fixnum(dpop());
173         dpush(tag_fixnum(string_nth(str,index)));
174 }
175
176 PRIMITIVE_FORWARD(string_nth)
177
178 inline void factor_vm::primitive_set_string_nth_fast()
179 {
180         string *str = untag<string>(dpop());
181         cell index = untag_fixnum(dpop());
182         cell value = untag_fixnum(dpop());
183         set_string_nth_fast(str,index,value);
184 }
185
186 PRIMITIVE_FORWARD(set_string_nth_fast)
187
188 inline void factor_vm::primitive_set_string_nth_slow()
189 {
190         string *str = untag<string>(dpop());
191         cell index = untag_fixnum(dpop());
192         cell value = untag_fixnum(dpop());
193         set_string_nth_slow(str,index,value);
194 }
195
196 PRIMITIVE_FORWARD(set_string_nth_slow)
197
198 }