Allow closeable and nvm structures to be located by where they were allocated.
[SquirrelJME.git] / nanocoat / src / stringPool.c
blob81d081f95eea266a87e858fa097135fe63bb348c
1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
10 #include <string.h>
12 #include "sjme/nvm/stringPool.h"
13 #include "sjme/cleanup.h"
14 #include "sjme/util.h"
16 /** The amount the size of the string pool should grow. */
17 #define SJME_STRING_POOL_GROW 256
19 sjme_errorCode sjme_stringPool_locateSeq(
20 sjme_attrInNotNull sjme_stringPool inStringPool,
21 sjme_attrInNotNull sjme_charSeq* inSeq,
22 sjme_attrOutNotNull sjme_stringPool_string* outString)
24 if (inStringPool == NULL || inSeq == NULL || outString == NULL)
25 return SJME_ERROR_NULL_ARGUMENTS;
27 sjme_todo("Impl?");
28 return SJME_ERROR_NOT_IMPLEMENTED;
31 sjme_errorCode sjme_stringPool_locateStream(
32 sjme_attrInNotNull sjme_stringPool inStringPool,
33 sjme_attrInNotNull sjme_stream_input inStream,
34 sjme_attrOutNotNull sjme_stringPool_string* outString)
36 sjme_errorCode error;
37 sjme_jshort length;
38 sjme_jbyte* chars;
39 sjme_jint count;
41 if (inStringPool == NULL || inStream == NULL || outString == NULL)
42 return SJME_ERROR_NULL_ARGUMENTS;
44 /* Read in string length. */
45 length = -1;
46 if (sjme_error_is(error = sjme_stream_inputReadValueJS(
47 inStream, &length)) || length < 0)
48 return sjme_error_default(error);
50 /* Allocate buffer to store it within. */
51 chars = sjme_alloca(length);
52 if (chars == NULL)
53 return sjme_error_outOfMemory(NULL, NULL);
54 memset(chars, 0, length);
56 /* Need to read in everything. */
57 if (sjme_error_is(error = sjme_stream_inputReadFully(
58 inStream, &count, chars, length)))
59 return sjme_error_default(error);
61 /* Too short of a read? */
62 if (count != length)
63 return SJME_ERROR_END_OF_FILE;
65 /* Use normal locating logic. */
66 return sjme_stringPool_locateUtf(inStringPool,
67 (sjme_lpcstr)chars, length, outString);
70 sjme_errorCode sjme_stringPool_locateUtf(
71 sjme_attrInNotNull sjme_stringPool inStringPool,
72 sjme_attrInNotNull sjme_lpcstr inUtf,
73 sjme_attrInNegativeOnePositive sjme_jint inUtfLen,
74 sjme_attrOutNotNull sjme_stringPool_string* outString)
76 sjme_errorCode error;
77 sjme_jint hash, i, n, firstFree;
78 sjme_list_sjme_stringPool_string* strings;
79 sjme_stringPool_string result;
80 sjme_stringPool_string possible;
82 if (inStringPool == NULL || inUtf == NULL || outString == NULL)
83 return SJME_ERROR_NULL_ARGUMENTS;
85 if (inUtfLen < -1)
86 return SJME_ERROR_INDEX_OUT_OF_BOUNDS;
88 /* Lock pool. */
89 if (sjme_error_is(error = sjme_thread_spinLockGrab(
90 &inStringPool->common.lock)))
91 return sjme_error_default(error);
93 /* Determine actual string length, if unknown. */
94 if (inUtfLen < 0)
95 inUtfLen = strlen(inUtf);
97 /* Calculate hash of string. */
98 hash = sjme_string_hashN(inUtf, inUtfLen);
100 /* Try to locate the string first. */
101 strings = inStringPool->strings;
102 firstFree = -1;
103 result = NULL;
104 for (i = 0, n = strings->length; i < n; i++)
106 /* Is this a filled slot? */
107 possible = strings->elements[i];
108 if (possible == NULL)
110 /* We can put a new string here. */
111 if (firstFree < 0)
112 firstFree = i;
113 continue;
116 /* If hash or length differ, not a possible match */
117 if (possible->hashCode != hash || possible->length != inUtfLen)
118 continue;
120 /* Must be exactly the same! */
121 if (0 == memcmp(&possible->chars[0], inUtf, inUtfLen))
123 result = possible;
124 break;
128 /* String is not in the pool. */
129 if (result == NULL)
131 /* Need to make the pool bigger? */
132 if (firstFree < 0)
134 sjme_todo("Impl?");
135 return sjme_error_notImplemented(0);
138 /* Allocate new result to store in the slot. */
139 result = NULL;
140 if (sjme_error_is(error = sjme_nvm_alloc(inStringPool->inPool,
141 sizeof(*result) + inUtfLen,
142 SJME_NVM_STRUCT_STRING_POOL_STRING,
143 SJME_AS_NVM_COMMONP(&result))) || result == NULL)
144 goto fail_stringAlloc;
146 /* Fill in information. */
147 memmove(&result->chars[0], inUtf, inUtfLen);
148 result->hashCode = hash;
149 result->length = inUtfLen;
150 result->seq.context = &result->chars[0];
152 /* Count up as the pool itself references it. */
153 if (sjme_error_is(error = sjme_alloc_weakRef(
154 result, NULL)))
155 goto fail_countUp;
157 /* Store it into the pool. */
158 strings->elements[firstFree] = result;
161 /* Release the lock. */
162 if (sjme_error_is(error = sjme_thread_spinLockRelease(
163 &inStringPool->common.lock, NULL)))
164 goto fail_releaseLock;
166 /* Success! */
167 *outString = result;
168 return SJME_ERROR_NONE;
170 fail_countUp:
171 fail_initCommon:
172 fail_stringAlloc:
173 if (result != NULL)
174 sjme_alloc_free(result);
176 fail_releaseLock:
177 /* Unlock before failing. */
178 sjme_thread_spinLockRelease(&inStringPool->common.lock,
179 NULL);
181 return sjme_error_default(error);
184 sjme_errorCode sjme_stringPool_new(
185 sjme_attrInNotNull sjme_alloc_pool* inPool,
186 sjme_attrOutNotNull sjme_stringPool* outStringPool)
188 sjme_errorCode error;
189 sjme_stringPool result;
190 sjme_list_sjme_stringPool_string* strings;
192 if (inPool == NULL || outStringPool == NULL)
193 return SJME_ERROR_NULL_ARGUMENTS;
195 /* Make sure we have the memory to store the buffer. */
196 strings = NULL;
197 if (sjme_error_is(error = sjme_list_alloc(
198 inPool, SJME_STRING_POOL_GROW,
199 &strings, sjme_stringPool_string, 0)) || strings == NULL)
200 goto fail_allocList;
202 /* Allocate result. */
203 result = NULL;
204 if (sjme_error_is(error = sjme_nvm_alloc(inPool,
205 sizeof(*result), SJME_NVM_STRUCT_STRING_POOL,
206 SJME_AS_NVM_COMMONP(&result))) || result == NULL)
207 goto fail_allocResult;
209 /* Setup fields. */
210 result->inPool = inPool;
211 result->strings = strings;
213 /* Success! */
214 *outStringPool = result;
215 return SJME_ERROR_NONE;
217 fail_initCommon:
218 fail_allocResult:
219 if (result != NULL)
220 sjme_alloc_free(result);
221 fail_allocList:
222 if (strings != NULL)
223 sjme_alloc_free(strings);
224 return sjme_error_default(error);