1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
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 // -------------------------------------------------------------------------*/
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
;
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
)
41 if (inStringPool
== NULL
|| inStream
== NULL
|| outString
== NULL
)
42 return SJME_ERROR_NULL_ARGUMENTS
;
44 /* Read in string length. */
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
);
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? */
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
)
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
;
86 return SJME_ERROR_INDEX_OUT_OF_BOUNDS
;
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. */
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
;
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. */
116 /* If hash or length differ, not a possible match */
117 if (possible
->hashCode
!= hash
|| possible
->length
!= inUtfLen
)
120 /* Must be exactly the same! */
121 if (0 == memcmp(&possible
->chars
[0], inUtf
, inUtfLen
))
128 /* String is not in the pool. */
131 /* Need to make the pool bigger? */
135 return sjme_error_notImplemented(0);
138 /* Allocate new result to store in the slot. */
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(
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
;
168 return SJME_ERROR_NONE
;
174 sjme_alloc_free(result
);
177 /* Unlock before failing. */
178 sjme_thread_spinLockRelease(&inStringPool
->common
.lock
,
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. */
197 if (sjme_error_is(error
= sjme_list_alloc(
198 inPool
, SJME_STRING_POOL_GROW
,
199 &strings
, sjme_stringPool_string
, 0)) || strings
== NULL
)
202 /* Allocate result. */
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
;
210 result
->inPool
= inPool
;
211 result
->strings
= strings
;
214 *outStringPool
= result
;
215 return SJME_ERROR_NONE
;
220 sjme_alloc_free(result
);
223 sjme_alloc_free(strings
);
224 return sjme_error_default(error
);