]> gitweb.factorcode.org Git - factor.git/blob - native/string.c
all-tests now pass without out of memory errors
[factor.git] / native / string.c
1 #include "factor.h"
2
3 /* untagged */
4 F_STRING* allot_string(CELL capacity)
5 {
6         F_STRING* string = allot_object(STRING_TYPE,
7                 sizeof(F_STRING) + (capacity + 1) * CHARS);
8         /* strings are null-terminated in memory, even though they also
9         have a length field. The null termination allows us to add
10         the sizeof(F_STRING) to a Factor string to get a C-style
11         UTF16 string for C library calls. */
12         cput(SREF(string,capacity),(u16)'\0');
13         string->length = tag_fixnum(capacity);
14         return string;
15 }
16
17 /* call this after constructing a string */
18 void rehash_string(F_STRING* str)
19 {
20         F_FIXNUM hash = 0;
21         CELL i;
22         CELL capacity = string_capacity(str);
23         for(i = 0; i < capacity; i++)
24                 hash = 31*hash + string_nth(str,i);
25         str->hashcode = tag_fixnum(hash);
26 }
27
28 void primitive_rehash_string(void)
29 {
30         rehash_string(untag_string(dpop()));
31 }
32
33 /* untagged */
34 F_STRING *string(CELL capacity, CELL fill)
35 {
36         CELL i;
37
38         F_STRING* string = allot_string(capacity);
39
40         for(i = 0; i < capacity; i++)
41                 cput(SREF(string,i),fill);
42
43         rehash_string(string);
44
45         return string;
46 }
47
48 F_STRING* resize_string(F_STRING* string, F_FIXNUM capacity, u16 fill)
49 {
50         /* later on, do an optimization: if end of array is here, just grow */
51         CELL i;
52         CELL to_copy = string_capacity(string);
53
54         if(capacity < to_copy)
55                 to_copy = capacity;
56
57         F_STRING* new_string = allot_string(capacity);
58
59         memcpy(new_string + 1,string + 1,to_copy * CHARS);
60
61         for(i = to_copy; i < capacity; i++)
62                 cput(SREF(new_string,i),fill);
63
64         return new_string;
65 }
66
67 void primitive_resize_string(void)
68 {
69         F_STRING* string;
70         CELL capacity = to_fixnum(dpeek2());
71         maybe_gc(string_size(capacity));
72         string = untag_string_fast(dpop());
73         drepl(tag_object(resize_string(string,capacity,F)));
74 }
75
76 F_STRING *memory_to_string(const BYTE* string, CELL length)
77 {
78         F_STRING* s = allot_string(length);
79         CELL i;
80
81         for(i = 0; i < length; i++)
82         {
83                 cput(SREF(s,i),*string);
84                 string++;
85         }
86
87         rehash_string(s);
88         
89         return s;
90 }
91
92 void primitive_memory_to_string(void)
93 {
94         CELL length = unbox_unsigned_cell();
95         BYTE *string = (BYTE*)unbox_unsigned_cell();
96         dpush(tag_object(memory_to_string(string,length)));
97 }
98
99 /* untagged */
100 F_STRING *from_c_string(const char *c_string)
101 {
102         return memory_to_string((BYTE*)c_string,strlen(c_string));
103 }
104
105 /* FFI calls this */
106 void box_c_string(const char *c_string)
107 {
108         dpush(c_string ? tag_object(from_c_string(c_string)) : F);
109 }
110
111 /* untagged */
112 char *to_c_string(F_STRING *s)
113 {
114         CELL i;
115         CELL capacity = string_capacity(s);
116         for(i = 0; i < capacity; i++)
117         {
118                 u16 ch = string_nth(s,i);
119                 if(ch == '\0' || ch > 255)
120                         general_error(ERROR_C_STRING,tag_object(s));
121         }
122
123         return to_c_string_unchecked(s);
124 }
125
126 void string_to_memory(F_STRING *s, BYTE *string)
127 {
128         CELL i;
129         CELL capacity = string_capacity(s);
130         for(i = 0; i < capacity; i++)
131                 string[i] = string_nth(s,i);
132 }
133
134 void primitive_string_to_memory(void)
135 {
136         BYTE *address = (BYTE*)unbox_unsigned_cell();
137         F_STRING *str = untag_string(dpop());
138         string_to_memory(str,address);
139 }
140
141 /* untagged */
142 char *to_c_string_unchecked(F_STRING *s)
143 {
144         CELL capacity = string_capacity(s);
145         F_STRING *_c_str = allot_string(capacity / CHARS + 1);
146         BYTE *c_str = (BYTE*)(_c_str + 1);
147         string_to_memory(s,c_str);
148         c_str[capacity] = '\0';
149         return (char*)c_str;
150 }
151
152 /* FFI calls this */
153 char *unbox_c_string(void)
154 {
155         CELL str = dpop();
156         return (str ? to_c_string(untag_string(str)) : NULL);
157 }
158
159 /* FFI calls this */
160 u16* unbox_utf16_string(void)
161 {
162         /* Return pointer to first character */
163         return (u16*)(untag_string(dpop()) + 1);
164 }
165
166 void primitive_char_slot(void)
167 {
168         F_STRING* string = untag_string_fast(dpop());
169         CELL index = untag_fixnum_fast(dpop());
170         dpush(tag_fixnum(string_nth(string,index)));
171 }
172
173 void primitive_set_char_slot(void)
174 {
175         F_STRING* string = untag_string_fast(dpop());
176         CELL index = untag_fixnum_fast(dpop());
177         CELL value = untag_fixnum_fast(dpop());
178         set_string_nth(string,index,value);
179 }
180
181 F_FIXNUM string_compare(F_STRING* s1, F_STRING* s2)
182 {
183         CELL len1 = string_capacity(s1);
184         CELL len2 = string_capacity(s2);
185
186         CELL limit = (len1 < len2 ? len1 : len2);
187
188         CELL i = 0;
189         while(i < limit)
190         {
191                 u16 c1 = string_nth(s1,i);
192                 u16 c2 = string_nth(s2,i);
193                 if(c1 != c2)
194                         return c1 - c2;
195                 i++;
196         }
197
198         return len1 - len2;
199 }
200
201 void primitive_string_compare(void)
202 {
203         F_STRING* s2 = untag_string(dpop());
204         F_STRING* s1 = untag_string(dpop());
205
206         dpush(tag_fixnum(string_compare(s1,s2)));
207 }