Merge lp:~stewart/drizzle/json-interface into lp:~drizzle-trunk/drizzle/development
- json-interface
- Merge into development
Status: | Merged |
---|---|
Approved by: | Brian Aker |
Approved revision: | 2300 |
Merged at revision: | 2310 |
Proposed branch: | lp:~stewart/drizzle/json-interface |
Merge into: | lp:~drizzle-trunk/drizzle/development |
Diff against target: |
7884 lines (+7638/-3) 32 files modified
drizzled/plugin/client/cached.h (+1/-0) drizzled/sql/result_set.h (+5/-0) drizzled/sql/result_set_meta_data.h (+6/-1) plugin/http_functions/http_functions.cc (+199/-0) plugin/http_functions/plugin.ac (+4/-0) plugin/http_functions/plugin.cnf (+2/-0) plugin/http_functions/plugin.ini (+6/-0) plugin/json_server/json/autolink.h (+58/-0) plugin/json_server/json/config.h (+81/-0) plugin/json_server/json/features.h (+80/-0) plugin/json_server/json/forwards.h (+77/-0) plugin/json_server/json/json.h (+48/-0) plugin/json_server/json/json_batchallocator.h (+163/-0) plugin/json_server/json/json_internalarray.inl (+486/-0) plugin/json_server/json/json_internalmap.inl (+645/-0) plugin/json_server/json/json_reader.cpp (+921/-0) plugin/json_server/json/json_value.cpp (+1759/-0) plugin/json_server/json/json_valueiterator.inl (+330/-0) plugin/json_server/json/json_writer.cpp (+862/-0) plugin/json_server/json/reader.h (+234/-0) plugin/json_server/json/value.h (+1107/-0) plugin/json_server/json/writer.h (+212/-0) plugin/json_server/json_server.cc (+284/-0) plugin/json_server/plugin.ac (+1/-0) plugin/json_server/plugin.ini (+12/-0) plugin/json_server/tests/r/basic.result (+35/-0) plugin/json_server/tests/t/basic.test (+10/-0) plugin/json_server/tests/t/master.opt (+1/-0) po/POTFILES.in (+1/-0) tests/lib/drizzle_test_run/dtr_test_execution.py (+1/-0) tests/lib/server_mgmt/drizzled.py (+2/-2) tests/test-run.pl (+5/-0) |
To merge this branch: | bzr merge lp:~stewart/drizzle/json-interface |
Related bugs: | |
Related blueprints: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mark Atwood | Needs Fixing | ||
Drizzle Merge Team | Pending | ||
Review via email: mp+59859@code.launchpad.net |
This proposal supersedes a proposal from 2011-04-21.
Commit message
Description of the change
Preliminary implementation of a HTTP interface to Drizzle.
Includes testing. Uses libevent http daemon. returns results as JSON.
includes brian's fixes.
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal | # |
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal | # |
so a problem with this branch currently is that the tests use 'curl' to test the interface. Not all systems have curl installed however, so I either need to (for example) add HTTP_GET(
Brian Aker (brianaker) wrote : Posted in a previous version of this proposal | # |
We should put a comment on the code so that we know where it came from (and either our own license, or put public domain headers on it).
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal | # |
now fixed to have http_() functions in the tree that are used to test json_server. Can also be used to fetch URLs and the like.
This change means param-build passes on every system.
http://
is the other thing we should work out how to have in the soure files.
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal | # |
Mark Atwood (fallenpegasus) wrote : | # |
fail in jenkins
http://
http://
http://
http://
http://
http://
Some sort of issue with flex?
please fix and resubmit
Stewart Smith (stewart) wrote : | # |
On Thu, 12 May 2011 23:42:27 -0000, Mark Atwood <email address hidden> wrote:
> Review: Needs Fixing
> fail in jenkins
>
> http://
> http://
> http://
> http://
> http://
> http://
>
> Some sort of issue with flex?
>
looks like something from vj's sp branch, not mine.
--
Stewart Smith
Mark Atwood (fallenpegasus) wrote : | # |
>>
>
> looks like something from vj's sp branch, not mine.
Brian and I are looking at it.
Preview Diff
1 | === modified file 'drizzled/plugin/client/cached.h' | |||
2 | --- drizzled/plugin/client/cached.h 2011-03-15 23:55:01 +0000 | |||
3 | +++ drizzled/plugin/client/cached.h 2011-05-04 01:52:37 +0000 | |||
4 | @@ -57,6 +57,7 @@ | |||
5 | 57 | item->make_field(&field); | 57 | item->make_field(&field); |
6 | 58 | max_column++; | 58 | max_column++; |
7 | 59 | } | 59 | } |
8 | 60 | _result_set->setColumnCount(max_column); | ||
9 | 60 | _result_set->createRow(); | 61 | _result_set->createRow(); |
10 | 61 | 62 | ||
11 | 62 | return false; | 63 | return false; |
12 | 63 | 64 | ||
13 | === modified file 'drizzled/sql/result_set.h' | |||
14 | --- drizzled/sql/result_set.h 2011-03-29 12:45:08 +0000 | |||
15 | +++ drizzled/sql/result_set.h 2011-05-04 01:52:37 +0000 | |||
16 | @@ -101,6 +101,11 @@ | |||
17 | 101 | { | 101 | { |
18 | 102 | } | 102 | } |
19 | 103 | 103 | ||
20 | 104 | void setColumnCount(size_t fields) | ||
21 | 105 | { | ||
22 | 106 | _meta_data.setColumnCount(fields); | ||
23 | 107 | } | ||
24 | 108 | |||
25 | 104 | ~ResultSet(); | 109 | ~ResultSet(); |
26 | 105 | 110 | ||
27 | 106 | void createRow(); | 111 | void createRow(); |
28 | 107 | 112 | ||
29 | === modified file 'drizzled/sql/result_set_meta_data.h' | |||
30 | --- drizzled/sql/result_set_meta_data.h 2011-03-29 12:45:08 +0000 | |||
31 | +++ drizzled/sql/result_set_meta_data.h 2011-05-04 01:52:37 +0000 | |||
32 | @@ -53,10 +53,15 @@ | |||
33 | 53 | { | 53 | { |
34 | 54 | } | 54 | } |
35 | 55 | 55 | ||
36 | 56 | void setColumnCount(size_t fields) | ||
37 | 57 | { | ||
38 | 58 | _columns= fields; | ||
39 | 59 | } | ||
40 | 60 | |||
41 | 56 | private: // Member methods | 61 | private: // Member methods |
42 | 57 | 62 | ||
43 | 58 | private: // Member variables | 63 | private: // Member variables |
45 | 59 | const size_t _columns; | 64 | size_t _columns; |
46 | 60 | }; | 65 | }; |
47 | 61 | 66 | ||
48 | 62 | std::ostream& operator<<(std::ostream& output, const ResultSetMetaData &result_set); | 67 | std::ostream& operator<<(std::ostream& output, const ResultSetMetaData &result_set); |
49 | 63 | 68 | ||
50 | === added directory 'plugin/http_functions' | |||
51 | === added file 'plugin/http_functions/http_functions.cc' | |||
52 | --- plugin/http_functions/http_functions.cc 1970-01-01 00:00:00 +0000 | |||
53 | +++ plugin/http_functions/http_functions.cc 2011-05-04 01:52:37 +0000 | |||
54 | @@ -0,0 +1,199 @@ | |||
55 | 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- | ||
56 | 2 | * vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
57 | 3 | * | ||
58 | 4 | * Copyright (C) 2011 Stewart Smith | ||
59 | 5 | * | ||
60 | 6 | * This program is free software; you can redistribute it and/or modify | ||
61 | 7 | * it under the terms of the GNU General Public License as published by | ||
62 | 8 | * the Free Software Foundation; version 2 of the License. | ||
63 | 9 | * | ||
64 | 10 | * This program is distributed in the hope that it will be useful, | ||
65 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
66 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
67 | 13 | * GNU General Public License for more details. | ||
68 | 14 | * | ||
69 | 15 | * You should have received a copy of the GNU General Public License | ||
70 | 16 | * along with this program; if not, write to the Free Software | ||
71 | 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
72 | 18 | */ | ||
73 | 19 | |||
74 | 20 | #include <config.h> | ||
75 | 21 | |||
76 | 22 | #include <drizzled/plugin/function.h> | ||
77 | 23 | #include <drizzled/function/str/strfunc.h> | ||
78 | 24 | #include <drizzled/charset.h> | ||
79 | 25 | #include <drizzled/error.h> | ||
80 | 26 | |||
81 | 27 | #include <curl/curl.h> | ||
82 | 28 | |||
83 | 29 | using namespace drizzled; | ||
84 | 30 | |||
85 | 31 | class HttpGetFunction :public Item_str_func | ||
86 | 32 | { | ||
87 | 33 | String result; | ||
88 | 34 | public: | ||
89 | 35 | HttpGetFunction() :Item_str_func() {} | ||
90 | 36 | String *val_str(String *); | ||
91 | 37 | void fix_length_and_dec(); | ||
92 | 38 | const char *func_name() const { return "http_get"; } | ||
93 | 39 | |||
94 | 40 | bool check_argument_count(int n) | ||
95 | 41 | { | ||
96 | 42 | return n == 1; | ||
97 | 43 | } | ||
98 | 44 | }; | ||
99 | 45 | |||
100 | 46 | extern "C" size_t | ||
101 | 47 | http_get_result_cb(void *ptr, size_t size, size_t nmemb, void *data); | ||
102 | 48 | |||
103 | 49 | extern "C" size_t | ||
104 | 50 | http_get_result_cb(void *ptr, size_t size, size_t nmemb, void *data) | ||
105 | 51 | { | ||
106 | 52 | size_t realsize= size * nmemb; | ||
107 | 53 | String *result= (String *)data; | ||
108 | 54 | |||
109 | 55 | result->reserve(realsize + 1); | ||
110 | 56 | result->append((const char*)ptr, realsize); | ||
111 | 57 | |||
112 | 58 | return realsize; | ||
113 | 59 | } | ||
114 | 60 | |||
115 | 61 | |||
116 | 62 | String *HttpGetFunction::val_str(String *str) | ||
117 | 63 | { | ||
118 | 64 | assert(fixed == 1); | ||
119 | 65 | String *url = args[0]->val_str(str); | ||
120 | 66 | CURL *curl; | ||
121 | 67 | CURLcode retref; | ||
122 | 68 | |||
123 | 69 | if ((null_value=args[0]->null_value)) | ||
124 | 70 | return NULL; | ||
125 | 71 | |||
126 | 72 | curl= curl_easy_init(); | ||
127 | 73 | curl_easy_setopt(curl, CURLOPT_URL, url->c_ptr_safe()); | ||
128 | 74 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_cb); | ||
129 | 75 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&result); | ||
130 | 76 | curl_easy_setopt(curl, CURLOPT_USERAGENT, "drizzle-http-functions/1.0"); | ||
131 | 77 | retref= curl_easy_perform(curl); | ||
132 | 78 | curl_easy_cleanup(curl); | ||
133 | 79 | |||
134 | 80 | if (retref != 0) | ||
135 | 81 | my_error(ER_GET_ERRMSG, MYF(0), retref, curl_easy_strerror(retref), | ||
136 | 82 | "http_get"); | ||
137 | 83 | |||
138 | 84 | return &result; | ||
139 | 85 | } | ||
140 | 86 | |||
141 | 87 | void HttpGetFunction::fix_length_and_dec() | ||
142 | 88 | { | ||
143 | 89 | collation.set(args[0]->collation); | ||
144 | 90 | max_length = ~0; | ||
145 | 91 | } | ||
146 | 92 | |||
147 | 93 | class HttpPostFunction :public Item_str_func | ||
148 | 94 | { | ||
149 | 95 | String result; | ||
150 | 96 | public: | ||
151 | 97 | HttpPostFunction() :Item_str_func() {} | ||
152 | 98 | String *val_str(String *); | ||
153 | 99 | void fix_length_and_dec(); | ||
154 | 100 | const char *func_name() const { return "http_post"; } | ||
155 | 101 | |||
156 | 102 | bool check_argument_count(int n) | ||
157 | 103 | { | ||
158 | 104 | return n == 2; | ||
159 | 105 | } | ||
160 | 106 | }; | ||
161 | 107 | |||
162 | 108 | class HttpPostData | ||
163 | 109 | { | ||
164 | 110 | private: | ||
165 | 111 | String *data; | ||
166 | 112 | size_t progress; | ||
167 | 113 | |||
168 | 114 | public: | ||
169 | 115 | HttpPostData(String* d) : data(d), progress(0) {} | ||
170 | 116 | |||
171 | 117 | size_t length() { return data->length(); } | ||
172 | 118 | |||
173 | 119 | size_t write(void* dest, size_t size) | ||
174 | 120 | { | ||
175 | 121 | size_t to_write= size; | ||
176 | 122 | |||
177 | 123 | if ((data->length() - progress) < to_write) | ||
178 | 124 | to_write= data->length() - progress; | ||
179 | 125 | |||
180 | 126 | memcpy(dest, data->ptr() + progress, to_write); | ||
181 | 127 | |||
182 | 128 | progress+= to_write; | ||
183 | 129 | |||
184 | 130 | return to_write; | ||
185 | 131 | } | ||
186 | 132 | }; | ||
187 | 133 | |||
188 | 134 | extern "C" size_t | ||
189 | 135 | http_post_readfunc(void *ptr, size_t size, size_t nmemb, void *data); | ||
190 | 136 | |||
191 | 137 | extern "C" size_t | ||
192 | 138 | http_post_readfunc(void *ptr, size_t size, size_t nmemb, void *data) | ||
193 | 139 | { | ||
194 | 140 | size_t realsize= size * nmemb; | ||
195 | 141 | HttpPostData *post_data= (HttpPostData *)data; | ||
196 | 142 | |||
197 | 143 | return post_data->write(ptr, realsize); | ||
198 | 144 | } | ||
199 | 145 | |||
200 | 146 | String *HttpPostFunction::val_str(String *str) | ||
201 | 147 | { | ||
202 | 148 | assert(fixed == 1); | ||
203 | 149 | String *url = args[0]->val_str(str); | ||
204 | 150 | CURL *curl; | ||
205 | 151 | CURLcode retref; | ||
206 | 152 | String post_storage; | ||
207 | 153 | HttpPostData post_data(args[1]->val_str(&post_storage)); | ||
208 | 154 | |||
209 | 155 | if ((null_value=args[0]->null_value)) | ||
210 | 156 | return NULL; | ||
211 | 157 | |||
212 | 158 | curl= curl_easy_init(); | ||
213 | 159 | curl_easy_setopt(curl, CURLOPT_URL, url->c_ptr_safe()); | ||
214 | 160 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_cb); | ||
215 | 161 | curl_easy_setopt(curl, CURLOPT_POST, 1L); | ||
216 | 162 | curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post_data.length()); | ||
217 | 163 | curl_easy_setopt(curl, CURLOPT_READDATA, &post_data); | ||
218 | 164 | curl_easy_setopt(curl, CURLOPT_READFUNCTION, http_post_readfunc); | ||
219 | 165 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&result); | ||
220 | 166 | curl_easy_setopt(curl, CURLOPT_USERAGENT, "drizzle-http-functions/1.0"); | ||
221 | 167 | retref= curl_easy_perform(curl); | ||
222 | 168 | curl_easy_cleanup(curl); | ||
223 | 169 | |||
224 | 170 | return &result; | ||
225 | 171 | } | ||
226 | 172 | |||
227 | 173 | void HttpPostFunction::fix_length_and_dec() | ||
228 | 174 | { | ||
229 | 175 | collation.set(args[0]->collation); | ||
230 | 176 | max_length = ~0; | ||
231 | 177 | } | ||
232 | 178 | |||
233 | 179 | static int initialize(drizzled::module::Context &context) | ||
234 | 180 | { | ||
235 | 181 | curl_global_init(CURL_GLOBAL_ALL); | ||
236 | 182 | context.add(new plugin::Create_function<HttpGetFunction>("http_get")); | ||
237 | 183 | context.add(new plugin::Create_function<HttpPostFunction>("http_post")); | ||
238 | 184 | return 0; | ||
239 | 185 | } | ||
240 | 186 | |||
241 | 187 | DRIZZLE_DECLARE_PLUGIN | ||
242 | 188 | { | ||
243 | 189 | DRIZZLE_VERSION_ID, | ||
244 | 190 | "http_functions", | ||
245 | 191 | "1.0", | ||
246 | 192 | "Stewart Smith", | ||
247 | 193 | "HTTP functions", | ||
248 | 194 | PLUGIN_LICENSE_GPL, | ||
249 | 195 | initialize, /* Plugin Init */ | ||
250 | 196 | NULL, /* depends */ | ||
251 | 197 | NULL /* config options */ | ||
252 | 198 | } | ||
253 | 199 | DRIZZLE_DECLARE_PLUGIN_END; | ||
254 | 0 | 200 | ||
255 | === added file 'plugin/http_functions/plugin.ac' | |||
256 | --- plugin/http_functions/plugin.ac 1970-01-01 00:00:00 +0000 | |||
257 | +++ plugin/http_functions/plugin.ac 2011-05-04 01:52:37 +0000 | |||
258 | @@ -0,0 +1,4 @@ | |||
259 | 1 | PANDORA_HAVE_LIBCURL | ||
260 | 2 | AS_IF([test "x$ac_cv_libcurl" = "xno"], | ||
261 | 3 | AC_MSG_WARN([libcurl not found: not building http_functions])) | ||
262 | 4 | PANDORA_ADD_PLUGIN_DEP_LIB([${LIBCURL}]) | ||
263 | 0 | 5 | ||
264 | === added file 'plugin/http_functions/plugin.cnf' | |||
265 | --- plugin/http_functions/plugin.cnf 1970-01-01 00:00:00 +0000 | |||
266 | +++ plugin/http_functions/plugin.cnf 2011-05-04 01:52:37 +0000 | |||
267 | @@ -0,0 +1,2 @@ | |||
268 | 1 | plugin-add=http_functions | ||
269 | 2 | |||
270 | 0 | 3 | ||
271 | === added file 'plugin/http_functions/plugin.ini' | |||
272 | --- plugin/http_functions/plugin.ini 1970-01-01 00:00:00 +0000 | |||
273 | +++ plugin/http_functions/plugin.ini 2011-05-04 01:52:37 +0000 | |||
274 | @@ -0,0 +1,6 @@ | |||
275 | 1 | [plugin] | ||
276 | 2 | title=HTTP functions | ||
277 | 3 | description=HTTP functions: HTTP_GET() etc | ||
278 | 4 | sources=http_functions.cc | ||
279 | 5 | build_conditional="${ac_cv_libcurl}" = "yes" | ||
280 | 6 | ldflags=${LTLIBCURL} | ||
281 | 0 | 7 | ||
282 | === added directory 'plugin/json_server' | |||
283 | === added directory 'plugin/json_server/json' | |||
284 | === added file 'plugin/json_server/json/autolink.h' | |||
285 | --- plugin/json_server/json/autolink.h 1970-01-01 00:00:00 +0000 | |||
286 | +++ plugin/json_server/json/autolink.h 2011-05-04 01:52:37 +0000 | |||
287 | @@ -0,0 +1,58 @@ | |||
288 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
289 | 2 | * | ||
290 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
291 | 4 | * | ||
292 | 5 | * Copyright (C) 2011 Stewart Smith | ||
293 | 6 | * All rights reserved. | ||
294 | 7 | * | ||
295 | 8 | * Redistribution and use in source and binary forms, with or without | ||
296 | 9 | * modification, are permitted provided that the following conditions are | ||
297 | 10 | * met: | ||
298 | 11 | * | ||
299 | 12 | * * Redistributions of source code must retain the above copyright | ||
300 | 13 | * notice, this list of conditions and the following disclaimer. | ||
301 | 14 | * | ||
302 | 15 | * * Redistributions in binary form must reproduce the above | ||
303 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
304 | 17 | * in the documentation and/or other materials provided with the | ||
305 | 18 | * distribution. | ||
306 | 19 | * | ||
307 | 20 | * * The names of its contributors may not be used to endorse or | ||
308 | 21 | * promote products derived from this software without specific prior | ||
309 | 22 | * written permission. | ||
310 | 23 | * | ||
311 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
312 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
313 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
314 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
315 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
316 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
317 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
318 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
319 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
320 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
321 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
322 | 35 | * | ||
323 | 36 | */ | ||
324 | 37 | |||
325 | 38 | #pragma once | ||
326 | 39 | |||
327 | 40 | #ifndef JSON_AUTOLINK_H_INCLUDED | ||
328 | 41 | # define JSON_AUTOLINK_H_INCLUDED | ||
329 | 42 | |||
330 | 43 | # include "config.h" | ||
331 | 44 | |||
332 | 45 | # ifdef JSON_IN_CPPTL | ||
333 | 46 | # include <cpptl/cpptl_autolink.h> | ||
334 | 47 | # endif | ||
335 | 48 | |||
336 | 49 | # if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL) | ||
337 | 50 | # define CPPTL_AUTOLINK_NAME "json" | ||
338 | 51 | # undef CPPTL_AUTOLINK_DLL | ||
339 | 52 | # ifdef JSON_DLL | ||
340 | 53 | # define CPPTL_AUTOLINK_DLL | ||
341 | 54 | # endif | ||
342 | 55 | # include "autolink.h" | ||
343 | 56 | # endif | ||
344 | 57 | |||
345 | 58 | #endif // JSON_AUTOLINK_H_INCLUDED | ||
346 | 0 | 59 | ||
347 | === added file 'plugin/json_server/json/config.h' | |||
348 | --- plugin/json_server/json/config.h 1970-01-01 00:00:00 +0000 | |||
349 | +++ plugin/json_server/json/config.h 2011-05-04 01:52:37 +0000 | |||
350 | @@ -0,0 +1,81 @@ | |||
351 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
352 | 2 | * | ||
353 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
354 | 4 | * | ||
355 | 5 | * Copyright (C) 2011 Stewart Smith | ||
356 | 6 | * All rights reserved. | ||
357 | 7 | * | ||
358 | 8 | * Redistribution and use in source and binary forms, with or without | ||
359 | 9 | * modification, are permitted provided that the following conditions are | ||
360 | 10 | * met: | ||
361 | 11 | * | ||
362 | 12 | * * Redistributions of source code must retain the above copyright | ||
363 | 13 | * notice, this list of conditions and the following disclaimer. | ||
364 | 14 | * | ||
365 | 15 | * * Redistributions in binary form must reproduce the above | ||
366 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
367 | 17 | * in the documentation and/or other materials provided with the | ||
368 | 18 | * distribution. | ||
369 | 19 | * | ||
370 | 20 | * * The names of its contributors may not be used to endorse or | ||
371 | 21 | * promote products derived from this software without specific prior | ||
372 | 22 | * written permission. | ||
373 | 23 | * | ||
374 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
375 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
376 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
377 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
378 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
379 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
380 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
381 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
382 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
383 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
384 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
385 | 35 | * | ||
386 | 36 | */ | ||
387 | 37 | |||
388 | 38 | #pragma once | ||
389 | 39 | #ifndef JSON_CONFIG_H_INCLUDED | ||
390 | 40 | # define JSON_CONFIG_H_INCLUDED | ||
391 | 41 | |||
392 | 42 | /// If defined, indicates that json library is embedded in CppTL library. | ||
393 | 43 | //# define JSON_IN_CPPTL 1 | ||
394 | 44 | |||
395 | 45 | /// If defined, indicates that json may leverage CppTL library | ||
396 | 46 | //# define JSON_USE_CPPTL 1 | ||
397 | 47 | /// If defined, indicates that cpptl vector based map should be used instead of std::map | ||
398 | 48 | /// as Value container. | ||
399 | 49 | //# define JSON_USE_CPPTL_SMALLMAP 1 | ||
400 | 50 | /// If defined, indicates that Json specific container should be used | ||
401 | 51 | /// (hash table & simple deque container with customizable allocator). | ||
402 | 52 | /// THIS FEATURE IS STILL EXPERIMENTAL! | ||
403 | 53 | //# define JSON_VALUE_USE_INTERNAL_MAP 1 | ||
404 | 54 | /// Force usage of standard new/malloc based allocator instead of memory pool based allocator. | ||
405 | 55 | /// The memory pools allocator used optimization (initializing Value and ValueInternalLink | ||
406 | 56 | /// as if it was a POD) that may cause some validation tool to report errors. | ||
407 | 57 | /// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined. | ||
408 | 58 | //# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1 | ||
409 | 59 | |||
410 | 60 | /// If defined, indicates that Json use exception to report invalid type manipulation | ||
411 | 61 | /// instead of C assert macro. | ||
412 | 62 | # define JSON_USE_EXCEPTION 1 | ||
413 | 63 | |||
414 | 64 | # ifdef JSON_IN_CPPTL | ||
415 | 65 | # include <cpptl/config.h> | ||
416 | 66 | # ifndef JSON_USE_CPPTL | ||
417 | 67 | # define JSON_USE_CPPTL 1 | ||
418 | 68 | # endif | ||
419 | 69 | # endif | ||
420 | 70 | |||
421 | 71 | # ifdef JSON_IN_CPPTL | ||
422 | 72 | # define JSON_API CPPTL_API | ||
423 | 73 | # elif defined(JSON_DLL_BUILD) | ||
424 | 74 | # define JSON_API __declspec(dllexport) | ||
425 | 75 | # elif defined(JSON_DLL) | ||
426 | 76 | # define JSON_API __declspec(dllimport) | ||
427 | 77 | # else | ||
428 | 78 | # define JSON_API | ||
429 | 79 | # endif | ||
430 | 80 | |||
431 | 81 | #endif // JSON_CONFIG_H_INCLUDED | ||
432 | 0 | 82 | ||
433 | === added file 'plugin/json_server/json/features.h' | |||
434 | --- plugin/json_server/json/features.h 1970-01-01 00:00:00 +0000 | |||
435 | +++ plugin/json_server/json/features.h 2011-05-04 01:52:37 +0000 | |||
436 | @@ -0,0 +1,80 @@ | |||
437 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
438 | 2 | * | ||
439 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
440 | 4 | * | ||
441 | 5 | * Copyright (C) 2011 Stewart Smith | ||
442 | 6 | * All rights reserved. | ||
443 | 7 | * | ||
444 | 8 | * Redistribution and use in source and binary forms, with or without | ||
445 | 9 | * modification, are permitted provided that the following conditions are | ||
446 | 10 | * met: | ||
447 | 11 | * | ||
448 | 12 | * * Redistributions of source code must retain the above copyright | ||
449 | 13 | * notice, this list of conditions and the following disclaimer. | ||
450 | 14 | * | ||
451 | 15 | * * Redistributions in binary form must reproduce the above | ||
452 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
453 | 17 | * in the documentation and/or other materials provided with the | ||
454 | 18 | * distribution. | ||
455 | 19 | * | ||
456 | 20 | * * The names of its contributors may not be used to endorse or | ||
457 | 21 | * promote products derived from this software without specific prior | ||
458 | 22 | * written permission. | ||
459 | 23 | * | ||
460 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
461 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
462 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
463 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
464 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
465 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
466 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
467 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
468 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
469 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
470 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
471 | 35 | * | ||
472 | 36 | */ | ||
473 | 37 | |||
474 | 38 | #pragma once | ||
475 | 39 | #ifndef CPPTL_JSON_FEATURES_H_INCLUDED | ||
476 | 40 | # define CPPTL_JSON_FEATURES_H_INCLUDED | ||
477 | 41 | |||
478 | 42 | # include "forwards.h" | ||
479 | 43 | |||
480 | 44 | namespace Json { | ||
481 | 45 | |||
482 | 46 | /** \brief Configuration passed to reader and writer. | ||
483 | 47 | * This configuration object can be used to force the Reader or Writer | ||
484 | 48 | * to behave in a standard conforming way. | ||
485 | 49 | */ | ||
486 | 50 | class JSON_API Features | ||
487 | 51 | { | ||
488 | 52 | public: | ||
489 | 53 | /** \brief A configuration that allows all features and assumes all strings are UTF-8. | ||
490 | 54 | * - C & C++ comments are allowed | ||
491 | 55 | * - Root object can be any JSON value | ||
492 | 56 | * - Assumes Value strings are encoded in UTF-8 | ||
493 | 57 | */ | ||
494 | 58 | static Features all(); | ||
495 | 59 | |||
496 | 60 | /** \brief A configuration that is strictly compatible with the JSON specification. | ||
497 | 61 | * - Comments are forbidden. | ||
498 | 62 | * - Root object must be either an array or an object value. | ||
499 | 63 | * - Assumes Value strings are encoded in UTF-8 | ||
500 | 64 | */ | ||
501 | 65 | static Features strictMode(); | ||
502 | 66 | |||
503 | 67 | /** \brief Initialize the configuration like JsonConfig::allFeatures; | ||
504 | 68 | */ | ||
505 | 69 | Features(); | ||
506 | 70 | |||
507 | 71 | /// \c true if comments are allowed. Default: \c true. | ||
508 | 72 | bool allowComments_; | ||
509 | 73 | |||
510 | 74 | /// \c true if root must be either an array or an object value. Default: \c false. | ||
511 | 75 | bool strictRoot_; | ||
512 | 76 | }; | ||
513 | 77 | |||
514 | 78 | } // namespace Json | ||
515 | 79 | |||
516 | 80 | #endif // CPPTL_JSON_FEATURES_H_INCLUDED | ||
517 | 0 | 81 | ||
518 | === added file 'plugin/json_server/json/forwards.h' | |||
519 | --- plugin/json_server/json/forwards.h 1970-01-01 00:00:00 +0000 | |||
520 | +++ plugin/json_server/json/forwards.h 2011-05-04 01:52:37 +0000 | |||
521 | @@ -0,0 +1,77 @@ | |||
522 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
523 | 2 | * | ||
524 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
525 | 4 | * | ||
526 | 5 | * Copyright (C) 2011 Stewart Smith | ||
527 | 6 | * All rights reserved. | ||
528 | 7 | * | ||
529 | 8 | * Redistribution and use in source and binary forms, with or without | ||
530 | 9 | * modification, are permitted provided that the following conditions are | ||
531 | 10 | * met: | ||
532 | 11 | * | ||
533 | 12 | * * Redistributions of source code must retain the above copyright | ||
534 | 13 | * notice, this list of conditions and the following disclaimer. | ||
535 | 14 | * | ||
536 | 15 | * * Redistributions in binary form must reproduce the above | ||
537 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
538 | 17 | * in the documentation and/or other materials provided with the | ||
539 | 18 | * distribution. | ||
540 | 19 | * | ||
541 | 20 | * * The names of its contributors may not be used to endorse or | ||
542 | 21 | * promote products derived from this software without specific prior | ||
543 | 22 | * written permission. | ||
544 | 23 | * | ||
545 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
546 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
547 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
548 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
549 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
550 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
551 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
552 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
553 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
554 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
555 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
556 | 35 | * | ||
557 | 36 | */ | ||
558 | 37 | |||
559 | 38 | #pragma once | ||
560 | 39 | #ifndef JSON_FORWARDS_H_INCLUDED | ||
561 | 40 | # define JSON_FORWARDS_H_INCLUDED | ||
562 | 41 | |||
563 | 42 | # include "config.h" | ||
564 | 43 | |||
565 | 44 | namespace Json { | ||
566 | 45 | |||
567 | 46 | // writer.h | ||
568 | 47 | class FastWriter; | ||
569 | 48 | class StyledWriter; | ||
570 | 49 | |||
571 | 50 | // reader.h | ||
572 | 51 | class Reader; | ||
573 | 52 | |||
574 | 53 | // features.h | ||
575 | 54 | class Features; | ||
576 | 55 | |||
577 | 56 | // value.h | ||
578 | 57 | typedef int Int; | ||
579 | 58 | typedef unsigned int UInt; | ||
580 | 59 | class StaticString; | ||
581 | 60 | class Path; | ||
582 | 61 | class PathArgument; | ||
583 | 62 | class Value; | ||
584 | 63 | class ValueIteratorBase; | ||
585 | 64 | class ValueIterator; | ||
586 | 65 | class ValueConstIterator; | ||
587 | 66 | #ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
588 | 67 | class ValueAllocator; | ||
589 | 68 | class ValueMapAllocator; | ||
590 | 69 | class ValueInternalLink; | ||
591 | 70 | class ValueInternalArray; | ||
592 | 71 | class ValueInternalMap; | ||
593 | 72 | #endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
594 | 73 | |||
595 | 74 | } // namespace Json | ||
596 | 75 | |||
597 | 76 | |||
598 | 77 | #endif // JSON_FORWARDS_H_INCLUDED | ||
599 | 0 | 78 | ||
600 | === added file 'plugin/json_server/json/json.h' | |||
601 | --- plugin/json_server/json/json.h 1970-01-01 00:00:00 +0000 | |||
602 | +++ plugin/json_server/json/json.h 2011-05-04 01:52:37 +0000 | |||
603 | @@ -0,0 +1,48 @@ | |||
604 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
605 | 2 | * | ||
606 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
607 | 4 | * | ||
608 | 5 | * Copyright (C) 2011 Stewart Smith | ||
609 | 6 | * All rights reserved. | ||
610 | 7 | * | ||
611 | 8 | * Redistribution and use in source and binary forms, with or without | ||
612 | 9 | * modification, are permitted provided that the following conditions are | ||
613 | 10 | * met: | ||
614 | 11 | * | ||
615 | 12 | * * Redistributions of source code must retain the above copyright | ||
616 | 13 | * notice, this list of conditions and the following disclaimer. | ||
617 | 14 | * | ||
618 | 15 | * * Redistributions in binary form must reproduce the above | ||
619 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
620 | 17 | * in the documentation and/or other materials provided with the | ||
621 | 18 | * distribution. | ||
622 | 19 | * | ||
623 | 20 | * * The names of its contributors may not be used to endorse or | ||
624 | 21 | * promote products derived from this software without specific prior | ||
625 | 22 | * written permission. | ||
626 | 23 | * | ||
627 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
628 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
629 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
630 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
631 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
632 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
633 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
634 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
635 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
636 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
637 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
638 | 35 | * | ||
639 | 36 | */ | ||
640 | 37 | |||
641 | 38 | #pragma once | ||
642 | 39 | #ifndef JSON_JSON_H_INCLUDED | ||
643 | 40 | # define JSON_JSON_H_INCLUDED | ||
644 | 41 | |||
645 | 42 | # include "autolink.h" | ||
646 | 43 | # include "value.h" | ||
647 | 44 | # include "reader.h" | ||
648 | 45 | # include "writer.h" | ||
649 | 46 | # include "features.h" | ||
650 | 47 | |||
651 | 48 | #endif // JSON_JSON_H_INCLUDED | ||
652 | 0 | 49 | ||
653 | === added file 'plugin/json_server/json/json_batchallocator.h' | |||
654 | --- plugin/json_server/json/json_batchallocator.h 1970-01-01 00:00:00 +0000 | |||
655 | +++ plugin/json_server/json/json_batchallocator.h 2011-05-04 01:52:37 +0000 | |||
656 | @@ -0,0 +1,163 @@ | |||
657 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
658 | 2 | * | ||
659 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
660 | 4 | * | ||
661 | 5 | * Copyright (C) 2011 Stewart Smith | ||
662 | 6 | * All rights reserved. | ||
663 | 7 | * | ||
664 | 8 | * Redistribution and use in source and binary forms, with or without | ||
665 | 9 | * modification, are permitted provided that the following conditions are | ||
666 | 10 | * met: | ||
667 | 11 | * | ||
668 | 12 | * * Redistributions of source code must retain the above copyright | ||
669 | 13 | * notice, this list of conditions and the following disclaimer. | ||
670 | 14 | * | ||
671 | 15 | * * Redistributions in binary form must reproduce the above | ||
672 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
673 | 17 | * in the documentation and/or other materials provided with the | ||
674 | 18 | * distribution. | ||
675 | 19 | * | ||
676 | 20 | * * The names of its contributors may not be used to endorse or | ||
677 | 21 | * promote products derived from this software without specific prior | ||
678 | 22 | * written permission. | ||
679 | 23 | * | ||
680 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
681 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
682 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
683 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
684 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
685 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
686 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
687 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
688 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
689 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
690 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
691 | 35 | * | ||
692 | 36 | */ | ||
693 | 37 | |||
694 | 38 | #pragma once | ||
695 | 39 | #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED | ||
696 | 40 | # define JSONCPP_BATCHALLOCATOR_H_INCLUDED | ||
697 | 41 | |||
698 | 42 | # include <stdlib.h> | ||
699 | 43 | # include <assert.h> | ||
700 | 44 | |||
701 | 45 | # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION | ||
702 | 46 | |||
703 | 47 | namespace Json { | ||
704 | 48 | |||
705 | 49 | /* Fast memory allocator. | ||
706 | 50 | * | ||
707 | 51 | * This memory allocator allocates memory for a batch of object (specified by | ||
708 | 52 | * the page size, the number of object in each page). | ||
709 | 53 | * | ||
710 | 54 | * It does not allow the destruction of a single object. All the allocated objects | ||
711 | 55 | * can be destroyed at once. The memory can be either released or reused for future | ||
712 | 56 | * allocation. | ||
713 | 57 | * | ||
714 | 58 | * The in-place new operator must be used to construct the object using the pointer | ||
715 | 59 | * returned by allocate. | ||
716 | 60 | */ | ||
717 | 61 | template<typename AllocatedType | ||
718 | 62 | ,const unsigned int objectPerAllocation> | ||
719 | 63 | class BatchAllocator | ||
720 | 64 | { | ||
721 | 65 | public: | ||
722 | 66 | typedef AllocatedType Type; | ||
723 | 67 | |||
724 | 68 | BatchAllocator( unsigned int objectsPerPage = 255 ) | ||
725 | 69 | : freeHead_( 0 ) | ||
726 | 70 | , objectsPerPage_( objectsPerPage ) | ||
727 | 71 | { | ||
728 | 72 | // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); | ||
729 | 73 | assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. | ||
730 | 74 | assert( objectsPerPage >= 16 ); | ||
731 | 75 | batches_ = allocateBatch( 0 ); // allocated a dummy page | ||
732 | 76 | currentBatch_ = batches_; | ||
733 | 77 | } | ||
734 | 78 | |||
735 | 79 | ~BatchAllocator() | ||
736 | 80 | { | ||
737 | 81 | for ( BatchInfo *batch = batches_; batch; ) | ||
738 | 82 | { | ||
739 | 83 | BatchInfo *nextBatch = batch->next_; | ||
740 | 84 | free( batch ); | ||
741 | 85 | batch = nextBatch; | ||
742 | 86 | } | ||
743 | 87 | } | ||
744 | 88 | |||
745 | 89 | /// allocate space for an array of objectPerAllocation object. | ||
746 | 90 | /// @warning it is the responsability of the caller to call objects constructors. | ||
747 | 91 | AllocatedType *allocate() | ||
748 | 92 | { | ||
749 | 93 | if ( freeHead_ ) // returns node from free list. | ||
750 | 94 | { | ||
751 | 95 | AllocatedType *object = freeHead_; | ||
752 | 96 | freeHead_ = *(AllocatedType **)object; | ||
753 | 97 | return object; | ||
754 | 98 | } | ||
755 | 99 | if ( currentBatch_->used_ == currentBatch_->end_ ) | ||
756 | 100 | { | ||
757 | 101 | currentBatch_ = currentBatch_->next_; | ||
758 | 102 | while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) | ||
759 | 103 | currentBatch_ = currentBatch_->next_; | ||
760 | 104 | |||
761 | 105 | if ( !currentBatch_ ) // no free batch found, allocate a new one | ||
762 | 106 | { | ||
763 | 107 | currentBatch_ = allocateBatch( objectsPerPage_ ); | ||
764 | 108 | currentBatch_->next_ = batches_; // insert at the head of the list | ||
765 | 109 | batches_ = currentBatch_; | ||
766 | 110 | } | ||
767 | 111 | } | ||
768 | 112 | AllocatedType *allocated = currentBatch_->used_; | ||
769 | 113 | currentBatch_->used_ += objectPerAllocation; | ||
770 | 114 | return allocated; | ||
771 | 115 | } | ||
772 | 116 | |||
773 | 117 | /// Release the object. | ||
774 | 118 | /// @warning it is the responsability of the caller to actually destruct the object. | ||
775 | 119 | void release( AllocatedType *object ) | ||
776 | 120 | { | ||
777 | 121 | assert( object != 0 ); | ||
778 | 122 | *(AllocatedType **)object = freeHead_; | ||
779 | 123 | freeHead_ = object; | ||
780 | 124 | } | ||
781 | 125 | |||
782 | 126 | private: | ||
783 | 127 | struct BatchInfo | ||
784 | 128 | { | ||
785 | 129 | BatchInfo *next_; | ||
786 | 130 | AllocatedType *used_; | ||
787 | 131 | AllocatedType *end_; | ||
788 | 132 | AllocatedType buffer_[objectPerAllocation]; | ||
789 | 133 | }; | ||
790 | 134 | |||
791 | 135 | // disabled copy constructor and assignement operator. | ||
792 | 136 | BatchAllocator( const BatchAllocator & ); | ||
793 | 137 | void operator =( const BatchAllocator &); | ||
794 | 138 | |||
795 | 139 | static BatchInfo *allocateBatch( unsigned int objectsPerPage ) | ||
796 | 140 | { | ||
797 | 141 | const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation | ||
798 | 142 | + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; | ||
799 | 143 | BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) ); | ||
800 | 144 | batch->next_ = 0; | ||
801 | 145 | batch->used_ = batch->buffer_; | ||
802 | 146 | batch->end_ = batch->buffer_ + objectsPerPage; | ||
803 | 147 | return batch; | ||
804 | 148 | } | ||
805 | 149 | |||
806 | 150 | BatchInfo *batches_; | ||
807 | 151 | BatchInfo *currentBatch_; | ||
808 | 152 | /// Head of a single linked list within the allocated space of freeed object | ||
809 | 153 | AllocatedType *freeHead_; | ||
810 | 154 | unsigned int objectsPerPage_; | ||
811 | 155 | }; | ||
812 | 156 | |||
813 | 157 | |||
814 | 158 | } // namespace Json | ||
815 | 159 | |||
816 | 160 | # endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION | ||
817 | 161 | |||
818 | 162 | #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED | ||
819 | 163 | |||
820 | 0 | 164 | ||
821 | === added file 'plugin/json_server/json/json_internalarray.inl' | |||
822 | --- plugin/json_server/json/json_internalarray.inl 1970-01-01 00:00:00 +0000 | |||
823 | +++ plugin/json_server/json/json_internalarray.inl 2011-05-04 01:52:37 +0000 | |||
824 | @@ -0,0 +1,486 @@ | |||
825 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
826 | 2 | * | ||
827 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
828 | 4 | * | ||
829 | 5 | * Copyright (C) 2011 Stewart Smith | ||
830 | 6 | * All rights reserved. | ||
831 | 7 | * | ||
832 | 8 | * Redistribution and use in source and binary forms, with or without | ||
833 | 9 | * modification, are permitted provided that the following conditions are | ||
834 | 10 | * met: | ||
835 | 11 | * | ||
836 | 12 | * * Redistributions of source code must retain the above copyright | ||
837 | 13 | * notice, this list of conditions and the following disclaimer. | ||
838 | 14 | * | ||
839 | 15 | * * Redistributions in binary form must reproduce the above | ||
840 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
841 | 17 | * in the documentation and/or other materials provided with the | ||
842 | 18 | * distribution. | ||
843 | 19 | * | ||
844 | 20 | * * The names of its contributors may not be used to endorse or | ||
845 | 21 | * promote products derived from this software without specific prior | ||
846 | 22 | * written permission. | ||
847 | 23 | * | ||
848 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
849 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
850 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
851 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
852 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
853 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
854 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
855 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
856 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
857 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
858 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
859 | 35 | * | ||
860 | 36 | */ | ||
861 | 37 | |||
862 | 38 | #pragma once | ||
863 | 39 | // included by json_value.cpp | ||
864 | 40 | // everything is within Json namespace | ||
865 | 41 | |||
866 | 42 | // ////////////////////////////////////////////////////////////////// | ||
867 | 43 | // ////////////////////////////////////////////////////////////////// | ||
868 | 44 | // ////////////////////////////////////////////////////////////////// | ||
869 | 45 | // class ValueInternalArray | ||
870 | 46 | // ////////////////////////////////////////////////////////////////// | ||
871 | 47 | // ////////////////////////////////////////////////////////////////// | ||
872 | 48 | // ////////////////////////////////////////////////////////////////// | ||
873 | 49 | |||
874 | 50 | ValueArrayAllocator::~ValueArrayAllocator() | ||
875 | 51 | { | ||
876 | 52 | } | ||
877 | 53 | |||
878 | 54 | // ////////////////////////////////////////////////////////////////// | ||
879 | 55 | // class DefaultValueArrayAllocator | ||
880 | 56 | // ////////////////////////////////////////////////////////////////// | ||
881 | 57 | #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR | ||
882 | 58 | class DefaultValueArrayAllocator : public ValueArrayAllocator | ||
883 | 59 | { | ||
884 | 60 | public: // overridden from ValueArrayAllocator | ||
885 | 61 | virtual ~DefaultValueArrayAllocator() | ||
886 | 62 | { | ||
887 | 63 | } | ||
888 | 64 | |||
889 | 65 | virtual ValueInternalArray *newArray() | ||
890 | 66 | { | ||
891 | 67 | return new ValueInternalArray(); | ||
892 | 68 | } | ||
893 | 69 | |||
894 | 70 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) | ||
895 | 71 | { | ||
896 | 72 | return new ValueInternalArray( other ); | ||
897 | 73 | } | ||
898 | 74 | |||
899 | 75 | virtual void destructArray( ValueInternalArray *array ) | ||
900 | 76 | { | ||
901 | 77 | delete array; | ||
902 | 78 | } | ||
903 | 79 | |||
904 | 80 | virtual void reallocateArrayPageIndex( Value **&indexes, | ||
905 | 81 | ValueInternalArray::PageIndex &indexCount, | ||
906 | 82 | ValueInternalArray::PageIndex minNewIndexCount ) | ||
907 | 83 | { | ||
908 | 84 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; | ||
909 | 85 | if ( minNewIndexCount > newIndexCount ) | ||
910 | 86 | newIndexCount = minNewIndexCount; | ||
911 | 87 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); | ||
912 | 88 | if ( !newIndexes ) | ||
913 | 89 | throw std::bad_alloc(); | ||
914 | 90 | indexCount = newIndexCount; | ||
915 | 91 | indexes = static_cast<Value **>( newIndexes ); | ||
916 | 92 | } | ||
917 | 93 | virtual void releaseArrayPageIndex( Value **indexes, | ||
918 | 94 | ValueInternalArray::PageIndex indexCount ) | ||
919 | 95 | { | ||
920 | 96 | if ( indexes ) | ||
921 | 97 | free( indexes ); | ||
922 | 98 | } | ||
923 | 99 | |||
924 | 100 | virtual Value *allocateArrayPage() | ||
925 | 101 | { | ||
926 | 102 | return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) ); | ||
927 | 103 | } | ||
928 | 104 | |||
929 | 105 | virtual void releaseArrayPage( Value *value ) | ||
930 | 106 | { | ||
931 | 107 | if ( value ) | ||
932 | 108 | free( value ); | ||
933 | 109 | } | ||
934 | 110 | }; | ||
935 | 111 | |||
936 | 112 | #else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR | ||
937 | 113 | /// @todo make this thread-safe (lock when accessign batch allocator) | ||
938 | 114 | class DefaultValueArrayAllocator : public ValueArrayAllocator | ||
939 | 115 | { | ||
940 | 116 | public: // overridden from ValueArrayAllocator | ||
941 | 117 | virtual ~DefaultValueArrayAllocator() | ||
942 | 118 | { | ||
943 | 119 | } | ||
944 | 120 | |||
945 | 121 | virtual ValueInternalArray *newArray() | ||
946 | 122 | { | ||
947 | 123 | ValueInternalArray *array = arraysAllocator_.allocate(); | ||
948 | 124 | new (array) ValueInternalArray(); // placement new | ||
949 | 125 | return array; | ||
950 | 126 | } | ||
951 | 127 | |||
952 | 128 | virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) | ||
953 | 129 | { | ||
954 | 130 | ValueInternalArray *array = arraysAllocator_.allocate(); | ||
955 | 131 | new (array) ValueInternalArray( other ); // placement new | ||
956 | 132 | return array; | ||
957 | 133 | } | ||
958 | 134 | |||
959 | 135 | virtual void destructArray( ValueInternalArray *array ) | ||
960 | 136 | { | ||
961 | 137 | if ( array ) | ||
962 | 138 | { | ||
963 | 139 | array->~ValueInternalArray(); | ||
964 | 140 | arraysAllocator_.release( array ); | ||
965 | 141 | } | ||
966 | 142 | } | ||
967 | 143 | |||
968 | 144 | virtual void reallocateArrayPageIndex( Value **&indexes, | ||
969 | 145 | ValueInternalArray::PageIndex &indexCount, | ||
970 | 146 | ValueInternalArray::PageIndex minNewIndexCount ) | ||
971 | 147 | { | ||
972 | 148 | ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1; | ||
973 | 149 | if ( minNewIndexCount > newIndexCount ) | ||
974 | 150 | newIndexCount = minNewIndexCount; | ||
975 | 151 | void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount ); | ||
976 | 152 | if ( !newIndexes ) | ||
977 | 153 | throw std::bad_alloc(); | ||
978 | 154 | indexCount = newIndexCount; | ||
979 | 155 | indexes = static_cast<Value **>( newIndexes ); | ||
980 | 156 | } | ||
981 | 157 | virtual void releaseArrayPageIndex( Value **indexes, | ||
982 | 158 | ValueInternalArray::PageIndex indexCount ) | ||
983 | 159 | { | ||
984 | 160 | if ( indexes ) | ||
985 | 161 | free( indexes ); | ||
986 | 162 | } | ||
987 | 163 | |||
988 | 164 | virtual Value *allocateArrayPage() | ||
989 | 165 | { | ||
990 | 166 | return static_cast<Value *>( pagesAllocator_.allocate() ); | ||
991 | 167 | } | ||
992 | 168 | |||
993 | 169 | virtual void releaseArrayPage( Value *value ) | ||
994 | 170 | { | ||
995 | 171 | if ( value ) | ||
996 | 172 | pagesAllocator_.release( value ); | ||
997 | 173 | } | ||
998 | 174 | private: | ||
999 | 175 | BatchAllocator<ValueInternalArray,1> arraysAllocator_; | ||
1000 | 176 | BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_; | ||
1001 | 177 | }; | ||
1002 | 178 | #endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR | ||
1003 | 179 | |||
1004 | 180 | static ValueArrayAllocator *&arrayAllocator() | ||
1005 | 181 | { | ||
1006 | 182 | static DefaultValueArrayAllocator defaultAllocator; | ||
1007 | 183 | static ValueArrayAllocator *arrayAllocator = &defaultAllocator; | ||
1008 | 184 | return arrayAllocator; | ||
1009 | 185 | } | ||
1010 | 186 | |||
1011 | 187 | static struct DummyArrayAllocatorInitializer { | ||
1012 | 188 | DummyArrayAllocatorInitializer() | ||
1013 | 189 | { | ||
1014 | 190 | arrayAllocator(); // ensure arrayAllocator() statics are initialized before main(). | ||
1015 | 191 | } | ||
1016 | 192 | } dummyArrayAllocatorInitializer; | ||
1017 | 193 | |||
1018 | 194 | // ////////////////////////////////////////////////////////////////// | ||
1019 | 195 | // class ValueInternalArray | ||
1020 | 196 | // ////////////////////////////////////////////////////////////////// | ||
1021 | 197 | bool | ||
1022 | 198 | ValueInternalArray::equals( const IteratorState &x, | ||
1023 | 199 | const IteratorState &other ) | ||
1024 | 200 | { | ||
1025 | 201 | return x.array_ == other.array_ | ||
1026 | 202 | && x.currentItemIndex_ == other.currentItemIndex_ | ||
1027 | 203 | && x.currentPageIndex_ == other.currentPageIndex_; | ||
1028 | 204 | } | ||
1029 | 205 | |||
1030 | 206 | |||
1031 | 207 | void | ||
1032 | 208 | ValueInternalArray::increment( IteratorState &it ) | ||
1033 | 209 | { | ||
1034 | 210 | JSON_ASSERT_MESSAGE( it.array_ && | ||
1035 | 211 | (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ | ||
1036 | 212 | != it.array_->size_, | ||
1037 | 213 | "ValueInternalArray::increment(): moving iterator beyond end" ); | ||
1038 | 214 | ++(it.currentItemIndex_); | ||
1039 | 215 | if ( it.currentItemIndex_ == itemsPerPage ) | ||
1040 | 216 | { | ||
1041 | 217 | it.currentItemIndex_ = 0; | ||
1042 | 218 | ++(it.currentPageIndex_); | ||
1043 | 219 | } | ||
1044 | 220 | } | ||
1045 | 221 | |||
1046 | 222 | |||
1047 | 223 | void | ||
1048 | 224 | ValueInternalArray::decrement( IteratorState &it ) | ||
1049 | 225 | { | ||
1050 | 226 | JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_ | ||
1051 | 227 | && it.currentItemIndex_ == 0, | ||
1052 | 228 | "ValueInternalArray::decrement(): moving iterator beyond end" ); | ||
1053 | 229 | if ( it.currentItemIndex_ == 0 ) | ||
1054 | 230 | { | ||
1055 | 231 | it.currentItemIndex_ = itemsPerPage-1; | ||
1056 | 232 | --(it.currentPageIndex_); | ||
1057 | 233 | } | ||
1058 | 234 | else | ||
1059 | 235 | { | ||
1060 | 236 | --(it.currentItemIndex_); | ||
1061 | 237 | } | ||
1062 | 238 | } | ||
1063 | 239 | |||
1064 | 240 | |||
1065 | 241 | Value & | ||
1066 | 242 | ValueInternalArray::unsafeDereference( const IteratorState &it ) | ||
1067 | 243 | { | ||
1068 | 244 | return (*(it.currentPageIndex_))[it.currentItemIndex_]; | ||
1069 | 245 | } | ||
1070 | 246 | |||
1071 | 247 | |||
1072 | 248 | Value & | ||
1073 | 249 | ValueInternalArray::dereference( const IteratorState &it ) | ||
1074 | 250 | { | ||
1075 | 251 | JSON_ASSERT_MESSAGE( it.array_ && | ||
1076 | 252 | (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_ | ||
1077 | 253 | < it.array_->size_, | ||
1078 | 254 | "ValueInternalArray::dereference(): dereferencing invalid iterator" ); | ||
1079 | 255 | return unsafeDereference( it ); | ||
1080 | 256 | } | ||
1081 | 257 | |||
1082 | 258 | void | ||
1083 | 259 | ValueInternalArray::makeBeginIterator( IteratorState &it ) const | ||
1084 | 260 | { | ||
1085 | 261 | it.array_ = const_cast<ValueInternalArray *>( this ); | ||
1086 | 262 | it.currentItemIndex_ = 0; | ||
1087 | 263 | it.currentPageIndex_ = pages_; | ||
1088 | 264 | } | ||
1089 | 265 | |||
1090 | 266 | |||
1091 | 267 | void | ||
1092 | 268 | ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const | ||
1093 | 269 | { | ||
1094 | 270 | it.array_ = const_cast<ValueInternalArray *>( this ); | ||
1095 | 271 | it.currentItemIndex_ = index % itemsPerPage; | ||
1096 | 272 | it.currentPageIndex_ = pages_ + index / itemsPerPage; | ||
1097 | 273 | } | ||
1098 | 274 | |||
1099 | 275 | |||
1100 | 276 | void | ||
1101 | 277 | ValueInternalArray::makeEndIterator( IteratorState &it ) const | ||
1102 | 278 | { | ||
1103 | 279 | makeIterator( it, size_ ); | ||
1104 | 280 | } | ||
1105 | 281 | |||
1106 | 282 | |||
1107 | 283 | ValueInternalArray::ValueInternalArray() | ||
1108 | 284 | : pages_( 0 ) | ||
1109 | 285 | , size_( 0 ) | ||
1110 | 286 | , pageCount_( 0 ) | ||
1111 | 287 | { | ||
1112 | 288 | } | ||
1113 | 289 | |||
1114 | 290 | |||
1115 | 291 | ValueInternalArray::ValueInternalArray( const ValueInternalArray &other ) | ||
1116 | 292 | : pages_( 0 ) | ||
1117 | 293 | , pageCount_( 0 ) | ||
1118 | 294 | , size_( other.size_ ) | ||
1119 | 295 | { | ||
1120 | 296 | PageIndex minNewPages = other.size_ / itemsPerPage; | ||
1121 | 297 | arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); | ||
1122 | 298 | JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, | ||
1123 | 299 | "ValueInternalArray::reserve(): bad reallocation" ); | ||
1124 | 300 | IteratorState itOther; | ||
1125 | 301 | other.makeBeginIterator( itOther ); | ||
1126 | 302 | Value *value; | ||
1127 | 303 | for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) ) | ||
1128 | 304 | { | ||
1129 | 305 | if ( index % itemsPerPage == 0 ) | ||
1130 | 306 | { | ||
1131 | 307 | PageIndex pageIndex = index / itemsPerPage; | ||
1132 | 308 | value = arrayAllocator()->allocateArrayPage(); | ||
1133 | 309 | pages_[pageIndex] = value; | ||
1134 | 310 | } | ||
1135 | 311 | new (value) Value( dereference( itOther ) ); | ||
1136 | 312 | } | ||
1137 | 313 | } | ||
1138 | 314 | |||
1139 | 315 | |||
1140 | 316 | ValueInternalArray & | ||
1141 | 317 | ValueInternalArray::operator =( const ValueInternalArray &other ) | ||
1142 | 318 | { | ||
1143 | 319 | ValueInternalArray temp( other ); | ||
1144 | 320 | swap( temp ); | ||
1145 | 321 | return *this; | ||
1146 | 322 | } | ||
1147 | 323 | |||
1148 | 324 | |||
1149 | 325 | ValueInternalArray::~ValueInternalArray() | ||
1150 | 326 | { | ||
1151 | 327 | // destroy all constructed items | ||
1152 | 328 | IteratorState it; | ||
1153 | 329 | IteratorState itEnd; | ||
1154 | 330 | makeBeginIterator( it); | ||
1155 | 331 | makeEndIterator( itEnd ); | ||
1156 | 332 | for ( ; !equals(it,itEnd); increment(it) ) | ||
1157 | 333 | { | ||
1158 | 334 | Value *value = &dereference(it); | ||
1159 | 335 | value->~Value(); | ||
1160 | 336 | } | ||
1161 | 337 | // release all pages | ||
1162 | 338 | PageIndex lastPageIndex = size_ / itemsPerPage; | ||
1163 | 339 | for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex ) | ||
1164 | 340 | arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); | ||
1165 | 341 | // release pages index | ||
1166 | 342 | arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ ); | ||
1167 | 343 | } | ||
1168 | 344 | |||
1169 | 345 | |||
1170 | 346 | void | ||
1171 | 347 | ValueInternalArray::swap( ValueInternalArray &other ) | ||
1172 | 348 | { | ||
1173 | 349 | Value **tempPages = pages_; | ||
1174 | 350 | pages_ = other.pages_; | ||
1175 | 351 | other.pages_ = tempPages; | ||
1176 | 352 | ArrayIndex tempSize = size_; | ||
1177 | 353 | size_ = other.size_; | ||
1178 | 354 | other.size_ = tempSize; | ||
1179 | 355 | PageIndex tempPageCount = pageCount_; | ||
1180 | 356 | pageCount_ = other.pageCount_; | ||
1181 | 357 | other.pageCount_ = tempPageCount; | ||
1182 | 358 | } | ||
1183 | 359 | |||
1184 | 360 | void | ||
1185 | 361 | ValueInternalArray::clear() | ||
1186 | 362 | { | ||
1187 | 363 | ValueInternalArray dummy; | ||
1188 | 364 | swap( dummy ); | ||
1189 | 365 | } | ||
1190 | 366 | |||
1191 | 367 | |||
1192 | 368 | void | ||
1193 | 369 | ValueInternalArray::resize( ArrayIndex newSize ) | ||
1194 | 370 | { | ||
1195 | 371 | if ( newSize == 0 ) | ||
1196 | 372 | clear(); | ||
1197 | 373 | else if ( newSize < size_ ) | ||
1198 | 374 | { | ||
1199 | 375 | IteratorState it; | ||
1200 | 376 | IteratorState itEnd; | ||
1201 | 377 | makeIterator( it, newSize ); | ||
1202 | 378 | makeIterator( itEnd, size_ ); | ||
1203 | 379 | for ( ; !equals(it,itEnd); increment(it) ) | ||
1204 | 380 | { | ||
1205 | 381 | Value *value = &dereference(it); | ||
1206 | 382 | value->~Value(); | ||
1207 | 383 | } | ||
1208 | 384 | PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage; | ||
1209 | 385 | PageIndex lastPageIndex = size_ / itemsPerPage; | ||
1210 | 386 | for ( ; pageIndex < lastPageIndex; ++pageIndex ) | ||
1211 | 387 | arrayAllocator()->releaseArrayPage( pages_[pageIndex] ); | ||
1212 | 388 | size_ = newSize; | ||
1213 | 389 | } | ||
1214 | 390 | else if ( newSize > size_ ) | ||
1215 | 391 | resolveReference( newSize ); | ||
1216 | 392 | } | ||
1217 | 393 | |||
1218 | 394 | |||
1219 | 395 | void | ||
1220 | 396 | ValueInternalArray::makeIndexValid( ArrayIndex index ) | ||
1221 | 397 | { | ||
1222 | 398 | // Need to enlarge page index ? | ||
1223 | 399 | if ( index >= pageCount_ * itemsPerPage ) | ||
1224 | 400 | { | ||
1225 | 401 | PageIndex minNewPages = (index + 1) / itemsPerPage; | ||
1226 | 402 | arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages ); | ||
1227 | 403 | JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" ); | ||
1228 | 404 | } | ||
1229 | 405 | |||
1230 | 406 | // Need to allocate new pages ? | ||
1231 | 407 | ArrayIndex nextPageIndex = | ||
1232 | 408 | (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage | ||
1233 | 409 | : size_; | ||
1234 | 410 | if ( nextPageIndex <= index ) | ||
1235 | 411 | { | ||
1236 | 412 | PageIndex pageIndex = nextPageIndex / itemsPerPage; | ||
1237 | 413 | PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1; | ||
1238 | 414 | for ( ; pageToAllocate-- > 0; ++pageIndex ) | ||
1239 | 415 | pages_[pageIndex] = arrayAllocator()->allocateArrayPage(); | ||
1240 | 416 | } | ||
1241 | 417 | |||
1242 | 418 | // Initialize all new entries | ||
1243 | 419 | IteratorState it; | ||
1244 | 420 | IteratorState itEnd; | ||
1245 | 421 | makeIterator( it, size_ ); | ||
1246 | 422 | size_ = index + 1; | ||
1247 | 423 | makeIterator( itEnd, size_ ); | ||
1248 | 424 | for ( ; !equals(it,itEnd); increment(it) ) | ||
1249 | 425 | { | ||
1250 | 426 | Value *value = &dereference(it); | ||
1251 | 427 | new (value) Value(); // Construct a default value using placement new | ||
1252 | 428 | } | ||
1253 | 429 | } | ||
1254 | 430 | |||
1255 | 431 | Value & | ||
1256 | 432 | ValueInternalArray::resolveReference( ArrayIndex index ) | ||
1257 | 433 | { | ||
1258 | 434 | if ( index >= size_ ) | ||
1259 | 435 | makeIndexValid( index ); | ||
1260 | 436 | return pages_[index/itemsPerPage][index%itemsPerPage]; | ||
1261 | 437 | } | ||
1262 | 438 | |||
1263 | 439 | Value * | ||
1264 | 440 | ValueInternalArray::find( ArrayIndex index ) const | ||
1265 | 441 | { | ||
1266 | 442 | if ( index >= size_ ) | ||
1267 | 443 | return 0; | ||
1268 | 444 | return &(pages_[index/itemsPerPage][index%itemsPerPage]); | ||
1269 | 445 | } | ||
1270 | 446 | |||
1271 | 447 | ValueInternalArray::ArrayIndex | ||
1272 | 448 | ValueInternalArray::size() const | ||
1273 | 449 | { | ||
1274 | 450 | return size_; | ||
1275 | 451 | } | ||
1276 | 452 | |||
1277 | 453 | int | ||
1278 | 454 | ValueInternalArray::distance( const IteratorState &x, const IteratorState &y ) | ||
1279 | 455 | { | ||
1280 | 456 | return indexOf(y) - indexOf(x); | ||
1281 | 457 | } | ||
1282 | 458 | |||
1283 | 459 | |||
1284 | 460 | ValueInternalArray::ArrayIndex | ||
1285 | 461 | ValueInternalArray::indexOf( const IteratorState &iterator ) | ||
1286 | 462 | { | ||
1287 | 463 | if ( !iterator.array_ ) | ||
1288 | 464 | return ArrayIndex(-1); | ||
1289 | 465 | return ArrayIndex( | ||
1290 | 466 | (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage | ||
1291 | 467 | + iterator.currentItemIndex_ ); | ||
1292 | 468 | } | ||
1293 | 469 | |||
1294 | 470 | |||
1295 | 471 | int | ||
1296 | 472 | ValueInternalArray::compare( const ValueInternalArray &other ) const | ||
1297 | 473 | { | ||
1298 | 474 | int sizeDiff( size_ - other.size_ ); | ||
1299 | 475 | if ( sizeDiff != 0 ) | ||
1300 | 476 | return sizeDiff; | ||
1301 | 477 | |||
1302 | 478 | for ( ArrayIndex index =0; index < size_; ++index ) | ||
1303 | 479 | { | ||
1304 | 480 | int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( | ||
1305 | 481 | other.pages_[index/itemsPerPage][index%itemsPerPage] ); | ||
1306 | 482 | if ( diff != 0 ) | ||
1307 | 483 | return diff; | ||
1308 | 484 | } | ||
1309 | 485 | return 0; | ||
1310 | 486 | } | ||
1311 | 0 | 487 | ||
1312 | === added file 'plugin/json_server/json/json_internalmap.inl' | |||
1313 | --- plugin/json_server/json/json_internalmap.inl 1970-01-01 00:00:00 +0000 | |||
1314 | +++ plugin/json_server/json/json_internalmap.inl 2011-05-04 01:52:37 +0000 | |||
1315 | @@ -0,0 +1,645 @@ | |||
1316 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
1317 | 2 | * | ||
1318 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
1319 | 4 | * | ||
1320 | 5 | * Copyright (C) 2011 Stewart Smith | ||
1321 | 6 | * All rights reserved. | ||
1322 | 7 | * | ||
1323 | 8 | * Redistribution and use in source and binary forms, with or without | ||
1324 | 9 | * modification, are permitted provided that the following conditions are | ||
1325 | 10 | * met: | ||
1326 | 11 | * | ||
1327 | 12 | * * Redistributions of source code must retain the above copyright | ||
1328 | 13 | * notice, this list of conditions and the following disclaimer. | ||
1329 | 14 | * | ||
1330 | 15 | * * Redistributions in binary form must reproduce the above | ||
1331 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
1332 | 17 | * in the documentation and/or other materials provided with the | ||
1333 | 18 | * distribution. | ||
1334 | 19 | * | ||
1335 | 20 | * * The names of its contributors may not be used to endorse or | ||
1336 | 21 | * promote products derived from this software without specific prior | ||
1337 | 22 | * written permission. | ||
1338 | 23 | * | ||
1339 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
1340 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
1341 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
1342 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
1343 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
1344 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
1345 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
1346 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
1347 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
1348 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
1349 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
1350 | 35 | * | ||
1351 | 36 | */ | ||
1352 | 37 | |||
1353 | 38 | #pragma once | ||
1354 | 39 | // included by json_value.cpp | ||
1355 | 40 | // everything is within Json namespace | ||
1356 | 41 | |||
1357 | 42 | // ////////////////////////////////////////////////////////////////// | ||
1358 | 43 | // ////////////////////////////////////////////////////////////////// | ||
1359 | 44 | // ////////////////////////////////////////////////////////////////// | ||
1360 | 45 | // class ValueInternalMap | ||
1361 | 46 | // ////////////////////////////////////////////////////////////////// | ||
1362 | 47 | // ////////////////////////////////////////////////////////////////// | ||
1363 | 48 | // ////////////////////////////////////////////////////////////////// | ||
1364 | 49 | |||
1365 | 50 | /** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) ); | ||
1366 | 51 | * This optimization is used by the fast allocator. | ||
1367 | 52 | */ | ||
1368 | 53 | ValueInternalLink::ValueInternalLink() | ||
1369 | 54 | : previous_( 0 ) | ||
1370 | 55 | , next_( 0 ) | ||
1371 | 56 | { | ||
1372 | 57 | } | ||
1373 | 58 | |||
1374 | 59 | ValueInternalLink::~ValueInternalLink() | ||
1375 | 60 | { | ||
1376 | 61 | for ( int index =0; index < itemPerLink; ++index ) | ||
1377 | 62 | { | ||
1378 | 63 | if ( !items_[index].isItemAvailable() ) | ||
1379 | 64 | { | ||
1380 | 65 | if ( !items_[index].isMemberNameStatic() ) | ||
1381 | 66 | free( keys_[index] ); | ||
1382 | 67 | } | ||
1383 | 68 | else | ||
1384 | 69 | break; | ||
1385 | 70 | } | ||
1386 | 71 | } | ||
1387 | 72 | |||
1388 | 73 | |||
1389 | 74 | |||
1390 | 75 | ValueMapAllocator::~ValueMapAllocator() | ||
1391 | 76 | { | ||
1392 | 77 | } | ||
1393 | 78 | |||
1394 | 79 | #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR | ||
1395 | 80 | class DefaultValueMapAllocator : public ValueMapAllocator | ||
1396 | 81 | { | ||
1397 | 82 | public: // overridden from ValueMapAllocator | ||
1398 | 83 | virtual ValueInternalMap *newMap() | ||
1399 | 84 | { | ||
1400 | 85 | return new ValueInternalMap(); | ||
1401 | 86 | } | ||
1402 | 87 | |||
1403 | 88 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) | ||
1404 | 89 | { | ||
1405 | 90 | return new ValueInternalMap( other ); | ||
1406 | 91 | } | ||
1407 | 92 | |||
1408 | 93 | virtual void destructMap( ValueInternalMap *map ) | ||
1409 | 94 | { | ||
1410 | 95 | delete map; | ||
1411 | 96 | } | ||
1412 | 97 | |||
1413 | 98 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) | ||
1414 | 99 | { | ||
1415 | 100 | return new ValueInternalLink[size]; | ||
1416 | 101 | } | ||
1417 | 102 | |||
1418 | 103 | virtual void releaseMapBuckets( ValueInternalLink *links ) | ||
1419 | 104 | { | ||
1420 | 105 | delete [] links; | ||
1421 | 106 | } | ||
1422 | 107 | |||
1423 | 108 | virtual ValueInternalLink *allocateMapLink() | ||
1424 | 109 | { | ||
1425 | 110 | return new ValueInternalLink(); | ||
1426 | 111 | } | ||
1427 | 112 | |||
1428 | 113 | virtual void releaseMapLink( ValueInternalLink *link ) | ||
1429 | 114 | { | ||
1430 | 115 | delete link; | ||
1431 | 116 | } | ||
1432 | 117 | }; | ||
1433 | 118 | #else | ||
1434 | 119 | /// @todo make this thread-safe (lock when accessign batch allocator) | ||
1435 | 120 | class DefaultValueMapAllocator : public ValueMapAllocator | ||
1436 | 121 | { | ||
1437 | 122 | public: // overridden from ValueMapAllocator | ||
1438 | 123 | virtual ValueInternalMap *newMap() | ||
1439 | 124 | { | ||
1440 | 125 | ValueInternalMap *map = mapsAllocator_.allocate(); | ||
1441 | 126 | new (map) ValueInternalMap(); // placement new | ||
1442 | 127 | return map; | ||
1443 | 128 | } | ||
1444 | 129 | |||
1445 | 130 | virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) | ||
1446 | 131 | { | ||
1447 | 132 | ValueInternalMap *map = mapsAllocator_.allocate(); | ||
1448 | 133 | new (map) ValueInternalMap( other ); // placement new | ||
1449 | 134 | return map; | ||
1450 | 135 | } | ||
1451 | 136 | |||
1452 | 137 | virtual void destructMap( ValueInternalMap *map ) | ||
1453 | 138 | { | ||
1454 | 139 | if ( map ) | ||
1455 | 140 | { | ||
1456 | 141 | map->~ValueInternalMap(); | ||
1457 | 142 | mapsAllocator_.release( map ); | ||
1458 | 143 | } | ||
1459 | 144 | } | ||
1460 | 145 | |||
1461 | 146 | virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) | ||
1462 | 147 | { | ||
1463 | 148 | return new ValueInternalLink[size]; | ||
1464 | 149 | } | ||
1465 | 150 | |||
1466 | 151 | virtual void releaseMapBuckets( ValueInternalLink *links ) | ||
1467 | 152 | { | ||
1468 | 153 | delete [] links; | ||
1469 | 154 | } | ||
1470 | 155 | |||
1471 | 156 | virtual ValueInternalLink *allocateMapLink() | ||
1472 | 157 | { | ||
1473 | 158 | ValueInternalLink *link = linksAllocator_.allocate(); | ||
1474 | 159 | memset( link, 0, sizeof(ValueInternalLink) ); | ||
1475 | 160 | return link; | ||
1476 | 161 | } | ||
1477 | 162 | |||
1478 | 163 | virtual void releaseMapLink( ValueInternalLink *link ) | ||
1479 | 164 | { | ||
1480 | 165 | link->~ValueInternalLink(); | ||
1481 | 166 | linksAllocator_.release( link ); | ||
1482 | 167 | } | ||
1483 | 168 | private: | ||
1484 | 169 | BatchAllocator<ValueInternalMap,1> mapsAllocator_; | ||
1485 | 170 | BatchAllocator<ValueInternalLink,1> linksAllocator_; | ||
1486 | 171 | }; | ||
1487 | 172 | #endif | ||
1488 | 173 | |||
1489 | 174 | static ValueMapAllocator *&mapAllocator() | ||
1490 | 175 | { | ||
1491 | 176 | static DefaultValueMapAllocator defaultAllocator; | ||
1492 | 177 | static ValueMapAllocator *mapAllocator = &defaultAllocator; | ||
1493 | 178 | return mapAllocator; | ||
1494 | 179 | } | ||
1495 | 180 | |||
1496 | 181 | static struct DummyMapAllocatorInitializer { | ||
1497 | 182 | DummyMapAllocatorInitializer() | ||
1498 | 183 | { | ||
1499 | 184 | mapAllocator(); // ensure mapAllocator() statics are initialized before main(). | ||
1500 | 185 | } | ||
1501 | 186 | } dummyMapAllocatorInitializer; | ||
1502 | 187 | |||
1503 | 188 | |||
1504 | 189 | |||
1505 | 190 | // h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32. | ||
1506 | 191 | |||
1507 | 192 | /* | ||
1508 | 193 | use linked list hash map. | ||
1509 | 194 | buckets array is a container. | ||
1510 | 195 | linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124) | ||
1511 | 196 | value have extra state: valid, available, deleted | ||
1512 | 197 | */ | ||
1513 | 198 | |||
1514 | 199 | |||
1515 | 200 | ValueInternalMap::ValueInternalMap() | ||
1516 | 201 | : buckets_( 0 ) | ||
1517 | 202 | , tailLink_( 0 ) | ||
1518 | 203 | , bucketsSize_( 0 ) | ||
1519 | 204 | , itemCount_( 0 ) | ||
1520 | 205 | { | ||
1521 | 206 | } | ||
1522 | 207 | |||
1523 | 208 | |||
1524 | 209 | ValueInternalMap::ValueInternalMap( const ValueInternalMap &other ) | ||
1525 | 210 | : buckets_( 0 ) | ||
1526 | 211 | , tailLink_( 0 ) | ||
1527 | 212 | , bucketsSize_( 0 ) | ||
1528 | 213 | , itemCount_( 0 ) | ||
1529 | 214 | { | ||
1530 | 215 | reserve( other.itemCount_ ); | ||
1531 | 216 | IteratorState it; | ||
1532 | 217 | IteratorState itEnd; | ||
1533 | 218 | other.makeBeginIterator( it ); | ||
1534 | 219 | other.makeEndIterator( itEnd ); | ||
1535 | 220 | for ( ; !equals(it,itEnd); increment(it) ) | ||
1536 | 221 | { | ||
1537 | 222 | bool isStatic; | ||
1538 | 223 | const char *memberName = key( it, isStatic ); | ||
1539 | 224 | const Value &aValue = value( it ); | ||
1540 | 225 | resolveReference(memberName, isStatic) = aValue; | ||
1541 | 226 | } | ||
1542 | 227 | } | ||
1543 | 228 | |||
1544 | 229 | |||
1545 | 230 | ValueInternalMap & | ||
1546 | 231 | ValueInternalMap::operator =( const ValueInternalMap &other ) | ||
1547 | 232 | { | ||
1548 | 233 | ValueInternalMap dummy( other ); | ||
1549 | 234 | swap( dummy ); | ||
1550 | 235 | return *this; | ||
1551 | 236 | } | ||
1552 | 237 | |||
1553 | 238 | |||
1554 | 239 | ValueInternalMap::~ValueInternalMap() | ||
1555 | 240 | { | ||
1556 | 241 | if ( buckets_ ) | ||
1557 | 242 | { | ||
1558 | 243 | for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex ) | ||
1559 | 244 | { | ||
1560 | 245 | ValueInternalLink *link = buckets_[bucketIndex].next_; | ||
1561 | 246 | while ( link ) | ||
1562 | 247 | { | ||
1563 | 248 | ValueInternalLink *linkToRelease = link; | ||
1564 | 249 | link = link->next_; | ||
1565 | 250 | mapAllocator()->releaseMapLink( linkToRelease ); | ||
1566 | 251 | } | ||
1567 | 252 | } | ||
1568 | 253 | mapAllocator()->releaseMapBuckets( buckets_ ); | ||
1569 | 254 | } | ||
1570 | 255 | } | ||
1571 | 256 | |||
1572 | 257 | |||
1573 | 258 | void | ||
1574 | 259 | ValueInternalMap::swap( ValueInternalMap &other ) | ||
1575 | 260 | { | ||
1576 | 261 | ValueInternalLink *tempBuckets = buckets_; | ||
1577 | 262 | buckets_ = other.buckets_; | ||
1578 | 263 | other.buckets_ = tempBuckets; | ||
1579 | 264 | ValueInternalLink *tempTailLink = tailLink_; | ||
1580 | 265 | tailLink_ = other.tailLink_; | ||
1581 | 266 | other.tailLink_ = tempTailLink; | ||
1582 | 267 | BucketIndex tempBucketsSize = bucketsSize_; | ||
1583 | 268 | bucketsSize_ = other.bucketsSize_; | ||
1584 | 269 | other.bucketsSize_ = tempBucketsSize; | ||
1585 | 270 | BucketIndex tempItemCount = itemCount_; | ||
1586 | 271 | itemCount_ = other.itemCount_; | ||
1587 | 272 | other.itemCount_ = tempItemCount; | ||
1588 | 273 | } | ||
1589 | 274 | |||
1590 | 275 | |||
1591 | 276 | void | ||
1592 | 277 | ValueInternalMap::clear() | ||
1593 | 278 | { | ||
1594 | 279 | ValueInternalMap dummy; | ||
1595 | 280 | swap( dummy ); | ||
1596 | 281 | } | ||
1597 | 282 | |||
1598 | 283 | |||
1599 | 284 | ValueInternalMap::BucketIndex | ||
1600 | 285 | ValueInternalMap::size() const | ||
1601 | 286 | { | ||
1602 | 287 | return itemCount_; | ||
1603 | 288 | } | ||
1604 | 289 | |||
1605 | 290 | bool | ||
1606 | 291 | ValueInternalMap::reserveDelta( BucketIndex growth ) | ||
1607 | 292 | { | ||
1608 | 293 | return reserve( itemCount_ + growth ); | ||
1609 | 294 | } | ||
1610 | 295 | |||
1611 | 296 | bool | ||
1612 | 297 | ValueInternalMap::reserve( BucketIndex newItemCount ) | ||
1613 | 298 | { | ||
1614 | 299 | if ( !buckets_ && newItemCount > 0 ) | ||
1615 | 300 | { | ||
1616 | 301 | buckets_ = mapAllocator()->allocateMapBuckets( 1 ); | ||
1617 | 302 | bucketsSize_ = 1; | ||
1618 | 303 | tailLink_ = &buckets_[0]; | ||
1619 | 304 | } | ||
1620 | 305 | // BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink; | ||
1621 | 306 | return true; | ||
1622 | 307 | } | ||
1623 | 308 | |||
1624 | 309 | |||
1625 | 310 | const Value * | ||
1626 | 311 | ValueInternalMap::find( const char *key ) const | ||
1627 | 312 | { | ||
1628 | 313 | if ( !bucketsSize_ ) | ||
1629 | 314 | return 0; | ||
1630 | 315 | HashKey hashedKey = hash( key ); | ||
1631 | 316 | BucketIndex bucketIndex = hashedKey % bucketsSize_; | ||
1632 | 317 | for ( const ValueInternalLink *current = &buckets_[bucketIndex]; | ||
1633 | 318 | current != 0; | ||
1634 | 319 | current = current->next_ ) | ||
1635 | 320 | { | ||
1636 | 321 | for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index ) | ||
1637 | 322 | { | ||
1638 | 323 | if ( current->items_[index].isItemAvailable() ) | ||
1639 | 324 | return 0; | ||
1640 | 325 | if ( strcmp( key, current->keys_[index] ) == 0 ) | ||
1641 | 326 | return ¤t->items_[index]; | ||
1642 | 327 | } | ||
1643 | 328 | } | ||
1644 | 329 | return 0; | ||
1645 | 330 | } | ||
1646 | 331 | |||
1647 | 332 | |||
1648 | 333 | Value * | ||
1649 | 334 | ValueInternalMap::find( const char *key ) | ||
1650 | 335 | { | ||
1651 | 336 | const ValueInternalMap *constThis = this; | ||
1652 | 337 | return const_cast<Value *>( constThis->find( key ) ); | ||
1653 | 338 | } | ||
1654 | 339 | |||
1655 | 340 | |||
1656 | 341 | Value & | ||
1657 | 342 | ValueInternalMap::resolveReference( const char *key, | ||
1658 | 343 | bool isStatic ) | ||
1659 | 344 | { | ||
1660 | 345 | HashKey hashedKey = hash( key ); | ||
1661 | 346 | if ( bucketsSize_ ) | ||
1662 | 347 | { | ||
1663 | 348 | BucketIndex bucketIndex = hashedKey % bucketsSize_; | ||
1664 | 349 | ValueInternalLink **previous = 0; | ||
1665 | 350 | BucketIndex index; | ||
1666 | 351 | for ( ValueInternalLink *current = &buckets_[bucketIndex]; | ||
1667 | 352 | current != 0; | ||
1668 | 353 | previous = ¤t->next_, current = current->next_ ) | ||
1669 | 354 | { | ||
1670 | 355 | for ( index=0; index < ValueInternalLink::itemPerLink; ++index ) | ||
1671 | 356 | { | ||
1672 | 357 | if ( current->items_[index].isItemAvailable() ) | ||
1673 | 358 | return setNewItem( key, isStatic, current, index ); | ||
1674 | 359 | if ( strcmp( key, current->keys_[index] ) == 0 ) | ||
1675 | 360 | return current->items_[index]; | ||
1676 | 361 | } | ||
1677 | 362 | } | ||
1678 | 363 | } | ||
1679 | 364 | |||
1680 | 365 | reserveDelta( 1 ); | ||
1681 | 366 | return unsafeAdd( key, isStatic, hashedKey ); | ||
1682 | 367 | } | ||
1683 | 368 | |||
1684 | 369 | |||
1685 | 370 | void | ||
1686 | 371 | ValueInternalMap::remove( const char *key ) | ||
1687 | 372 | { | ||
1688 | 373 | HashKey hashedKey = hash( key ); | ||
1689 | 374 | if ( !bucketsSize_ ) | ||
1690 | 375 | return; | ||
1691 | 376 | BucketIndex bucketIndex = hashedKey % bucketsSize_; | ||
1692 | 377 | for ( ValueInternalLink *link = &buckets_[bucketIndex]; | ||
1693 | 378 | link != 0; | ||
1694 | 379 | link = link->next_ ) | ||
1695 | 380 | { | ||
1696 | 381 | BucketIndex index; | ||
1697 | 382 | for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) | ||
1698 | 383 | { | ||
1699 | 384 | if ( link->items_[index].isItemAvailable() ) | ||
1700 | 385 | return; | ||
1701 | 386 | if ( strcmp( key, link->keys_[index] ) == 0 ) | ||
1702 | 387 | { | ||
1703 | 388 | doActualRemove( link, index, bucketIndex ); | ||
1704 | 389 | return; | ||
1705 | 390 | } | ||
1706 | 391 | } | ||
1707 | 392 | } | ||
1708 | 393 | } | ||
1709 | 394 | |||
1710 | 395 | void | ||
1711 | 396 | ValueInternalMap::doActualRemove( ValueInternalLink *link, | ||
1712 | 397 | BucketIndex index, | ||
1713 | 398 | BucketIndex bucketIndex ) | ||
1714 | 399 | { | ||
1715 | 400 | // find last item of the bucket and swap it with the 'removed' one. | ||
1716 | 401 | // set removed items flags to 'available'. | ||
1717 | 402 | // if last page only contains 'available' items, then desallocate it (it's empty) | ||
1718 | 403 | ValueInternalLink *&lastLink = getLastLinkInBucket( index ); | ||
1719 | 404 | BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1 | ||
1720 | 405 | for ( ; | ||
1721 | 406 | lastItemIndex < ValueInternalLink::itemPerLink; | ||
1722 | 407 | ++lastItemIndex ) // may be optimized with dicotomic search | ||
1723 | 408 | { | ||
1724 | 409 | if ( lastLink->items_[lastItemIndex].isItemAvailable() ) | ||
1725 | 410 | break; | ||
1726 | 411 | } | ||
1727 | 412 | |||
1728 | 413 | BucketIndex lastUsedIndex = lastItemIndex - 1; | ||
1729 | 414 | Value *valueToDelete = &link->items_[index]; | ||
1730 | 415 | Value *valueToPreserve = &lastLink->items_[lastUsedIndex]; | ||
1731 | 416 | if ( valueToDelete != valueToPreserve ) | ||
1732 | 417 | valueToDelete->swap( *valueToPreserve ); | ||
1733 | 418 | if ( lastUsedIndex == 0 ) // page is now empty | ||
1734 | 419 | { // remove it from bucket linked list and delete it. | ||
1735 | 420 | ValueInternalLink *linkPreviousToLast = lastLink->previous_; | ||
1736 | 421 | if ( linkPreviousToLast != 0 ) // can not deleted bucket link. | ||
1737 | 422 | { | ||
1738 | 423 | mapAllocator()->releaseMapLink( lastLink ); | ||
1739 | 424 | linkPreviousToLast->next_ = 0; | ||
1740 | 425 | lastLink = linkPreviousToLast; | ||
1741 | 426 | } | ||
1742 | 427 | } | ||
1743 | 428 | else | ||
1744 | 429 | { | ||
1745 | 430 | Value dummy; | ||
1746 | 431 | valueToPreserve->swap( dummy ); // restore deleted to default Value. | ||
1747 | 432 | valueToPreserve->setItemUsed( false ); | ||
1748 | 433 | } | ||
1749 | 434 | --itemCount_; | ||
1750 | 435 | } | ||
1751 | 436 | |||
1752 | 437 | |||
1753 | 438 | ValueInternalLink *& | ||
1754 | 439 | ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex ) | ||
1755 | 440 | { | ||
1756 | 441 | if ( bucketIndex == bucketsSize_ - 1 ) | ||
1757 | 442 | return tailLink_; | ||
1758 | 443 | ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_; | ||
1759 | 444 | if ( !previous ) | ||
1760 | 445 | previous = &buckets_[bucketIndex]; | ||
1761 | 446 | return previous; | ||
1762 | 447 | } | ||
1763 | 448 | |||
1764 | 449 | |||
1765 | 450 | Value & | ||
1766 | 451 | ValueInternalMap::setNewItem( const char *key, | ||
1767 | 452 | bool isStatic, | ||
1768 | 453 | ValueInternalLink *link, | ||
1769 | 454 | BucketIndex index ) | ||
1770 | 455 | { | ||
1771 | 456 | char *duplicatedKey = valueAllocator()->makeMemberName( key ); | ||
1772 | 457 | ++itemCount_; | ||
1773 | 458 | link->keys_[index] = duplicatedKey; | ||
1774 | 459 | link->items_[index].setItemUsed(); | ||
1775 | 460 | link->items_[index].setMemberNameIsStatic( isStatic ); | ||
1776 | 461 | return link->items_[index]; // items already default constructed. | ||
1777 | 462 | } | ||
1778 | 463 | |||
1779 | 464 | |||
1780 | 465 | Value & | ||
1781 | 466 | ValueInternalMap::unsafeAdd( const char *key, | ||
1782 | 467 | bool isStatic, | ||
1783 | 468 | HashKey hashedKey ) | ||
1784 | 469 | { | ||
1785 | 470 | JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." ); | ||
1786 | 471 | BucketIndex bucketIndex = hashedKey % bucketsSize_; | ||
1787 | 472 | ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex ); | ||
1788 | 473 | ValueInternalLink *link = previousLink; | ||
1789 | 474 | BucketIndex index; | ||
1790 | 475 | for ( index =0; index < ValueInternalLink::itemPerLink; ++index ) | ||
1791 | 476 | { | ||
1792 | 477 | if ( link->items_[index].isItemAvailable() ) | ||
1793 | 478 | break; | ||
1794 | 479 | } | ||
1795 | 480 | if ( index == ValueInternalLink::itemPerLink ) // need to add a new page | ||
1796 | 481 | { | ||
1797 | 482 | ValueInternalLink *newLink = mapAllocator()->allocateMapLink(); | ||
1798 | 483 | index = 0; | ||
1799 | 484 | link->next_ = newLink; | ||
1800 | 485 | previousLink = newLink; | ||
1801 | 486 | link = newLink; | ||
1802 | 487 | } | ||
1803 | 488 | return setNewItem( key, isStatic, link, index ); | ||
1804 | 489 | } | ||
1805 | 490 | |||
1806 | 491 | |||
1807 | 492 | ValueInternalMap::HashKey | ||
1808 | 493 | ValueInternalMap::hash( const char *key ) const | ||
1809 | 494 | { | ||
1810 | 495 | HashKey hash = 0; | ||
1811 | 496 | while ( *key ) | ||
1812 | 497 | hash += *key++ * 37; | ||
1813 | 498 | return hash; | ||
1814 | 499 | } | ||
1815 | 500 | |||
1816 | 501 | |||
1817 | 502 | int | ||
1818 | 503 | ValueInternalMap::compare( const ValueInternalMap &other ) const | ||
1819 | 504 | { | ||
1820 | 505 | int sizeDiff( itemCount_ - other.itemCount_ ); | ||
1821 | 506 | if ( sizeDiff != 0 ) | ||
1822 | 507 | return sizeDiff; | ||
1823 | 508 | // Strict order guaranty is required. Compare all keys FIRST, then compare values. | ||
1824 | 509 | IteratorState it; | ||
1825 | 510 | IteratorState itEnd; | ||
1826 | 511 | makeBeginIterator( it ); | ||
1827 | 512 | makeEndIterator( itEnd ); | ||
1828 | 513 | for ( ; !equals(it,itEnd); increment(it) ) | ||
1829 | 514 | { | ||
1830 | 515 | if ( !other.find( key( it ) ) ) | ||
1831 | 516 | return 1; | ||
1832 | 517 | } | ||
1833 | 518 | |||
1834 | 519 | // All keys are equals, let's compare values | ||
1835 | 520 | makeBeginIterator( it ); | ||
1836 | 521 | for ( ; !equals(it,itEnd); increment(it) ) | ||
1837 | 522 | { | ||
1838 | 523 | const Value *otherValue = other.find( key( it ) ); | ||
1839 | 524 | int valueDiff = value(it).compare( *otherValue ); | ||
1840 | 525 | if ( valueDiff != 0 ) | ||
1841 | 526 | return valueDiff; | ||
1842 | 527 | } | ||
1843 | 528 | return 0; | ||
1844 | 529 | } | ||
1845 | 530 | |||
1846 | 531 | |||
1847 | 532 | void | ||
1848 | 533 | ValueInternalMap::makeBeginIterator( IteratorState &it ) const | ||
1849 | 534 | { | ||
1850 | 535 | it.map_ = const_cast<ValueInternalMap *>( this ); | ||
1851 | 536 | it.bucketIndex_ = 0; | ||
1852 | 537 | it.itemIndex_ = 0; | ||
1853 | 538 | it.link_ = buckets_; | ||
1854 | 539 | } | ||
1855 | 540 | |||
1856 | 541 | |||
1857 | 542 | void | ||
1858 | 543 | ValueInternalMap::makeEndIterator( IteratorState &it ) const | ||
1859 | 544 | { | ||
1860 | 545 | it.map_ = const_cast<ValueInternalMap *>( this ); | ||
1861 | 546 | it.bucketIndex_ = bucketsSize_; | ||
1862 | 547 | it.itemIndex_ = 0; | ||
1863 | 548 | it.link_ = 0; | ||
1864 | 549 | } | ||
1865 | 550 | |||
1866 | 551 | |||
1867 | 552 | bool | ||
1868 | 553 | ValueInternalMap::equals( const IteratorState &x, const IteratorState &other ) | ||
1869 | 554 | { | ||
1870 | 555 | return x.map_ == other.map_ | ||
1871 | 556 | && x.bucketIndex_ == other.bucketIndex_ | ||
1872 | 557 | && x.link_ == other.link_ | ||
1873 | 558 | && x.itemIndex_ == other.itemIndex_; | ||
1874 | 559 | } | ||
1875 | 560 | |||
1876 | 561 | |||
1877 | 562 | void | ||
1878 | 563 | ValueInternalMap::incrementBucket( IteratorState &iterator ) | ||
1879 | 564 | { | ||
1880 | 565 | ++iterator.bucketIndex_; | ||
1881 | 566 | JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_, | ||
1882 | 567 | "ValueInternalMap::increment(): attempting to iterate beyond end." ); | ||
1883 | 568 | if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ ) | ||
1884 | 569 | iterator.link_ = 0; | ||
1885 | 570 | else | ||
1886 | 571 | iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]); | ||
1887 | 572 | iterator.itemIndex_ = 0; | ||
1888 | 573 | } | ||
1889 | 574 | |||
1890 | 575 | |||
1891 | 576 | void | ||
1892 | 577 | ValueInternalMap::increment( IteratorState &iterator ) | ||
1893 | 578 | { | ||
1894 | 579 | JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." ); | ||
1895 | 580 | ++iterator.itemIndex_; | ||
1896 | 581 | if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink ) | ||
1897 | 582 | { | ||
1898 | 583 | JSON_ASSERT_MESSAGE( iterator.link_ != 0, | ||
1899 | 584 | "ValueInternalMap::increment(): attempting to iterate beyond end." ); | ||
1900 | 585 | iterator.link_ = iterator.link_->next_; | ||
1901 | 586 | if ( iterator.link_ == 0 ) | ||
1902 | 587 | incrementBucket( iterator ); | ||
1903 | 588 | } | ||
1904 | 589 | else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() ) | ||
1905 | 590 | { | ||
1906 | 591 | incrementBucket( iterator ); | ||
1907 | 592 | } | ||
1908 | 593 | } | ||
1909 | 594 | |||
1910 | 595 | |||
1911 | 596 | void | ||
1912 | 597 | ValueInternalMap::decrement( IteratorState &iterator ) | ||
1913 | 598 | { | ||
1914 | 599 | if ( iterator.itemIndex_ == 0 ) | ||
1915 | 600 | { | ||
1916 | 601 | JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." ); | ||
1917 | 602 | if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] ) | ||
1918 | 603 | { | ||
1919 | 604 | JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." ); | ||
1920 | 605 | --(iterator.bucketIndex_); | ||
1921 | 606 | } | ||
1922 | 607 | iterator.link_ = iterator.link_->previous_; | ||
1923 | 608 | iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1; | ||
1924 | 609 | } | ||
1925 | 610 | } | ||
1926 | 611 | |||
1927 | 612 | |||
1928 | 613 | const char * | ||
1929 | 614 | ValueInternalMap::key( const IteratorState &iterator ) | ||
1930 | 615 | { | ||
1931 | 616 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); | ||
1932 | 617 | return iterator.link_->keys_[iterator.itemIndex_]; | ||
1933 | 618 | } | ||
1934 | 619 | |||
1935 | 620 | const char * | ||
1936 | 621 | ValueInternalMap::key( const IteratorState &iterator, bool &isStatic ) | ||
1937 | 622 | { | ||
1938 | 623 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); | ||
1939 | 624 | isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic(); | ||
1940 | 625 | return iterator.link_->keys_[iterator.itemIndex_]; | ||
1941 | 626 | } | ||
1942 | 627 | |||
1943 | 628 | |||
1944 | 629 | Value & | ||
1945 | 630 | ValueInternalMap::value( const IteratorState &iterator ) | ||
1946 | 631 | { | ||
1947 | 632 | JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." ); | ||
1948 | 633 | return iterator.link_->items_[iterator.itemIndex_]; | ||
1949 | 634 | } | ||
1950 | 635 | |||
1951 | 636 | |||
1952 | 637 | int | ||
1953 | 638 | ValueInternalMap::distance( const IteratorState &x, const IteratorState &y ) | ||
1954 | 639 | { | ||
1955 | 640 | int offset = 0; | ||
1956 | 641 | IteratorState it = x; | ||
1957 | 642 | while ( !equals( it, y ) ) | ||
1958 | 643 | increment( it ); | ||
1959 | 644 | return offset; | ||
1960 | 645 | } | ||
1961 | 0 | 646 | ||
1962 | === added file 'plugin/json_server/json/json_reader.cpp' | |||
1963 | --- plugin/json_server/json/json_reader.cpp 1970-01-01 00:00:00 +0000 | |||
1964 | +++ plugin/json_server/json/json_reader.cpp 2011-05-04 01:52:37 +0000 | |||
1965 | @@ -0,0 +1,921 @@ | |||
1966 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
1967 | 2 | * | ||
1968 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
1969 | 4 | * | ||
1970 | 5 | * Copyright (C) 2011 Stewart Smith | ||
1971 | 6 | * All rights reserved. | ||
1972 | 7 | * | ||
1973 | 8 | * Redistribution and use in source and binary forms, with or without | ||
1974 | 9 | * modification, are permitted provided that the following conditions are | ||
1975 | 10 | * met: | ||
1976 | 11 | * | ||
1977 | 12 | * * Redistributions of source code must retain the above copyright | ||
1978 | 13 | * notice, this list of conditions and the following disclaimer. | ||
1979 | 14 | * | ||
1980 | 15 | * * Redistributions in binary form must reproduce the above | ||
1981 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
1982 | 17 | * in the documentation and/or other materials provided with the | ||
1983 | 18 | * distribution. | ||
1984 | 19 | * | ||
1985 | 20 | * * The names of its contributors may not be used to endorse or | ||
1986 | 21 | * promote products derived from this software without specific prior | ||
1987 | 22 | * written permission. | ||
1988 | 23 | * | ||
1989 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
1990 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
1991 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
1992 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
1993 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
1994 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
1995 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
1996 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
1997 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
1998 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
1999 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
2000 | 35 | * | ||
2001 | 36 | */ | ||
2002 | 37 | |||
2003 | 38 | #include <config.h> | ||
2004 | 39 | |||
2005 | 40 | #include <plugin/json_server/json/reader.h> | ||
2006 | 41 | #include <plugin/json_server/json/value.h> | ||
2007 | 42 | |||
2008 | 43 | #include <cassert> | ||
2009 | 44 | #include <cstdio> | ||
2010 | 45 | #include <cstring> | ||
2011 | 46 | #include <iostream> | ||
2012 | 47 | #include <stdexcept> | ||
2013 | 48 | #include <utility> | ||
2014 | 49 | |||
2015 | 50 | namespace Json { | ||
2016 | 51 | |||
2017 | 52 | // Implementation of class Features | ||
2018 | 53 | // //////////////////////////////// | ||
2019 | 54 | |||
2020 | 55 | Features::Features() | ||
2021 | 56 | : allowComments_( true ) | ||
2022 | 57 | , strictRoot_( false ) | ||
2023 | 58 | { | ||
2024 | 59 | } | ||
2025 | 60 | |||
2026 | 61 | |||
2027 | 62 | Features | ||
2028 | 63 | Features::all() | ||
2029 | 64 | { | ||
2030 | 65 | return Features(); | ||
2031 | 66 | } | ||
2032 | 67 | |||
2033 | 68 | |||
2034 | 69 | Features | ||
2035 | 70 | Features::strictMode() | ||
2036 | 71 | { | ||
2037 | 72 | Features features; | ||
2038 | 73 | features.allowComments_ = false; | ||
2039 | 74 | features.strictRoot_ = true; | ||
2040 | 75 | return features; | ||
2041 | 76 | } | ||
2042 | 77 | |||
2043 | 78 | // Implementation of class Reader | ||
2044 | 79 | // //////////////////////////////// | ||
2045 | 80 | |||
2046 | 81 | |||
2047 | 82 | static inline bool | ||
2048 | 83 | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) | ||
2049 | 84 | { | ||
2050 | 85 | return c == c1 || c == c2 || c == c3 || c == c4; | ||
2051 | 86 | } | ||
2052 | 87 | |||
2053 | 88 | static inline bool | ||
2054 | 89 | in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) | ||
2055 | 90 | { | ||
2056 | 91 | return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; | ||
2057 | 92 | } | ||
2058 | 93 | |||
2059 | 94 | |||
2060 | 95 | static bool | ||
2061 | 96 | containsNewLine( Reader::Location begin, | ||
2062 | 97 | Reader::Location end ) | ||
2063 | 98 | { | ||
2064 | 99 | for ( ;begin < end; ++begin ) | ||
2065 | 100 | if ( *begin == '\n' || *begin == '\r' ) | ||
2066 | 101 | return true; | ||
2067 | 102 | return false; | ||
2068 | 103 | } | ||
2069 | 104 | |||
2070 | 105 | static std::string codePointToUTF8(unsigned int cp) | ||
2071 | 106 | { | ||
2072 | 107 | std::string result; | ||
2073 | 108 | |||
2074 | 109 | // based on description from http://en.wikipedia.org/wiki/UTF-8 | ||
2075 | 110 | |||
2076 | 111 | if (cp <= 0x7f) | ||
2077 | 112 | { | ||
2078 | 113 | result.resize(1); | ||
2079 | 114 | result[0] = static_cast<char>(cp); | ||
2080 | 115 | } | ||
2081 | 116 | else if (cp <= 0x7FF) | ||
2082 | 117 | { | ||
2083 | 118 | result.resize(2); | ||
2084 | 119 | result[1] = static_cast<char>(0x80 | (0x3f & cp)); | ||
2085 | 120 | result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6))); | ||
2086 | 121 | } | ||
2087 | 122 | else if (cp <= 0xFFFF) | ||
2088 | 123 | { | ||
2089 | 124 | result.resize(3); | ||
2090 | 125 | result[2] = static_cast<char>(0x80 | (0x3f & cp)); | ||
2091 | 126 | result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6))); | ||
2092 | 127 | result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12))); | ||
2093 | 128 | } | ||
2094 | 129 | else if (cp <= 0x10FFFF) | ||
2095 | 130 | { | ||
2096 | 131 | result.resize(4); | ||
2097 | 132 | result[3] = static_cast<char>(0x80 | (0x3f & cp)); | ||
2098 | 133 | result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6))); | ||
2099 | 134 | result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12))); | ||
2100 | 135 | result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18))); | ||
2101 | 136 | } | ||
2102 | 137 | |||
2103 | 138 | return result; | ||
2104 | 139 | } | ||
2105 | 140 | |||
2106 | 141 | |||
2107 | 142 | // Class Reader | ||
2108 | 143 | // ////////////////////////////////////////////////////////////////// | ||
2109 | 144 | |||
2110 | 145 | Reader::Reader() | ||
2111 | 146 | : features_( Features::all() ) | ||
2112 | 147 | { | ||
2113 | 148 | } | ||
2114 | 149 | |||
2115 | 150 | |||
2116 | 151 | Reader::Reader( const Features &features ) | ||
2117 | 152 | : features_( features ) | ||
2118 | 153 | { | ||
2119 | 154 | } | ||
2120 | 155 | |||
2121 | 156 | |||
2122 | 157 | bool | ||
2123 | 158 | Reader::parse( const std::string &document, | ||
2124 | 159 | Value &root, | ||
2125 | 160 | bool collectComments ) | ||
2126 | 161 | { | ||
2127 | 162 | document_ = document; | ||
2128 | 163 | const char *begin = document_.c_str(); | ||
2129 | 164 | const char *end = begin + document_.length(); | ||
2130 | 165 | return parse( begin, end, root, collectComments ); | ||
2131 | 166 | } | ||
2132 | 167 | |||
2133 | 168 | |||
2134 | 169 | bool | ||
2135 | 170 | Reader::parse( std::istream& sin, | ||
2136 | 171 | Value &root, | ||
2137 | 172 | bool collectComments ) | ||
2138 | 173 | { | ||
2139 | 174 | //std::istream_iterator<char> begin(sin); | ||
2140 | 175 | //std::istream_iterator<char> end; | ||
2141 | 176 | // Those would allow streamed input from a file, if parse() were a | ||
2142 | 177 | // template function. | ||
2143 | 178 | |||
2144 | 179 | // Since std::string is reference-counted, this at least does not | ||
2145 | 180 | // create an extra copy. | ||
2146 | 181 | std::string doc; | ||
2147 | 182 | std::getline(sin, doc, (char)EOF); | ||
2148 | 183 | return parse( doc, root, collectComments ); | ||
2149 | 184 | } | ||
2150 | 185 | |||
2151 | 186 | bool | ||
2152 | 187 | Reader::parse( const char *beginDoc, const char *endDoc, | ||
2153 | 188 | Value &root, | ||
2154 | 189 | bool collectComments ) | ||
2155 | 190 | { | ||
2156 | 191 | if ( !features_.allowComments_ ) | ||
2157 | 192 | { | ||
2158 | 193 | collectComments = false; | ||
2159 | 194 | } | ||
2160 | 195 | |||
2161 | 196 | begin_ = beginDoc; | ||
2162 | 197 | end_ = endDoc; | ||
2163 | 198 | collectComments_ = collectComments; | ||
2164 | 199 | current_ = begin_; | ||
2165 | 200 | lastValueEnd_ = 0; | ||
2166 | 201 | lastValue_ = 0; | ||
2167 | 202 | commentsBefore_ = ""; | ||
2168 | 203 | errors_.clear(); | ||
2169 | 204 | while ( !nodes_.empty() ) | ||
2170 | 205 | nodes_.pop(); | ||
2171 | 206 | nodes_.push( &root ); | ||
2172 | 207 | |||
2173 | 208 | bool successful = readValue(); | ||
2174 | 209 | Token token; | ||
2175 | 210 | skipCommentTokens( token ); | ||
2176 | 211 | if ( collectComments_ && !commentsBefore_.empty() ) | ||
2177 | 212 | root.setComment( commentsBefore_, commentAfter ); | ||
2178 | 213 | if ( features_.strictRoot_ ) | ||
2179 | 214 | { | ||
2180 | 215 | if ( !root.isArray() && !root.isObject() ) | ||
2181 | 216 | { | ||
2182 | 217 | // Set error location to start of doc, ideally should be first token found in doc | ||
2183 | 218 | token.type_ = tokenError; | ||
2184 | 219 | token.start_ = beginDoc; | ||
2185 | 220 | token.end_ = endDoc; | ||
2186 | 221 | addError( "A valid JSON document must be either an array or an object value.", | ||
2187 | 222 | token ); | ||
2188 | 223 | return false; | ||
2189 | 224 | } | ||
2190 | 225 | } | ||
2191 | 226 | return successful; | ||
2192 | 227 | } | ||
2193 | 228 | |||
2194 | 229 | |||
2195 | 230 | bool | ||
2196 | 231 | Reader::readValue() | ||
2197 | 232 | { | ||
2198 | 233 | Token token; | ||
2199 | 234 | skipCommentTokens( token ); | ||
2200 | 235 | bool successful = true; | ||
2201 | 236 | |||
2202 | 237 | if ( collectComments_ && !commentsBefore_.empty() ) | ||
2203 | 238 | { | ||
2204 | 239 | currentValue().setComment( commentsBefore_, commentBefore ); | ||
2205 | 240 | commentsBefore_ = ""; | ||
2206 | 241 | } | ||
2207 | 242 | |||
2208 | 243 | |||
2209 | 244 | switch ( token.type_ ) | ||
2210 | 245 | { | ||
2211 | 246 | case tokenObjectBegin: | ||
2212 | 247 | successful = readObject( token ); | ||
2213 | 248 | break; | ||
2214 | 249 | case tokenArrayBegin: | ||
2215 | 250 | successful = readArray( token ); | ||
2216 | 251 | break; | ||
2217 | 252 | case tokenNumber: | ||
2218 | 253 | successful = decodeNumber( token ); | ||
2219 | 254 | break; | ||
2220 | 255 | case tokenString: | ||
2221 | 256 | successful = decodeString( token ); | ||
2222 | 257 | break; | ||
2223 | 258 | case tokenTrue: | ||
2224 | 259 | currentValue() = true; | ||
2225 | 260 | break; | ||
2226 | 261 | case tokenFalse: | ||
2227 | 262 | currentValue() = false; | ||
2228 | 263 | break; | ||
2229 | 264 | case tokenNull: | ||
2230 | 265 | currentValue() = Value(); | ||
2231 | 266 | break; | ||
2232 | 267 | default: | ||
2233 | 268 | return addError( "Syntax error: value, object or array expected.", token ); | ||
2234 | 269 | } | ||
2235 | 270 | |||
2236 | 271 | if ( collectComments_ ) | ||
2237 | 272 | { | ||
2238 | 273 | lastValueEnd_ = current_; | ||
2239 | 274 | lastValue_ = ¤tValue(); | ||
2240 | 275 | } | ||
2241 | 276 | |||
2242 | 277 | return successful; | ||
2243 | 278 | } | ||
2244 | 279 | |||
2245 | 280 | |||
2246 | 281 | void | ||
2247 | 282 | Reader::skipCommentTokens( Token &token ) | ||
2248 | 283 | { | ||
2249 | 284 | if ( features_.allowComments_ ) | ||
2250 | 285 | { | ||
2251 | 286 | do | ||
2252 | 287 | { | ||
2253 | 288 | readToken( token ); | ||
2254 | 289 | } | ||
2255 | 290 | while ( token.type_ == tokenComment ); | ||
2256 | 291 | } | ||
2257 | 292 | else | ||
2258 | 293 | { | ||
2259 | 294 | readToken( token ); | ||
2260 | 295 | } | ||
2261 | 296 | } | ||
2262 | 297 | |||
2263 | 298 | |||
2264 | 299 | bool | ||
2265 | 300 | Reader::expectToken( TokenType type, Token &token, const char *message ) | ||
2266 | 301 | { | ||
2267 | 302 | readToken( token ); | ||
2268 | 303 | if ( token.type_ != type ) | ||
2269 | 304 | return addError( message, token ); | ||
2270 | 305 | return true; | ||
2271 | 306 | } | ||
2272 | 307 | |||
2273 | 308 | |||
2274 | 309 | bool | ||
2275 | 310 | Reader::readToken( Token &token ) | ||
2276 | 311 | { | ||
2277 | 312 | skipSpaces(); | ||
2278 | 313 | token.start_ = current_; | ||
2279 | 314 | Char c = getNextChar(); | ||
2280 | 315 | bool ok = true; | ||
2281 | 316 | switch ( c ) | ||
2282 | 317 | { | ||
2283 | 318 | case '{': | ||
2284 | 319 | token.type_ = tokenObjectBegin; | ||
2285 | 320 | break; | ||
2286 | 321 | case '}': | ||
2287 | 322 | token.type_ = tokenObjectEnd; | ||
2288 | 323 | break; | ||
2289 | 324 | case '[': | ||
2290 | 325 | token.type_ = tokenArrayBegin; | ||
2291 | 326 | break; | ||
2292 | 327 | case ']': | ||
2293 | 328 | token.type_ = tokenArrayEnd; | ||
2294 | 329 | break; | ||
2295 | 330 | case '"': | ||
2296 | 331 | token.type_ = tokenString; | ||
2297 | 332 | ok = readString(); | ||
2298 | 333 | break; | ||
2299 | 334 | case '/': | ||
2300 | 335 | token.type_ = tokenComment; | ||
2301 | 336 | ok = readComment(); | ||
2302 | 337 | break; | ||
2303 | 338 | case '0': | ||
2304 | 339 | case '1': | ||
2305 | 340 | case '2': | ||
2306 | 341 | case '3': | ||
2307 | 342 | case '4': | ||
2308 | 343 | case '5': | ||
2309 | 344 | case '6': | ||
2310 | 345 | case '7': | ||
2311 | 346 | case '8': | ||
2312 | 347 | case '9': | ||
2313 | 348 | case '-': | ||
2314 | 349 | token.type_ = tokenNumber; | ||
2315 | 350 | readNumber(); | ||
2316 | 351 | break; | ||
2317 | 352 | case 't': | ||
2318 | 353 | token.type_ = tokenTrue; | ||
2319 | 354 | ok = match( "rue", 3 ); | ||
2320 | 355 | break; | ||
2321 | 356 | case 'f': | ||
2322 | 357 | token.type_ = tokenFalse; | ||
2323 | 358 | ok = match( "alse", 4 ); | ||
2324 | 359 | break; | ||
2325 | 360 | case 'n': | ||
2326 | 361 | token.type_ = tokenNull; | ||
2327 | 362 | ok = match( "ull", 3 ); | ||
2328 | 363 | break; | ||
2329 | 364 | case ',': | ||
2330 | 365 | token.type_ = tokenArraySeparator; | ||
2331 | 366 | break; | ||
2332 | 367 | case ':': | ||
2333 | 368 | token.type_ = tokenMemberSeparator; | ||
2334 | 369 | break; | ||
2335 | 370 | case 0: | ||
2336 | 371 | token.type_ = tokenEndOfStream; | ||
2337 | 372 | break; | ||
2338 | 373 | default: | ||
2339 | 374 | ok = false; | ||
2340 | 375 | break; | ||
2341 | 376 | } | ||
2342 | 377 | if ( !ok ) | ||
2343 | 378 | token.type_ = tokenError; | ||
2344 | 379 | token.end_ = current_; | ||
2345 | 380 | return true; | ||
2346 | 381 | } | ||
2347 | 382 | |||
2348 | 383 | |||
2349 | 384 | void | ||
2350 | 385 | Reader::skipSpaces() | ||
2351 | 386 | { | ||
2352 | 387 | while ( current_ != end_ ) | ||
2353 | 388 | { | ||
2354 | 389 | Char c = *current_; | ||
2355 | 390 | if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) | ||
2356 | 391 | ++current_; | ||
2357 | 392 | else | ||
2358 | 393 | break; | ||
2359 | 394 | } | ||
2360 | 395 | } | ||
2361 | 396 | |||
2362 | 397 | |||
2363 | 398 | bool | ||
2364 | 399 | Reader::match( Location pattern, | ||
2365 | 400 | int patternLength ) | ||
2366 | 401 | { | ||
2367 | 402 | if ( end_ - current_ < patternLength ) | ||
2368 | 403 | return false; | ||
2369 | 404 | int index = patternLength; | ||
2370 | 405 | while ( index-- ) | ||
2371 | 406 | if ( current_[index] != pattern[index] ) | ||
2372 | 407 | return false; | ||
2373 | 408 | current_ += patternLength; | ||
2374 | 409 | return true; | ||
2375 | 410 | } | ||
2376 | 411 | |||
2377 | 412 | |||
2378 | 413 | bool | ||
2379 | 414 | Reader::readComment() | ||
2380 | 415 | { | ||
2381 | 416 | Location commentBegin = current_ - 1; | ||
2382 | 417 | Char c = getNextChar(); | ||
2383 | 418 | bool successful = false; | ||
2384 | 419 | if ( c == '*' ) | ||
2385 | 420 | successful = readCStyleComment(); | ||
2386 | 421 | else if ( c == '/' ) | ||
2387 | 422 | successful = readCppStyleComment(); | ||
2388 | 423 | if ( !successful ) | ||
2389 | 424 | return false; | ||
2390 | 425 | |||
2391 | 426 | if ( collectComments_ ) | ||
2392 | 427 | { | ||
2393 | 428 | CommentPlacement placement = commentBefore; | ||
2394 | 429 | if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) | ||
2395 | 430 | { | ||
2396 | 431 | if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) | ||
2397 | 432 | placement = commentAfterOnSameLine; | ||
2398 | 433 | } | ||
2399 | 434 | |||
2400 | 435 | addComment( commentBegin, current_, placement ); | ||
2401 | 436 | } | ||
2402 | 437 | return true; | ||
2403 | 438 | } | ||
2404 | 439 | |||
2405 | 440 | |||
2406 | 441 | void | ||
2407 | 442 | Reader::addComment( Location begin, | ||
2408 | 443 | Location end, | ||
2409 | 444 | CommentPlacement placement ) | ||
2410 | 445 | { | ||
2411 | 446 | assert( collectComments_ ); | ||
2412 | 447 | if ( placement == commentAfterOnSameLine ) | ||
2413 | 448 | { | ||
2414 | 449 | assert( lastValue_ != 0 ); | ||
2415 | 450 | lastValue_->setComment( std::string( begin, end ), placement ); | ||
2416 | 451 | } | ||
2417 | 452 | else | ||
2418 | 453 | { | ||
2419 | 454 | if ( !commentsBefore_.empty() ) | ||
2420 | 455 | commentsBefore_ += "\n"; | ||
2421 | 456 | commentsBefore_ += std::string( begin, end ); | ||
2422 | 457 | } | ||
2423 | 458 | } | ||
2424 | 459 | |||
2425 | 460 | |||
2426 | 461 | bool | ||
2427 | 462 | Reader::readCStyleComment() | ||
2428 | 463 | { | ||
2429 | 464 | while ( current_ != end_ ) | ||
2430 | 465 | { | ||
2431 | 466 | Char c = getNextChar(); | ||
2432 | 467 | if ( c == '*' && *current_ == '/' ) | ||
2433 | 468 | break; | ||
2434 | 469 | } | ||
2435 | 470 | return getNextChar() == '/'; | ||
2436 | 471 | } | ||
2437 | 472 | |||
2438 | 473 | |||
2439 | 474 | bool | ||
2440 | 475 | Reader::readCppStyleComment() | ||
2441 | 476 | { | ||
2442 | 477 | while ( current_ != end_ ) | ||
2443 | 478 | { | ||
2444 | 479 | Char c = getNextChar(); | ||
2445 | 480 | if ( c == '\r' || c == '\n' ) | ||
2446 | 481 | break; | ||
2447 | 482 | } | ||
2448 | 483 | return true; | ||
2449 | 484 | } | ||
2450 | 485 | |||
2451 | 486 | |||
2452 | 487 | void | ||
2453 | 488 | Reader::readNumber() | ||
2454 | 489 | { | ||
2455 | 490 | while ( current_ != end_ ) | ||
2456 | 491 | { | ||
2457 | 492 | if ( !(*current_ >= '0' && *current_ <= '9') && | ||
2458 | 493 | !in( *current_, '.', 'e', 'E', '+', '-' ) ) | ||
2459 | 494 | break; | ||
2460 | 495 | ++current_; | ||
2461 | 496 | } | ||
2462 | 497 | } | ||
2463 | 498 | |||
2464 | 499 | bool | ||
2465 | 500 | Reader::readString() | ||
2466 | 501 | { | ||
2467 | 502 | Char c = 0; | ||
2468 | 503 | while ( current_ != end_ ) | ||
2469 | 504 | { | ||
2470 | 505 | c = getNextChar(); | ||
2471 | 506 | if ( c == '\\' ) | ||
2472 | 507 | getNextChar(); | ||
2473 | 508 | else if ( c == '"' ) | ||
2474 | 509 | break; | ||
2475 | 510 | } | ||
2476 | 511 | return c == '"'; | ||
2477 | 512 | } | ||
2478 | 513 | |||
2479 | 514 | |||
2480 | 515 | bool | ||
2481 | 516 | Reader::readObject( Token & ) | ||
2482 | 517 | { | ||
2483 | 518 | Token tokenName; | ||
2484 | 519 | std::string name; | ||
2485 | 520 | currentValue() = Value( objectValue ); | ||
2486 | 521 | while ( readToken( tokenName ) ) | ||
2487 | 522 | { | ||
2488 | 523 | bool initialTokenOk = true; | ||
2489 | 524 | while ( tokenName.type_ == tokenComment && initialTokenOk ) | ||
2490 | 525 | initialTokenOk = readToken( tokenName ); | ||
2491 | 526 | if ( !initialTokenOk ) | ||
2492 | 527 | break; | ||
2493 | 528 | if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object | ||
2494 | 529 | return true; | ||
2495 | 530 | if ( tokenName.type_ != tokenString ) | ||
2496 | 531 | break; | ||
2497 | 532 | |||
2498 | 533 | name = ""; | ||
2499 | 534 | if ( !decodeString( tokenName, name ) ) | ||
2500 | 535 | return recoverFromError( tokenObjectEnd ); | ||
2501 | 536 | |||
2502 | 537 | Token colon; | ||
2503 | 538 | if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) | ||
2504 | 539 | { | ||
2505 | 540 | return addErrorAndRecover( "Missing ':' after object member name", | ||
2506 | 541 | colon, | ||
2507 | 542 | tokenObjectEnd ); | ||
2508 | 543 | } | ||
2509 | 544 | Value &value = currentValue()[ name ]; | ||
2510 | 545 | nodes_.push( &value ); | ||
2511 | 546 | bool ok = readValue(); | ||
2512 | 547 | nodes_.pop(); | ||
2513 | 548 | if ( !ok ) // error already set | ||
2514 | 549 | return recoverFromError( tokenObjectEnd ); | ||
2515 | 550 | |||
2516 | 551 | Token comma; | ||
2517 | 552 | if ( !readToken( comma ) | ||
2518 | 553 | || ( comma.type_ != tokenObjectEnd && | ||
2519 | 554 | comma.type_ != tokenArraySeparator && | ||
2520 | 555 | comma.type_ != tokenComment ) ) | ||
2521 | 556 | { | ||
2522 | 557 | return addErrorAndRecover( "Missing ',' or '}' in object declaration", | ||
2523 | 558 | comma, | ||
2524 | 559 | tokenObjectEnd ); | ||
2525 | 560 | } | ||
2526 | 561 | bool finalizeTokenOk = true; | ||
2527 | 562 | while ( comma.type_ == tokenComment && | ||
2528 | 563 | finalizeTokenOk ) | ||
2529 | 564 | finalizeTokenOk = readToken( comma ); | ||
2530 | 565 | if ( comma.type_ == tokenObjectEnd ) | ||
2531 | 566 | return true; | ||
2532 | 567 | } | ||
2533 | 568 | return addErrorAndRecover( "Missing '}' or object member name", | ||
2534 | 569 | tokenName, | ||
2535 | 570 | tokenObjectEnd ); | ||
2536 | 571 | } | ||
2537 | 572 | |||
2538 | 573 | |||
2539 | 574 | bool | ||
2540 | 575 | Reader::readArray( Token & ) | ||
2541 | 576 | { | ||
2542 | 577 | currentValue() = Value( arrayValue ); | ||
2543 | 578 | skipSpaces(); | ||
2544 | 579 | if ( *current_ == ']' ) // empty array | ||
2545 | 580 | { | ||
2546 | 581 | Token endArray; | ||
2547 | 582 | readToken( endArray ); | ||
2548 | 583 | return true; | ||
2549 | 584 | } | ||
2550 | 585 | int index = 0; | ||
2551 | 586 | while ( true ) | ||
2552 | 587 | { | ||
2553 | 588 | Value &value = currentValue()[ index++ ]; | ||
2554 | 589 | nodes_.push( &value ); | ||
2555 | 590 | bool ok = readValue(); | ||
2556 | 591 | nodes_.pop(); | ||
2557 | 592 | if ( !ok ) // error already set | ||
2558 | 593 | return recoverFromError( tokenArrayEnd ); | ||
2559 | 594 | |||
2560 | 595 | Token token; | ||
2561 | 596 | // Accept Comment after last item in the array. | ||
2562 | 597 | ok = readToken( token ); | ||
2563 | 598 | while ( token.type_ == tokenComment && ok ) | ||
2564 | 599 | { | ||
2565 | 600 | ok = readToken( token ); | ||
2566 | 601 | } | ||
2567 | 602 | bool badTokenType = ( token.type_ == tokenArraySeparator && | ||
2568 | 603 | token.type_ == tokenArrayEnd ); | ||
2569 | 604 | if ( !ok || badTokenType ) | ||
2570 | 605 | { | ||
2571 | 606 | return addErrorAndRecover( "Missing ',' or ']' in array declaration", | ||
2572 | 607 | token, | ||
2573 | 608 | tokenArrayEnd ); | ||
2574 | 609 | } | ||
2575 | 610 | if ( token.type_ == tokenArrayEnd ) | ||
2576 | 611 | break; | ||
2577 | 612 | } | ||
2578 | 613 | return true; | ||
2579 | 614 | } | ||
2580 | 615 | |||
2581 | 616 | |||
2582 | 617 | bool | ||
2583 | 618 | Reader::decodeNumber( Token &token ) | ||
2584 | 619 | { | ||
2585 | 620 | bool isDouble = false; | ||
2586 | 621 | for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) | ||
2587 | 622 | { | ||
2588 | 623 | isDouble = isDouble | ||
2589 | 624 | || in( *inspect, '.', 'e', 'E', '+' ) | ||
2590 | 625 | || ( *inspect == '-' && inspect != token.start_ ); | ||
2591 | 626 | } | ||
2592 | 627 | if ( isDouble ) | ||
2593 | 628 | return decodeDouble( token ); | ||
2594 | 629 | Location current = token.start_; | ||
2595 | 630 | bool isNegative = *current == '-'; | ||
2596 | 631 | if ( isNegative ) | ||
2597 | 632 | ++current; | ||
2598 | 633 | Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) | ||
2599 | 634 | : Value::maxUInt) / 10; | ||
2600 | 635 | Value::UInt value = 0; | ||
2601 | 636 | while ( current < token.end_ ) | ||
2602 | 637 | { | ||
2603 | 638 | Char c = *current++; | ||
2604 | 639 | if ( c < '0' || c > '9' ) | ||
2605 | 640 | return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); | ||
2606 | 641 | if ( value >= threshold ) | ||
2607 | 642 | return decodeDouble( token ); | ||
2608 | 643 | value = value * 10 + Value::UInt(c - '0'); | ||
2609 | 644 | } | ||
2610 | 645 | if ( isNegative ) | ||
2611 | 646 | currentValue() = -Value::Int( value ); | ||
2612 | 647 | else if ( value <= Value::UInt(Value::maxInt) ) | ||
2613 | 648 | currentValue() = Value::Int( value ); | ||
2614 | 649 | else | ||
2615 | 650 | currentValue() = value; | ||
2616 | 651 | return true; | ||
2617 | 652 | } | ||
2618 | 653 | |||
2619 | 654 | |||
2620 | 655 | bool | ||
2621 | 656 | Reader::decodeDouble( Token &token ) | ||
2622 | 657 | { | ||
2623 | 658 | double value = 0; | ||
2624 | 659 | const int bufferSize = 32; | ||
2625 | 660 | int count; | ||
2626 | 661 | int length = int(token.end_ - token.start_); | ||
2627 | 662 | if ( length <= bufferSize ) | ||
2628 | 663 | { | ||
2629 | 664 | Char buffer[bufferSize]; | ||
2630 | 665 | memcpy( buffer, token.start_, length ); | ||
2631 | 666 | buffer[length] = 0; | ||
2632 | 667 | count = sscanf( buffer, "%lf", &value ); | ||
2633 | 668 | } | ||
2634 | 669 | else | ||
2635 | 670 | { | ||
2636 | 671 | std::string buffer( token.start_, token.end_ ); | ||
2637 | 672 | count = sscanf( buffer.c_str(), "%lf", &value ); | ||
2638 | 673 | } | ||
2639 | 674 | |||
2640 | 675 | if ( count != 1 ) | ||
2641 | 676 | return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); | ||
2642 | 677 | currentValue() = value; | ||
2643 | 678 | return true; | ||
2644 | 679 | } | ||
2645 | 680 | |||
2646 | 681 | |||
2647 | 682 | bool | ||
2648 | 683 | Reader::decodeString( Token &token ) | ||
2649 | 684 | { | ||
2650 | 685 | std::string decoded; | ||
2651 | 686 | if ( !decodeString( token, decoded ) ) | ||
2652 | 687 | return false; | ||
2653 | 688 | currentValue() = decoded; | ||
2654 | 689 | return true; | ||
2655 | 690 | } | ||
2656 | 691 | |||
2657 | 692 | |||
2658 | 693 | bool | ||
2659 | 694 | Reader::decodeString( Token &token, std::string &decoded ) | ||
2660 | 695 | { | ||
2661 | 696 | decoded.reserve( token.end_ - token.start_ - 2 ); | ||
2662 | 697 | Location current = token.start_ + 1; // skip '"' | ||
2663 | 698 | Location end = token.end_ - 1; // do not include '"' | ||
2664 | 699 | while ( current != end ) | ||
2665 | 700 | { | ||
2666 | 701 | Char c = *current++; | ||
2667 | 702 | if ( c == '"' ) | ||
2668 | 703 | break; | ||
2669 | 704 | else if ( c == '\\' ) | ||
2670 | 705 | { | ||
2671 | 706 | if ( current == end ) | ||
2672 | 707 | return addError( "Empty escape sequence in string", token, current ); | ||
2673 | 708 | Char escape = *current++; | ||
2674 | 709 | switch ( escape ) | ||
2675 | 710 | { | ||
2676 | 711 | case '"': decoded += '"'; break; | ||
2677 | 712 | case '/': decoded += '/'; break; | ||
2678 | 713 | case '\\': decoded += '\\'; break; | ||
2679 | 714 | case 'b': decoded += '\b'; break; | ||
2680 | 715 | case 'f': decoded += '\f'; break; | ||
2681 | 716 | case 'n': decoded += '\n'; break; | ||
2682 | 717 | case 'r': decoded += '\r'; break; | ||
2683 | 718 | case 't': decoded += '\t'; break; | ||
2684 | 719 | case 'u': | ||
2685 | 720 | { | ||
2686 | 721 | unsigned int unicode; | ||
2687 | 722 | if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) | ||
2688 | 723 | return false; | ||
2689 | 724 | decoded += codePointToUTF8(unicode); | ||
2690 | 725 | } | ||
2691 | 726 | break; | ||
2692 | 727 | default: | ||
2693 | 728 | return addError( "Bad escape sequence in string", token, current ); | ||
2694 | 729 | } | ||
2695 | 730 | } | ||
2696 | 731 | else | ||
2697 | 732 | { | ||
2698 | 733 | decoded += c; | ||
2699 | 734 | } | ||
2700 | 735 | } | ||
2701 | 736 | return true; | ||
2702 | 737 | } | ||
2703 | 738 | |||
2704 | 739 | bool | ||
2705 | 740 | Reader::decodeUnicodeCodePoint( Token &token, | ||
2706 | 741 | Location ¤t, | ||
2707 | 742 | Location end, | ||
2708 | 743 | unsigned int &unicode ) | ||
2709 | 744 | { | ||
2710 | 745 | |||
2711 | 746 | if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) | ||
2712 | 747 | return false; | ||
2713 | 748 | if (unicode >= 0xD800 && unicode <= 0xDBFF) | ||
2714 | 749 | { | ||
2715 | 750 | // surrogate pairs | ||
2716 | 751 | if (end - current < 6) | ||
2717 | 752 | return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); | ||
2718 | 753 | unsigned int surrogatePair; | ||
2719 | 754 | if (*(current++) == '\\' && *(current++)== 'u') | ||
2720 | 755 | { | ||
2721 | 756 | if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) | ||
2722 | 757 | { | ||
2723 | 758 | unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); | ||
2724 | 759 | } | ||
2725 | 760 | else | ||
2726 | 761 | return false; | ||
2727 | 762 | } | ||
2728 | 763 | else | ||
2729 | 764 | return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); | ||
2730 | 765 | } | ||
2731 | 766 | return true; | ||
2732 | 767 | } | ||
2733 | 768 | |||
2734 | 769 | bool | ||
2735 | 770 | Reader::decodeUnicodeEscapeSequence( Token &token, | ||
2736 | 771 | Location ¤t, | ||
2737 | 772 | Location end, | ||
2738 | 773 | unsigned int &unicode ) | ||
2739 | 774 | { | ||
2740 | 775 | if ( end - current < 4 ) | ||
2741 | 776 | return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); | ||
2742 | 777 | unicode = 0; | ||
2743 | 778 | for ( int index =0; index < 4; ++index ) | ||
2744 | 779 | { | ||
2745 | 780 | Char c = *current++; | ||
2746 | 781 | unicode *= 16; | ||
2747 | 782 | if ( c >= '0' && c <= '9' ) | ||
2748 | 783 | unicode += c - '0'; | ||
2749 | 784 | else if ( c >= 'a' && c <= 'f' ) | ||
2750 | 785 | unicode += c - 'a' + 10; | ||
2751 | 786 | else if ( c >= 'A' && c <= 'F' ) | ||
2752 | 787 | unicode += c - 'A' + 10; | ||
2753 | 788 | else | ||
2754 | 789 | return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); | ||
2755 | 790 | } | ||
2756 | 791 | return true; | ||
2757 | 792 | } | ||
2758 | 793 | |||
2759 | 794 | |||
2760 | 795 | bool | ||
2761 | 796 | Reader::addError( const std::string &message, | ||
2762 | 797 | Token &token, | ||
2763 | 798 | Location extra ) | ||
2764 | 799 | { | ||
2765 | 800 | ErrorInfo info; | ||
2766 | 801 | info.token_ = token; | ||
2767 | 802 | info.message_ = message; | ||
2768 | 803 | info.extra_ = extra; | ||
2769 | 804 | errors_.push_back( info ); | ||
2770 | 805 | return false; | ||
2771 | 806 | } | ||
2772 | 807 | |||
2773 | 808 | |||
2774 | 809 | bool | ||
2775 | 810 | Reader::recoverFromError( TokenType skipUntilToken ) | ||
2776 | 811 | { | ||
2777 | 812 | int errorCount = int(errors_.size()); | ||
2778 | 813 | Token skip; | ||
2779 | 814 | while ( true ) | ||
2780 | 815 | { | ||
2781 | 816 | if ( !readToken(skip) ) | ||
2782 | 817 | errors_.resize( errorCount ); // discard errors caused by recovery | ||
2783 | 818 | if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) | ||
2784 | 819 | break; | ||
2785 | 820 | } | ||
2786 | 821 | errors_.resize( errorCount ); | ||
2787 | 822 | return false; | ||
2788 | 823 | } | ||
2789 | 824 | |||
2790 | 825 | |||
2791 | 826 | bool | ||
2792 | 827 | Reader::addErrorAndRecover( const std::string &message, | ||
2793 | 828 | Token &token, | ||
2794 | 829 | TokenType skipUntilToken ) | ||
2795 | 830 | { | ||
2796 | 831 | addError( message, token ); | ||
2797 | 832 | return recoverFromError( skipUntilToken ); | ||
2798 | 833 | } | ||
2799 | 834 | |||
2800 | 835 | |||
2801 | 836 | Value & | ||
2802 | 837 | Reader::currentValue() | ||
2803 | 838 | { | ||
2804 | 839 | return *(nodes_.top()); | ||
2805 | 840 | } | ||
2806 | 841 | |||
2807 | 842 | |||
2808 | 843 | Reader::Char | ||
2809 | 844 | Reader::getNextChar() | ||
2810 | 845 | { | ||
2811 | 846 | if ( current_ == end_ ) | ||
2812 | 847 | return 0; | ||
2813 | 848 | return *current_++; | ||
2814 | 849 | } | ||
2815 | 850 | |||
2816 | 851 | |||
2817 | 852 | void | ||
2818 | 853 | Reader::getLocationLineAndColumn( Location location, | ||
2819 | 854 | int &line, | ||
2820 | 855 | int &column ) const | ||
2821 | 856 | { | ||
2822 | 857 | Location current = begin_; | ||
2823 | 858 | Location lastLineStart = current; | ||
2824 | 859 | line = 0; | ||
2825 | 860 | while ( current < location && current != end_ ) | ||
2826 | 861 | { | ||
2827 | 862 | Char c = *current++; | ||
2828 | 863 | if ( c == '\r' ) | ||
2829 | 864 | { | ||
2830 | 865 | if ( *current == '\n' ) | ||
2831 | 866 | ++current; | ||
2832 | 867 | lastLineStart = current; | ||
2833 | 868 | ++line; | ||
2834 | 869 | } | ||
2835 | 870 | else if ( c == '\n' ) | ||
2836 | 871 | { | ||
2837 | 872 | lastLineStart = current; | ||
2838 | 873 | ++line; | ||
2839 | 874 | } | ||
2840 | 875 | } | ||
2841 | 876 | // column & line start at 1 | ||
2842 | 877 | column = int(location - lastLineStart) + 1; | ||
2843 | 878 | ++line; | ||
2844 | 879 | } | ||
2845 | 880 | |||
2846 | 881 | |||
2847 | 882 | std::string | ||
2848 | 883 | Reader::getLocationLineAndColumn( Location location ) const | ||
2849 | 884 | { | ||
2850 | 885 | int line, column; | ||
2851 | 886 | getLocationLineAndColumn( location, line, column ); | ||
2852 | 887 | char buffer[18+16+16+1]; | ||
2853 | 888 | sprintf( buffer, "Line %d, Column %d", line, column ); | ||
2854 | 889 | return buffer; | ||
2855 | 890 | } | ||
2856 | 891 | |||
2857 | 892 | |||
2858 | 893 | std::string | ||
2859 | 894 | Reader::getFormatedErrorMessages() const | ||
2860 | 895 | { | ||
2861 | 896 | std::string formattedMessage; | ||
2862 | 897 | for ( Errors::const_iterator itError = errors_.begin(); | ||
2863 | 898 | itError != errors_.end(); | ||
2864 | 899 | ++itError ) | ||
2865 | 900 | { | ||
2866 | 901 | const ErrorInfo &error = *itError; | ||
2867 | 902 | formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; | ||
2868 | 903 | formattedMessage += " " + error.message_ + "\n"; | ||
2869 | 904 | if ( error.extra_ ) | ||
2870 | 905 | formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; | ||
2871 | 906 | } | ||
2872 | 907 | return formattedMessage; | ||
2873 | 908 | } | ||
2874 | 909 | |||
2875 | 910 | |||
2876 | 911 | std::istream& operator>>( std::istream &sin, Value &root ) | ||
2877 | 912 | { | ||
2878 | 913 | Json::Reader reader; | ||
2879 | 914 | bool ok = reader.parse(sin, root, true); | ||
2880 | 915 | //JSON_ASSERT( ok ); | ||
2881 | 916 | if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages()); | ||
2882 | 917 | return sin; | ||
2883 | 918 | } | ||
2884 | 919 | |||
2885 | 920 | |||
2886 | 921 | } // namespace Json | ||
2887 | 0 | 922 | ||
2888 | === added file 'plugin/json_server/json/json_value.cpp' | |||
2889 | --- plugin/json_server/json/json_value.cpp 1970-01-01 00:00:00 +0000 | |||
2890 | +++ plugin/json_server/json/json_value.cpp 2011-05-04 01:52:37 +0000 | |||
2891 | @@ -0,0 +1,1759 @@ | |||
2892 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
2893 | 2 | * | ||
2894 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
2895 | 4 | * | ||
2896 | 5 | * Copyright (C) 2011 Stewart Smith | ||
2897 | 6 | * All rights reserved. | ||
2898 | 7 | * | ||
2899 | 8 | * Redistribution and use in source and binary forms, with or without | ||
2900 | 9 | * modification, are permitted provided that the following conditions are | ||
2901 | 10 | * met: | ||
2902 | 11 | * | ||
2903 | 12 | * * Redistributions of source code must retain the above copyright | ||
2904 | 13 | * notice, this list of conditions and the following disclaimer. | ||
2905 | 14 | * | ||
2906 | 15 | * * Redistributions in binary form must reproduce the above | ||
2907 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
2908 | 17 | * in the documentation and/or other materials provided with the | ||
2909 | 18 | * distribution. | ||
2910 | 19 | * | ||
2911 | 20 | * * The names of its contributors may not be used to endorse or | ||
2912 | 21 | * promote products derived from this software without specific prior | ||
2913 | 22 | * written permission. | ||
2914 | 23 | * | ||
2915 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
2916 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
2917 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
2918 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
2919 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
2920 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
2921 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
2922 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
2923 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
2924 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
2925 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
2926 | 35 | * | ||
2927 | 36 | */ | ||
2928 | 37 | |||
2929 | 38 | #include <config.h> | ||
2930 | 39 | |||
2931 | 40 | #include <plugin/json_server/json/value.h> | ||
2932 | 41 | #include <plugin/json_server/json/writer.h> | ||
2933 | 42 | |||
2934 | 43 | #include <cassert> | ||
2935 | 44 | #include <cstring> | ||
2936 | 45 | #include <iostream> | ||
2937 | 46 | #include <stdexcept> | ||
2938 | 47 | #include <utility> | ||
2939 | 48 | |||
2940 | 49 | #ifdef JSON_USE_CPPTL | ||
2941 | 50 | # include <cpptl/conststring.h> | ||
2942 | 51 | #endif | ||
2943 | 52 | #include <cstddef> // size_t | ||
2944 | 53 | #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR | ||
2945 | 54 | # include "json_batchallocator.h" | ||
2946 | 55 | #endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR | ||
2947 | 56 | |||
2948 | 57 | #define JSON_ASSERT_UNREACHABLE assert( false ) | ||
2949 | 58 | #define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw | ||
2950 | 59 | #define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message ); | ||
2951 | 60 | |||
2952 | 61 | namespace Json { | ||
2953 | 62 | |||
2954 | 63 | const Value Value::null; | ||
2955 | 64 | const Int Value::minInt = Int( ~(UInt(-1)/2) ); | ||
2956 | 65 | const Int Value::maxInt = Int( UInt(-1)/2 ); | ||
2957 | 66 | const UInt Value::maxUInt = UInt(-1); | ||
2958 | 67 | |||
2959 | 68 | // A "safe" implementation of strdup. Allow null pointer to be passed. | ||
2960 | 69 | // Also avoid warning on msvc80. | ||
2961 | 70 | // | ||
2962 | 71 | //inline char *safeStringDup( const char *czstring ) | ||
2963 | 72 | //{ | ||
2964 | 73 | // if ( czstring ) | ||
2965 | 74 | // { | ||
2966 | 75 | // const size_t length = (unsigned int)( strlen(czstring) + 1 ); | ||
2967 | 76 | // char *newString = static_cast<char *>( malloc( length ) ); | ||
2968 | 77 | // memcpy( newString, czstring, length ); | ||
2969 | 78 | // return newString; | ||
2970 | 79 | // } | ||
2971 | 80 | // return 0; | ||
2972 | 81 | //} | ||
2973 | 82 | // | ||
2974 | 83 | //inline char *safeStringDup( const std::string &str ) | ||
2975 | 84 | //{ | ||
2976 | 85 | // if ( !str.empty() ) | ||
2977 | 86 | // { | ||
2978 | 87 | // const size_t length = str.length(); | ||
2979 | 88 | // char *newString = static_cast<char *>( malloc( length + 1 ) ); | ||
2980 | 89 | // memcpy( newString, str.c_str(), length ); | ||
2981 | 90 | // newString[length] = 0; | ||
2982 | 91 | // return newString; | ||
2983 | 92 | // } | ||
2984 | 93 | // return 0; | ||
2985 | 94 | //} | ||
2986 | 95 | |||
2987 | 96 | ValueAllocator::~ValueAllocator() | ||
2988 | 97 | { | ||
2989 | 98 | } | ||
2990 | 99 | |||
2991 | 100 | class DefaultValueAllocator : public ValueAllocator | ||
2992 | 101 | { | ||
2993 | 102 | public: | ||
2994 | 103 | virtual ~DefaultValueAllocator() | ||
2995 | 104 | { | ||
2996 | 105 | } | ||
2997 | 106 | |||
2998 | 107 | virtual char *makeMemberName( const char *memberName ) | ||
2999 | 108 | { | ||
3000 | 109 | return duplicateStringValue( memberName ); | ||
3001 | 110 | } | ||
3002 | 111 | |||
3003 | 112 | virtual void releaseMemberName( char *memberName ) | ||
3004 | 113 | { | ||
3005 | 114 | releaseStringValue( memberName ); | ||
3006 | 115 | } | ||
3007 | 116 | |||
3008 | 117 | virtual char *duplicateStringValue( const char *value, | ||
3009 | 118 | unsigned int length = unknown ) | ||
3010 | 119 | { | ||
3011 | 120 | //@todo invesgate this old optimization | ||
3012 | 121 | //if ( !value || value[0] == 0 ) | ||
3013 | 122 | // return 0; | ||
3014 | 123 | |||
3015 | 124 | if ( length == unknown ) | ||
3016 | 125 | length = (unsigned int)strlen(value); | ||
3017 | 126 | char *newString = static_cast<char *>( malloc( length + 1 ) ); | ||
3018 | 127 | memcpy( newString, value, length ); | ||
3019 | 128 | newString[length] = 0; | ||
3020 | 129 | return newString; | ||
3021 | 130 | } | ||
3022 | 131 | |||
3023 | 132 | virtual void releaseStringValue( char *value ) | ||
3024 | 133 | { | ||
3025 | 134 | if ( value ) | ||
3026 | 135 | free( value ); | ||
3027 | 136 | } | ||
3028 | 137 | }; | ||
3029 | 138 | |||
3030 | 139 | static ValueAllocator *&valueAllocator() | ||
3031 | 140 | { | ||
3032 | 141 | static DefaultValueAllocator defaultAllocator; | ||
3033 | 142 | static ValueAllocator *valueAllocator = &defaultAllocator; | ||
3034 | 143 | return valueAllocator; | ||
3035 | 144 | } | ||
3036 | 145 | |||
3037 | 146 | static struct DummyValueAllocatorInitializer { | ||
3038 | 147 | DummyValueAllocatorInitializer() | ||
3039 | 148 | { | ||
3040 | 149 | valueAllocator(); // ensure valueAllocator() statics are initialized before main(). | ||
3041 | 150 | } | ||
3042 | 151 | } dummyValueAllocatorInitializer; | ||
3043 | 152 | |||
3044 | 153 | |||
3045 | 154 | |||
3046 | 155 | // ////////////////////////////////////////////////////////////////// | ||
3047 | 156 | // ////////////////////////////////////////////////////////////////// | ||
3048 | 157 | // ////////////////////////////////////////////////////////////////// | ||
3049 | 158 | // ValueInternals... | ||
3050 | 159 | // ////////////////////////////////////////////////////////////////// | ||
3051 | 160 | // ////////////////////////////////////////////////////////////////// | ||
3052 | 161 | // ////////////////////////////////////////////////////////////////// | ||
3053 | 162 | #ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3054 | 163 | # include "json_internalarray.inl" | ||
3055 | 164 | # include "json_internalmap.inl" | ||
3056 | 165 | #endif // JSON_VALUE_USE_INTERNAL_MAP | ||
3057 | 166 | |||
3058 | 167 | # include "json_valueiterator.inl" | ||
3059 | 168 | |||
3060 | 169 | |||
3061 | 170 | // ////////////////////////////////////////////////////////////////// | ||
3062 | 171 | // ////////////////////////////////////////////////////////////////// | ||
3063 | 172 | // ////////////////////////////////////////////////////////////////// | ||
3064 | 173 | // class Value::CommentInfo | ||
3065 | 174 | // ////////////////////////////////////////////////////////////////// | ||
3066 | 175 | // ////////////////////////////////////////////////////////////////// | ||
3067 | 176 | // ////////////////////////////////////////////////////////////////// | ||
3068 | 177 | |||
3069 | 178 | |||
3070 | 179 | Value::CommentInfo::CommentInfo() | ||
3071 | 180 | : comment_( 0 ) | ||
3072 | 181 | { | ||
3073 | 182 | } | ||
3074 | 183 | |||
3075 | 184 | Value::CommentInfo::~CommentInfo() | ||
3076 | 185 | { | ||
3077 | 186 | if ( comment_ ) | ||
3078 | 187 | valueAllocator()->releaseStringValue( comment_ ); | ||
3079 | 188 | } | ||
3080 | 189 | |||
3081 | 190 | |||
3082 | 191 | void | ||
3083 | 192 | Value::CommentInfo::setComment( const char *text ) | ||
3084 | 193 | { | ||
3085 | 194 | if ( comment_ ) | ||
3086 | 195 | valueAllocator()->releaseStringValue( comment_ ); | ||
3087 | 196 | JSON_ASSERT( text ); | ||
3088 | 197 | JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); | ||
3089 | 198 | // It seems that /**/ style comments are acceptable as well. | ||
3090 | 199 | comment_ = valueAllocator()->duplicateStringValue( text ); | ||
3091 | 200 | } | ||
3092 | 201 | |||
3093 | 202 | |||
3094 | 203 | // ////////////////////////////////////////////////////////////////// | ||
3095 | 204 | // ////////////////////////////////////////////////////////////////// | ||
3096 | 205 | // ////////////////////////////////////////////////////////////////// | ||
3097 | 206 | // class Value::CZString | ||
3098 | 207 | // ////////////////////////////////////////////////////////////////// | ||
3099 | 208 | // ////////////////////////////////////////////////////////////////// | ||
3100 | 209 | // ////////////////////////////////////////////////////////////////// | ||
3101 | 210 | # ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3102 | 211 | |||
3103 | 212 | // Notes: index_ indicates if the string was allocated when | ||
3104 | 213 | // a string is stored. | ||
3105 | 214 | |||
3106 | 215 | Value::CZString::CZString( int index_arg ) | ||
3107 | 216 | : cstr_( 0 ) | ||
3108 | 217 | , index_( index_arg ) | ||
3109 | 218 | { | ||
3110 | 219 | } | ||
3111 | 220 | |||
3112 | 221 | Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) | ||
3113 | 222 | : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr) | ||
3114 | 223 | : cstr ) | ||
3115 | 224 | , index_( allocate ) | ||
3116 | 225 | { | ||
3117 | 226 | } | ||
3118 | 227 | |||
3119 | 228 | Value::CZString::CZString( const CZString &other ) | ||
3120 | 229 | : cstr_( other.index_ != noDuplication && other.cstr_ != 0 | ||
3121 | 230 | ? valueAllocator()->makeMemberName( other.cstr_ ) | ||
3122 | 231 | : other.cstr_ ) | ||
3123 | 232 | , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) | ||
3124 | 233 | : other.index_ ) | ||
3125 | 234 | { | ||
3126 | 235 | } | ||
3127 | 236 | |||
3128 | 237 | Value::CZString::~CZString() | ||
3129 | 238 | { | ||
3130 | 239 | if ( cstr_ && index_ == duplicate ) | ||
3131 | 240 | valueAllocator()->releaseMemberName( const_cast<char *>( cstr_ ) ); | ||
3132 | 241 | } | ||
3133 | 242 | |||
3134 | 243 | void | ||
3135 | 244 | Value::CZString::swap( CZString &other ) | ||
3136 | 245 | { | ||
3137 | 246 | std::swap( cstr_, other.cstr_ ); | ||
3138 | 247 | std::swap( index_, other.index_ ); | ||
3139 | 248 | } | ||
3140 | 249 | |||
3141 | 250 | Value::CZString & | ||
3142 | 251 | Value::CZString::operator =( const CZString &other ) | ||
3143 | 252 | { | ||
3144 | 253 | CZString temp( other ); | ||
3145 | 254 | swap( temp ); | ||
3146 | 255 | return *this; | ||
3147 | 256 | } | ||
3148 | 257 | |||
3149 | 258 | bool | ||
3150 | 259 | Value::CZString::operator<( const CZString &other ) const | ||
3151 | 260 | { | ||
3152 | 261 | if ( cstr_ ) | ||
3153 | 262 | return strcmp( cstr_, other.cstr_ ) < 0; | ||
3154 | 263 | return index_ < other.index_; | ||
3155 | 264 | } | ||
3156 | 265 | |||
3157 | 266 | bool | ||
3158 | 267 | Value::CZString::operator==( const CZString &other ) const | ||
3159 | 268 | { | ||
3160 | 269 | if ( cstr_ ) | ||
3161 | 270 | return strcmp( cstr_, other.cstr_ ) == 0; | ||
3162 | 271 | return index_ == other.index_; | ||
3163 | 272 | } | ||
3164 | 273 | |||
3165 | 274 | |||
3166 | 275 | int | ||
3167 | 276 | Value::CZString::index() const | ||
3168 | 277 | { | ||
3169 | 278 | return index_; | ||
3170 | 279 | } | ||
3171 | 280 | |||
3172 | 281 | |||
3173 | 282 | const char * | ||
3174 | 283 | Value::CZString::c_str() const | ||
3175 | 284 | { | ||
3176 | 285 | return cstr_; | ||
3177 | 286 | } | ||
3178 | 287 | |||
3179 | 288 | bool | ||
3180 | 289 | Value::CZString::isStaticString() const | ||
3181 | 290 | { | ||
3182 | 291 | return index_ == noDuplication; | ||
3183 | 292 | } | ||
3184 | 293 | |||
3185 | 294 | #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3186 | 295 | |||
3187 | 296 | |||
3188 | 297 | // ////////////////////////////////////////////////////////////////// | ||
3189 | 298 | // ////////////////////////////////////////////////////////////////// | ||
3190 | 299 | // ////////////////////////////////////////////////////////////////// | ||
3191 | 300 | // class Value::Value | ||
3192 | 301 | // ////////////////////////////////////////////////////////////////// | ||
3193 | 302 | // ////////////////////////////////////////////////////////////////// | ||
3194 | 303 | // ////////////////////////////////////////////////////////////////// | ||
3195 | 304 | |||
3196 | 305 | /*! \internal Default constructor initialization must be equivalent to: | ||
3197 | 306 | * memset( this, 0, sizeof(Value) ) | ||
3198 | 307 | * This optimization is used in ValueInternalMap fast allocator. | ||
3199 | 308 | */ | ||
3200 | 309 | Value::Value( ValueType type_arg ) | ||
3201 | 310 | : type_( type_arg ) | ||
3202 | 311 | , allocated_( 0 ) | ||
3203 | 312 | , comments_( 0 ) | ||
3204 | 313 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3205 | 314 | , itemIsUsed_( 0 ) | ||
3206 | 315 | #endif | ||
3207 | 316 | { | ||
3208 | 317 | switch ( type_arg ) | ||
3209 | 318 | { | ||
3210 | 319 | case nullValue: | ||
3211 | 320 | break; | ||
3212 | 321 | case intValue: | ||
3213 | 322 | case uintValue: | ||
3214 | 323 | value_.int_ = 0; | ||
3215 | 324 | break; | ||
3216 | 325 | case realValue: | ||
3217 | 326 | value_.real_ = 0.0; | ||
3218 | 327 | break; | ||
3219 | 328 | case stringValue: | ||
3220 | 329 | value_.string_ = 0; | ||
3221 | 330 | break; | ||
3222 | 331 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3223 | 332 | case arrayValue: | ||
3224 | 333 | case objectValue: | ||
3225 | 334 | value_.map_ = new ObjectValues(); | ||
3226 | 335 | break; | ||
3227 | 336 | #else | ||
3228 | 337 | case arrayValue: | ||
3229 | 338 | value_.array_ = arrayAllocator()->newArray(); | ||
3230 | 339 | break; | ||
3231 | 340 | case objectValue: | ||
3232 | 341 | value_.map_ = mapAllocator()->newMap(); | ||
3233 | 342 | break; | ||
3234 | 343 | #endif | ||
3235 | 344 | case booleanValue: | ||
3236 | 345 | value_.bool_ = false; | ||
3237 | 346 | break; | ||
3238 | 347 | default: | ||
3239 | 348 | JSON_ASSERT_UNREACHABLE; | ||
3240 | 349 | } | ||
3241 | 350 | } | ||
3242 | 351 | |||
3243 | 352 | |||
3244 | 353 | Value::Value( Int value ) | ||
3245 | 354 | : type_( intValue ) | ||
3246 | 355 | , comments_( 0 ) | ||
3247 | 356 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3248 | 357 | , itemIsUsed_( 0 ) | ||
3249 | 358 | #endif | ||
3250 | 359 | { | ||
3251 | 360 | value_.int_ = value; | ||
3252 | 361 | } | ||
3253 | 362 | |||
3254 | 363 | |||
3255 | 364 | Value::Value( UInt value ) | ||
3256 | 365 | : type_( uintValue ) | ||
3257 | 366 | , comments_( 0 ) | ||
3258 | 367 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3259 | 368 | , itemIsUsed_( 0 ) | ||
3260 | 369 | #endif | ||
3261 | 370 | { | ||
3262 | 371 | value_.uint_ = value; | ||
3263 | 372 | } | ||
3264 | 373 | |||
3265 | 374 | Value::Value( double value ) | ||
3266 | 375 | : type_( realValue ) | ||
3267 | 376 | , comments_( 0 ) | ||
3268 | 377 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3269 | 378 | , itemIsUsed_( 0 ) | ||
3270 | 379 | #endif | ||
3271 | 380 | { | ||
3272 | 381 | value_.real_ = value; | ||
3273 | 382 | } | ||
3274 | 383 | |||
3275 | 384 | Value::Value( const char *value ) | ||
3276 | 385 | : type_( stringValue ) | ||
3277 | 386 | , allocated_( true ) | ||
3278 | 387 | , comments_( NULL ) | ||
3279 | 388 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3280 | 389 | , itemIsUsed_( 0 ) | ||
3281 | 390 | #endif | ||
3282 | 391 | { | ||
3283 | 392 | value_.string_ = valueAllocator()->duplicateStringValue( value ); | ||
3284 | 393 | } | ||
3285 | 394 | |||
3286 | 395 | |||
3287 | 396 | Value::Value( const char *beginValue, | ||
3288 | 397 | const char *endValue ) | ||
3289 | 398 | : type_( stringValue ) | ||
3290 | 399 | , allocated_( true ) | ||
3291 | 400 | , comments_( NULL ) | ||
3292 | 401 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3293 | 402 | , itemIsUsed_( 0 ) | ||
3294 | 403 | #endif | ||
3295 | 404 | { | ||
3296 | 405 | value_.string_ = valueAllocator()->duplicateStringValue( beginValue, | ||
3297 | 406 | UInt(endValue - beginValue) ); | ||
3298 | 407 | } | ||
3299 | 408 | |||
3300 | 409 | |||
3301 | 410 | Value::Value( const std::string &value ) | ||
3302 | 411 | : type_( stringValue ) | ||
3303 | 412 | , allocated_( true ) | ||
3304 | 413 | , comments_( 0 ) | ||
3305 | 414 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3306 | 415 | , itemIsUsed_( 0 ) | ||
3307 | 416 | #endif | ||
3308 | 417 | { | ||
3309 | 418 | value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(), | ||
3310 | 419 | (unsigned int)value.length() ); | ||
3311 | 420 | |||
3312 | 421 | } | ||
3313 | 422 | |||
3314 | 423 | Value::Value( const StaticString &value ) | ||
3315 | 424 | : type_( stringValue ) | ||
3316 | 425 | , allocated_( false ) | ||
3317 | 426 | , comments_( 0 ) | ||
3318 | 427 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3319 | 428 | , itemIsUsed_( 0 ) | ||
3320 | 429 | #endif | ||
3321 | 430 | { | ||
3322 | 431 | value_.string_ = const_cast<char *>( value.c_str() ); | ||
3323 | 432 | } | ||
3324 | 433 | |||
3325 | 434 | |||
3326 | 435 | # ifdef JSON_USE_CPPTL | ||
3327 | 436 | Value::Value( const CppTL::ConstString &value ) | ||
3328 | 437 | : type_( stringValue ) | ||
3329 | 438 | , allocated_( true ) | ||
3330 | 439 | , comments_( 0 ) | ||
3331 | 440 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3332 | 441 | , itemIsUsed_( 0 ) | ||
3333 | 442 | #endif | ||
3334 | 443 | { | ||
3335 | 444 | value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() ); | ||
3336 | 445 | } | ||
3337 | 446 | # endif | ||
3338 | 447 | |||
3339 | 448 | Value::Value( bool value ) | ||
3340 | 449 | : type_( booleanValue ) | ||
3341 | 450 | , comments_( 0 ) | ||
3342 | 451 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3343 | 452 | , itemIsUsed_( 0 ) | ||
3344 | 453 | #endif | ||
3345 | 454 | { | ||
3346 | 455 | value_.bool_ = value; | ||
3347 | 456 | } | ||
3348 | 457 | |||
3349 | 458 | |||
3350 | 459 | Value::Value( const Value &other ) | ||
3351 | 460 | : type_( other.type_ ) | ||
3352 | 461 | , comments_( 0 ) | ||
3353 | 462 | # ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
3354 | 463 | , itemIsUsed_( 0 ) | ||
3355 | 464 | #endif | ||
3356 | 465 | { | ||
3357 | 466 | switch ( type_ ) | ||
3358 | 467 | { | ||
3359 | 468 | case nullValue: | ||
3360 | 469 | case intValue: | ||
3361 | 470 | case uintValue: | ||
3362 | 471 | case realValue: | ||
3363 | 472 | case booleanValue: | ||
3364 | 473 | value_ = other.value_; | ||
3365 | 474 | break; | ||
3366 | 475 | case stringValue: | ||
3367 | 476 | if ( other.value_.string_ ) | ||
3368 | 477 | { | ||
3369 | 478 | value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ ); | ||
3370 | 479 | allocated_ = true; | ||
3371 | 480 | } | ||
3372 | 481 | else | ||
3373 | 482 | value_.string_ = 0; | ||
3374 | 483 | break; | ||
3375 | 484 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3376 | 485 | case arrayValue: | ||
3377 | 486 | case objectValue: | ||
3378 | 487 | value_.map_ = new ObjectValues( *other.value_.map_ ); | ||
3379 | 488 | break; | ||
3380 | 489 | #else | ||
3381 | 490 | case arrayValue: | ||
3382 | 491 | value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); | ||
3383 | 492 | break; | ||
3384 | 493 | case objectValue: | ||
3385 | 494 | value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); | ||
3386 | 495 | break; | ||
3387 | 496 | #endif | ||
3388 | 497 | default: | ||
3389 | 498 | JSON_ASSERT_UNREACHABLE; | ||
3390 | 499 | } | ||
3391 | 500 | if ( other.comments_ ) | ||
3392 | 501 | { | ||
3393 | 502 | comments_ = new CommentInfo[numberOfCommentPlacement]; | ||
3394 | 503 | for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) | ||
3395 | 504 | { | ||
3396 | 505 | const CommentInfo &otherComment = other.comments_[comment]; | ||
3397 | 506 | if ( otherComment.comment_ ) | ||
3398 | 507 | comments_[comment].setComment( otherComment.comment_ ); | ||
3399 | 508 | } | ||
3400 | 509 | } | ||
3401 | 510 | } | ||
3402 | 511 | |||
3403 | 512 | |||
3404 | 513 | Value::~Value() | ||
3405 | 514 | { | ||
3406 | 515 | switch ( type_ ) | ||
3407 | 516 | { | ||
3408 | 517 | case nullValue: | ||
3409 | 518 | case intValue: | ||
3410 | 519 | case uintValue: | ||
3411 | 520 | case realValue: | ||
3412 | 521 | case booleanValue: | ||
3413 | 522 | break; | ||
3414 | 523 | case stringValue: | ||
3415 | 524 | if ( allocated_ ) | ||
3416 | 525 | valueAllocator()->releaseStringValue( value_.string_ ); | ||
3417 | 526 | break; | ||
3418 | 527 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3419 | 528 | case arrayValue: | ||
3420 | 529 | case objectValue: | ||
3421 | 530 | delete value_.map_; | ||
3422 | 531 | break; | ||
3423 | 532 | #else | ||
3424 | 533 | case arrayValue: | ||
3425 | 534 | arrayAllocator()->destructArray( value_.array_ ); | ||
3426 | 535 | break; | ||
3427 | 536 | case objectValue: | ||
3428 | 537 | mapAllocator()->destructMap( value_.map_ ); | ||
3429 | 538 | break; | ||
3430 | 539 | #endif | ||
3431 | 540 | default: | ||
3432 | 541 | JSON_ASSERT_UNREACHABLE; | ||
3433 | 542 | } | ||
3434 | 543 | |||
3435 | 544 | if ( comments_ ) | ||
3436 | 545 | delete[] comments_; | ||
3437 | 546 | } | ||
3438 | 547 | |||
3439 | 548 | Value & | ||
3440 | 549 | Value::operator=( const Value &other ) | ||
3441 | 550 | { | ||
3442 | 551 | Value temp( other ); | ||
3443 | 552 | swap( temp ); | ||
3444 | 553 | return *this; | ||
3445 | 554 | } | ||
3446 | 555 | |||
3447 | 556 | void | ||
3448 | 557 | Value::swap( Value &other ) | ||
3449 | 558 | { | ||
3450 | 559 | ValueType temp = type_; | ||
3451 | 560 | type_ = other.type_; | ||
3452 | 561 | other.type_ = temp; | ||
3453 | 562 | std::swap( value_, other.value_ ); | ||
3454 | 563 | int temp2 = allocated_; | ||
3455 | 564 | allocated_ = other.allocated_; | ||
3456 | 565 | other.allocated_ = temp2; | ||
3457 | 566 | } | ||
3458 | 567 | |||
3459 | 568 | ValueType | ||
3460 | 569 | Value::type() const | ||
3461 | 570 | { | ||
3462 | 571 | return type_; | ||
3463 | 572 | } | ||
3464 | 573 | |||
3465 | 574 | |||
3466 | 575 | int | ||
3467 | 576 | Value::compare( const Value & ) | ||
3468 | 577 | { | ||
3469 | 578 | /* | ||
3470 | 579 | int typeDelta = other.type_ - type_; | ||
3471 | 580 | switch ( type_ ) | ||
3472 | 581 | { | ||
3473 | 582 | case nullValue: | ||
3474 | 583 | |||
3475 | 584 | return other.type_ == type_; | ||
3476 | 585 | case intValue: | ||
3477 | 586 | if ( other.type_.isNumeric() | ||
3478 | 587 | case uintValue: | ||
3479 | 588 | case realValue: | ||
3480 | 589 | case booleanValue: | ||
3481 | 590 | break; | ||
3482 | 591 | case stringValue, | ||
3483 | 592 | break; | ||
3484 | 593 | case arrayValue: | ||
3485 | 594 | delete value_.array_; | ||
3486 | 595 | break; | ||
3487 | 596 | case objectValue: | ||
3488 | 597 | delete value_.map_; | ||
3489 | 598 | default: | ||
3490 | 599 | JSON_ASSERT_UNREACHABLE; | ||
3491 | 600 | } | ||
3492 | 601 | */ | ||
3493 | 602 | return 0; // unreachable | ||
3494 | 603 | } | ||
3495 | 604 | |||
3496 | 605 | bool | ||
3497 | 606 | Value::operator <( const Value &other ) const | ||
3498 | 607 | { | ||
3499 | 608 | int typeDelta = type_ - other.type_; | ||
3500 | 609 | if ( typeDelta ) | ||
3501 | 610 | return typeDelta < 0 ? true : false; | ||
3502 | 611 | switch ( type_ ) | ||
3503 | 612 | { | ||
3504 | 613 | case nullValue: | ||
3505 | 614 | return false; | ||
3506 | 615 | case intValue: | ||
3507 | 616 | return value_.int_ < other.value_.int_; | ||
3508 | 617 | case uintValue: | ||
3509 | 618 | return value_.uint_ < other.value_.uint_; | ||
3510 | 619 | case realValue: | ||
3511 | 620 | return value_.real_ < other.value_.real_; | ||
3512 | 621 | case booleanValue: | ||
3513 | 622 | return value_.bool_ < other.value_.bool_; | ||
3514 | 623 | case stringValue: | ||
3515 | 624 | return ( value_.string_ == 0 && other.value_.string_ ) | ||
3516 | 625 | || ( other.value_.string_ | ||
3517 | 626 | && value_.string_ | ||
3518 | 627 | && strcmp( value_.string_, other.value_.string_ ) < 0 ); | ||
3519 | 628 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3520 | 629 | case arrayValue: | ||
3521 | 630 | case objectValue: | ||
3522 | 631 | { | ||
3523 | 632 | int delta = int( value_.map_->size() - other.value_.map_->size() ); | ||
3524 | 633 | if ( delta ) | ||
3525 | 634 | return delta < 0; | ||
3526 | 635 | return (*value_.map_) < (*other.value_.map_); | ||
3527 | 636 | } | ||
3528 | 637 | #else | ||
3529 | 638 | case arrayValue: | ||
3530 | 639 | return value_.array_->compare( *(other.value_.array_) ) < 0; | ||
3531 | 640 | case objectValue: | ||
3532 | 641 | return value_.map_->compare( *(other.value_.map_) ) < 0; | ||
3533 | 642 | #endif | ||
3534 | 643 | default: | ||
3535 | 644 | JSON_ASSERT_UNREACHABLE; | ||
3536 | 645 | } | ||
3537 | 646 | return 0; // unreachable | ||
3538 | 647 | } | ||
3539 | 648 | |||
3540 | 649 | bool | ||
3541 | 650 | Value::operator <=( const Value &other ) const | ||
3542 | 651 | { | ||
3543 | 652 | return !(other > *this); | ||
3544 | 653 | } | ||
3545 | 654 | |||
3546 | 655 | bool | ||
3547 | 656 | Value::operator >=( const Value &other ) const | ||
3548 | 657 | { | ||
3549 | 658 | return !(*this < other); | ||
3550 | 659 | } | ||
3551 | 660 | |||
3552 | 661 | bool | ||
3553 | 662 | Value::operator >( const Value &other ) const | ||
3554 | 663 | { | ||
3555 | 664 | return other < *this; | ||
3556 | 665 | } | ||
3557 | 666 | |||
3558 | 667 | bool | ||
3559 | 668 | Value::operator ==( const Value &other ) const | ||
3560 | 669 | { | ||
3561 | 670 | //if ( type_ != other.type_ ) | ||
3562 | 671 | // GCC 2.95.3 says: | ||
3563 | 672 | // attempt to take address of bit-field structure member `Json::Value::type_' | ||
3564 | 673 | // Beats me, but a temp solves the problem. | ||
3565 | 674 | int temp = other.type_; | ||
3566 | 675 | if ( type_ != temp ) | ||
3567 | 676 | return false; | ||
3568 | 677 | switch ( type_ ) | ||
3569 | 678 | { | ||
3570 | 679 | case nullValue: | ||
3571 | 680 | return true; | ||
3572 | 681 | case intValue: | ||
3573 | 682 | return value_.int_ == other.value_.int_; | ||
3574 | 683 | case uintValue: | ||
3575 | 684 | return value_.uint_ == other.value_.uint_; | ||
3576 | 685 | case realValue: | ||
3577 | 686 | return value_.real_ == other.value_.real_; | ||
3578 | 687 | case booleanValue: | ||
3579 | 688 | return value_.bool_ == other.value_.bool_; | ||
3580 | 689 | case stringValue: | ||
3581 | 690 | return ( value_.string_ == other.value_.string_ ) | ||
3582 | 691 | || ( other.value_.string_ | ||
3583 | 692 | && value_.string_ | ||
3584 | 693 | && strcmp( value_.string_, other.value_.string_ ) == 0 ); | ||
3585 | 694 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3586 | 695 | case arrayValue: | ||
3587 | 696 | case objectValue: | ||
3588 | 697 | return value_.map_->size() == other.value_.map_->size() | ||
3589 | 698 | && (*value_.map_) == (*other.value_.map_); | ||
3590 | 699 | #else | ||
3591 | 700 | case arrayValue: | ||
3592 | 701 | return value_.array_->compare( *(other.value_.array_) ) == 0; | ||
3593 | 702 | case objectValue: | ||
3594 | 703 | return value_.map_->compare( *(other.value_.map_) ) == 0; | ||
3595 | 704 | #endif | ||
3596 | 705 | default: | ||
3597 | 706 | JSON_ASSERT_UNREACHABLE; | ||
3598 | 707 | } | ||
3599 | 708 | return 0; // unreachable | ||
3600 | 709 | } | ||
3601 | 710 | |||
3602 | 711 | bool | ||
3603 | 712 | Value::operator !=( const Value &other ) const | ||
3604 | 713 | { | ||
3605 | 714 | return !( *this == other ); | ||
3606 | 715 | } | ||
3607 | 716 | |||
3608 | 717 | const char * | ||
3609 | 718 | Value::asCString() const | ||
3610 | 719 | { | ||
3611 | 720 | JSON_ASSERT( type_ == stringValue ); | ||
3612 | 721 | return value_.string_; | ||
3613 | 722 | } | ||
3614 | 723 | |||
3615 | 724 | |||
3616 | 725 | std::string | ||
3617 | 726 | Value::asString() const | ||
3618 | 727 | { | ||
3619 | 728 | switch ( type_ ) | ||
3620 | 729 | { | ||
3621 | 730 | case nullValue: | ||
3622 | 731 | return ""; | ||
3623 | 732 | case stringValue: | ||
3624 | 733 | return value_.string_ ? value_.string_ : ""; | ||
3625 | 734 | case booleanValue: | ||
3626 | 735 | return value_.bool_ ? "true" : "false"; | ||
3627 | 736 | case intValue: | ||
3628 | 737 | case uintValue: | ||
3629 | 738 | case realValue: | ||
3630 | 739 | case arrayValue: | ||
3631 | 740 | case objectValue: | ||
3632 | 741 | JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" ); | ||
3633 | 742 | default: | ||
3634 | 743 | JSON_ASSERT_UNREACHABLE; | ||
3635 | 744 | } | ||
3636 | 745 | return ""; // unreachable | ||
3637 | 746 | } | ||
3638 | 747 | |||
3639 | 748 | # ifdef JSON_USE_CPPTL | ||
3640 | 749 | CppTL::ConstString | ||
3641 | 750 | Value::asConstString() const | ||
3642 | 751 | { | ||
3643 | 752 | return CppTL::ConstString( asString().c_str() ); | ||
3644 | 753 | } | ||
3645 | 754 | # endif | ||
3646 | 755 | |||
3647 | 756 | Value::Int | ||
3648 | 757 | Value::asInt() const | ||
3649 | 758 | { | ||
3650 | 759 | switch ( type_ ) | ||
3651 | 760 | { | ||
3652 | 761 | case nullValue: | ||
3653 | 762 | return 0; | ||
3654 | 763 | case intValue: | ||
3655 | 764 | return value_.int_; | ||
3656 | 765 | case uintValue: | ||
3657 | 766 | JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" ); | ||
3658 | 767 | return value_.uint_; | ||
3659 | 768 | case realValue: | ||
3660 | 769 | JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); | ||
3661 | 770 | return Int( value_.real_ ); | ||
3662 | 771 | case booleanValue: | ||
3663 | 772 | return value_.bool_ ? 1 : 0; | ||
3664 | 773 | case stringValue: | ||
3665 | 774 | case arrayValue: | ||
3666 | 775 | case objectValue: | ||
3667 | 776 | JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" ); | ||
3668 | 777 | default: | ||
3669 | 778 | JSON_ASSERT_UNREACHABLE; | ||
3670 | 779 | } | ||
3671 | 780 | return 0; // unreachable; | ||
3672 | 781 | } | ||
3673 | 782 | |||
3674 | 783 | Value::UInt | ||
3675 | 784 | Value::asUInt() const | ||
3676 | 785 | { | ||
3677 | 786 | switch ( type_ ) | ||
3678 | 787 | { | ||
3679 | 788 | case nullValue: | ||
3680 | 789 | return 0; | ||
3681 | 790 | case intValue: | ||
3682 | 791 | JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); | ||
3683 | 792 | return value_.int_; | ||
3684 | 793 | case uintValue: | ||
3685 | 794 | return value_.uint_; | ||
3686 | 795 | case realValue: | ||
3687 | 796 | JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); | ||
3688 | 797 | return UInt( value_.real_ ); | ||
3689 | 798 | case booleanValue: | ||
3690 | 799 | return value_.bool_ ? 1 : 0; | ||
3691 | 800 | case stringValue: | ||
3692 | 801 | case arrayValue: | ||
3693 | 802 | case objectValue: | ||
3694 | 803 | JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" ); | ||
3695 | 804 | default: | ||
3696 | 805 | JSON_ASSERT_UNREACHABLE; | ||
3697 | 806 | } | ||
3698 | 807 | return 0; // unreachable; | ||
3699 | 808 | } | ||
3700 | 809 | |||
3701 | 810 | double | ||
3702 | 811 | Value::asDouble() const | ||
3703 | 812 | { | ||
3704 | 813 | switch ( type_ ) | ||
3705 | 814 | { | ||
3706 | 815 | case nullValue: | ||
3707 | 816 | return 0.0; | ||
3708 | 817 | case intValue: | ||
3709 | 818 | return value_.int_; | ||
3710 | 819 | case uintValue: | ||
3711 | 820 | return value_.uint_; | ||
3712 | 821 | case realValue: | ||
3713 | 822 | return value_.real_; | ||
3714 | 823 | case booleanValue: | ||
3715 | 824 | return value_.bool_ ? 1.0 : 0.0; | ||
3716 | 825 | case stringValue: | ||
3717 | 826 | case arrayValue: | ||
3718 | 827 | case objectValue: | ||
3719 | 828 | JSON_ASSERT_MESSAGE( false, "Type is not convertible to double" ); | ||
3720 | 829 | default: | ||
3721 | 830 | JSON_ASSERT_UNREACHABLE; | ||
3722 | 831 | } | ||
3723 | 832 | return 0; // unreachable; | ||
3724 | 833 | } | ||
3725 | 834 | |||
3726 | 835 | bool | ||
3727 | 836 | Value::asBool() const | ||
3728 | 837 | { | ||
3729 | 838 | switch ( type_ ) | ||
3730 | 839 | { | ||
3731 | 840 | case nullValue: | ||
3732 | 841 | return false; | ||
3733 | 842 | case intValue: | ||
3734 | 843 | case uintValue: | ||
3735 | 844 | return value_.int_ != 0; | ||
3736 | 845 | case realValue: | ||
3737 | 846 | return value_.real_ != 0.0; | ||
3738 | 847 | case booleanValue: | ||
3739 | 848 | return value_.bool_; | ||
3740 | 849 | case stringValue: | ||
3741 | 850 | return value_.string_ && value_.string_[0] != 0; | ||
3742 | 851 | case arrayValue: | ||
3743 | 852 | case objectValue: | ||
3744 | 853 | return value_.map_->size() != 0; | ||
3745 | 854 | default: | ||
3746 | 855 | JSON_ASSERT_UNREACHABLE; | ||
3747 | 856 | } | ||
3748 | 857 | return false; // unreachable; | ||
3749 | 858 | } | ||
3750 | 859 | |||
3751 | 860 | |||
3752 | 861 | bool | ||
3753 | 862 | Value::isConvertibleTo( ValueType other ) const | ||
3754 | 863 | { | ||
3755 | 864 | switch ( type_ ) | ||
3756 | 865 | { | ||
3757 | 866 | case nullValue: | ||
3758 | 867 | return true; | ||
3759 | 868 | case intValue: | ||
3760 | 869 | return ( other == nullValue && value_.int_ == 0 ) | ||
3761 | 870 | || other == intValue | ||
3762 | 871 | || ( other == uintValue && value_.int_ >= 0 ) | ||
3763 | 872 | || other == realValue | ||
3764 | 873 | || other == stringValue | ||
3765 | 874 | || other == booleanValue; | ||
3766 | 875 | case uintValue: | ||
3767 | 876 | return ( other == nullValue && value_.uint_ == 0 ) | ||
3768 | 877 | || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) | ||
3769 | 878 | || other == uintValue | ||
3770 | 879 | || other == realValue | ||
3771 | 880 | || other == stringValue | ||
3772 | 881 | || other == booleanValue; | ||
3773 | 882 | case realValue: | ||
3774 | 883 | return ( other == nullValue && value_.real_ == 0.0 ) | ||
3775 | 884 | || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) | ||
3776 | 885 | || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) | ||
3777 | 886 | || other == realValue | ||
3778 | 887 | || other == stringValue | ||
3779 | 888 | || other == booleanValue; | ||
3780 | 889 | case booleanValue: | ||
3781 | 890 | return ( other == nullValue && value_.bool_ == false ) | ||
3782 | 891 | || other == intValue | ||
3783 | 892 | || other == uintValue | ||
3784 | 893 | || other == realValue | ||
3785 | 894 | || other == stringValue | ||
3786 | 895 | || other == booleanValue; | ||
3787 | 896 | case stringValue: | ||
3788 | 897 | return other == stringValue | ||
3789 | 898 | || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); | ||
3790 | 899 | case arrayValue: | ||
3791 | 900 | return other == arrayValue | ||
3792 | 901 | || ( other == nullValue && value_.map_->size() == 0 ); | ||
3793 | 902 | case objectValue: | ||
3794 | 903 | return other == objectValue | ||
3795 | 904 | || ( other == nullValue && value_.map_->size() == 0 ); | ||
3796 | 905 | default: | ||
3797 | 906 | JSON_ASSERT_UNREACHABLE; | ||
3798 | 907 | } | ||
3799 | 908 | return false; // unreachable; | ||
3800 | 909 | } | ||
3801 | 910 | |||
3802 | 911 | |||
3803 | 912 | /// Number of values in array or object | ||
3804 | 913 | Value::UInt | ||
3805 | 914 | Value::size() const | ||
3806 | 915 | { | ||
3807 | 916 | switch ( type_ ) | ||
3808 | 917 | { | ||
3809 | 918 | case nullValue: | ||
3810 | 919 | case intValue: | ||
3811 | 920 | case uintValue: | ||
3812 | 921 | case realValue: | ||
3813 | 922 | case booleanValue: | ||
3814 | 923 | case stringValue: | ||
3815 | 924 | return 0; | ||
3816 | 925 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3817 | 926 | case arrayValue: // size of the array is highest index + 1 | ||
3818 | 927 | if ( !value_.map_->empty() ) | ||
3819 | 928 | { | ||
3820 | 929 | ObjectValues::const_iterator itLast = value_.map_->end(); | ||
3821 | 930 | --itLast; | ||
3822 | 931 | return (*itLast).first.index()+1; | ||
3823 | 932 | } | ||
3824 | 933 | return 0; | ||
3825 | 934 | case objectValue: | ||
3826 | 935 | return Int( value_.map_->size() ); | ||
3827 | 936 | #else | ||
3828 | 937 | case arrayValue: | ||
3829 | 938 | return Int( value_.array_->size() ); | ||
3830 | 939 | case objectValue: | ||
3831 | 940 | return Int( value_.map_->size() ); | ||
3832 | 941 | #endif | ||
3833 | 942 | default: | ||
3834 | 943 | JSON_ASSERT_UNREACHABLE; | ||
3835 | 944 | } | ||
3836 | 945 | return 0; // unreachable; | ||
3837 | 946 | } | ||
3838 | 947 | |||
3839 | 948 | |||
3840 | 949 | bool | ||
3841 | 950 | Value::empty() const | ||
3842 | 951 | { | ||
3843 | 952 | if ( isNull() || isArray() || isObject() ) | ||
3844 | 953 | return size() == 0u; | ||
3845 | 954 | else | ||
3846 | 955 | return false; | ||
3847 | 956 | } | ||
3848 | 957 | |||
3849 | 958 | |||
3850 | 959 | bool | ||
3851 | 960 | Value::operator!() const | ||
3852 | 961 | { | ||
3853 | 962 | return isNull(); | ||
3854 | 963 | } | ||
3855 | 964 | |||
3856 | 965 | |||
3857 | 966 | void | ||
3858 | 967 | Value::clear() | ||
3859 | 968 | { | ||
3860 | 969 | JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); | ||
3861 | 970 | |||
3862 | 971 | switch ( type_ ) | ||
3863 | 972 | { | ||
3864 | 973 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3865 | 974 | case arrayValue: | ||
3866 | 975 | case objectValue: | ||
3867 | 976 | value_.map_->clear(); | ||
3868 | 977 | break; | ||
3869 | 978 | #else | ||
3870 | 979 | case arrayValue: | ||
3871 | 980 | value_.array_->clear(); | ||
3872 | 981 | break; | ||
3873 | 982 | case objectValue: | ||
3874 | 983 | value_.map_->clear(); | ||
3875 | 984 | break; | ||
3876 | 985 | #endif | ||
3877 | 986 | default: | ||
3878 | 987 | break; | ||
3879 | 988 | } | ||
3880 | 989 | } | ||
3881 | 990 | |||
3882 | 991 | void | ||
3883 | 992 | Value::resize( UInt newSize ) | ||
3884 | 993 | { | ||
3885 | 994 | JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); | ||
3886 | 995 | if ( type_ == nullValue ) | ||
3887 | 996 | *this = Value( arrayValue ); | ||
3888 | 997 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3889 | 998 | UInt oldSize = size(); | ||
3890 | 999 | if ( newSize == 0 ) | ||
3891 | 1000 | clear(); | ||
3892 | 1001 | else if ( newSize > oldSize ) | ||
3893 | 1002 | (*this)[ newSize - 1 ]; | ||
3894 | 1003 | else | ||
3895 | 1004 | { | ||
3896 | 1005 | for ( UInt index = newSize; index < oldSize; ++index ) | ||
3897 | 1006 | value_.map_->erase( index ); | ||
3898 | 1007 | assert( size() == newSize ); | ||
3899 | 1008 | } | ||
3900 | 1009 | #else | ||
3901 | 1010 | value_.array_->resize( newSize ); | ||
3902 | 1011 | #endif | ||
3903 | 1012 | } | ||
3904 | 1013 | |||
3905 | 1014 | |||
3906 | 1015 | Value & | ||
3907 | 1016 | Value::operator[]( UInt index ) | ||
3908 | 1017 | { | ||
3909 | 1018 | JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); | ||
3910 | 1019 | if ( type_ == nullValue ) | ||
3911 | 1020 | *this = Value( arrayValue ); | ||
3912 | 1021 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3913 | 1022 | CZString key( index ); | ||
3914 | 1023 | ObjectValues::iterator it = value_.map_->lower_bound( key ); | ||
3915 | 1024 | if ( it != value_.map_->end() && (*it).first == key ) | ||
3916 | 1025 | return (*it).second; | ||
3917 | 1026 | |||
3918 | 1027 | ObjectValues::value_type defaultValue( key, null ); | ||
3919 | 1028 | it = value_.map_->insert( it, defaultValue ); | ||
3920 | 1029 | return (*it).second; | ||
3921 | 1030 | #else | ||
3922 | 1031 | return value_.array_->resolveReference( index ); | ||
3923 | 1032 | #endif | ||
3924 | 1033 | } | ||
3925 | 1034 | |||
3926 | 1035 | |||
3927 | 1036 | const Value & | ||
3928 | 1037 | Value::operator[]( UInt index ) const | ||
3929 | 1038 | { | ||
3930 | 1039 | JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); | ||
3931 | 1040 | if ( type_ == nullValue ) | ||
3932 | 1041 | return null; | ||
3933 | 1042 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3934 | 1043 | CZString key( index ); | ||
3935 | 1044 | ObjectValues::const_iterator it = value_.map_->find( key ); | ||
3936 | 1045 | if ( it == value_.map_->end() ) | ||
3937 | 1046 | return null; | ||
3938 | 1047 | return (*it).second; | ||
3939 | 1048 | #else | ||
3940 | 1049 | Value *value = value_.array_->find( index ); | ||
3941 | 1050 | return value ? *value : null; | ||
3942 | 1051 | #endif | ||
3943 | 1052 | } | ||
3944 | 1053 | |||
3945 | 1054 | |||
3946 | 1055 | Value & | ||
3947 | 1056 | Value::operator[]( const char *key ) | ||
3948 | 1057 | { | ||
3949 | 1058 | return resolveReference( key, false ); | ||
3950 | 1059 | } | ||
3951 | 1060 | |||
3952 | 1061 | |||
3953 | 1062 | Value & | ||
3954 | 1063 | Value::resolveReference( const char *key, | ||
3955 | 1064 | bool isStatic ) | ||
3956 | 1065 | { | ||
3957 | 1066 | JSON_ASSERT( type_ == nullValue || type_ == objectValue ); | ||
3958 | 1067 | if ( type_ == nullValue ) | ||
3959 | 1068 | *this = Value( objectValue ); | ||
3960 | 1069 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
3961 | 1070 | CZString actualKey( key, isStatic ? CZString::noDuplication | ||
3962 | 1071 | : CZString::duplicateOnCopy ); | ||
3963 | 1072 | ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); | ||
3964 | 1073 | if ( it != value_.map_->end() && (*it).first == actualKey ) | ||
3965 | 1074 | return (*it).second; | ||
3966 | 1075 | |||
3967 | 1076 | ObjectValues::value_type defaultValue( actualKey, null ); | ||
3968 | 1077 | it = value_.map_->insert( it, defaultValue ); | ||
3969 | 1078 | Value &value = (*it).second; | ||
3970 | 1079 | return value; | ||
3971 | 1080 | #else | ||
3972 | 1081 | return value_.map_->resolveReference( key, isStatic ); | ||
3973 | 1082 | #endif | ||
3974 | 1083 | } | ||
3975 | 1084 | |||
3976 | 1085 | |||
3977 | 1086 | Value | ||
3978 | 1087 | Value::get( UInt index, | ||
3979 | 1088 | const Value &defaultValue ) const | ||
3980 | 1089 | { | ||
3981 | 1090 | const Value *value = &((*this)[index]); | ||
3982 | 1091 | return value == &null ? defaultValue : *value; | ||
3983 | 1092 | } | ||
3984 | 1093 | |||
3985 | 1094 | |||
3986 | 1095 | bool | ||
3987 | 1096 | Value::isValidIndex( UInt index ) const | ||
3988 | 1097 | { | ||
3989 | 1098 | return index < size(); | ||
3990 | 1099 | } | ||
3991 | 1100 | |||
3992 | 1101 | |||
3993 | 1102 | |||
3994 | 1103 | const Value & | ||
3995 | 1104 | Value::operator[]( const char *key ) const | ||
3996 | 1105 | { | ||
3997 | 1106 | JSON_ASSERT( type_ == nullValue || type_ == objectValue ); | ||
3998 | 1107 | if ( type_ == nullValue ) | ||
3999 | 1108 | return null; | ||
4000 | 1109 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4001 | 1110 | CZString actualKey( key, CZString::noDuplication ); | ||
4002 | 1111 | ObjectValues::const_iterator it = value_.map_->find( actualKey ); | ||
4003 | 1112 | if ( it == value_.map_->end() ) | ||
4004 | 1113 | return null; | ||
4005 | 1114 | return (*it).second; | ||
4006 | 1115 | #else | ||
4007 | 1116 | const Value *value = value_.map_->find( key ); | ||
4008 | 1117 | return value ? *value : null; | ||
4009 | 1118 | #endif | ||
4010 | 1119 | } | ||
4011 | 1120 | |||
4012 | 1121 | |||
4013 | 1122 | Value & | ||
4014 | 1123 | Value::operator[]( const std::string &key ) | ||
4015 | 1124 | { | ||
4016 | 1125 | return (*this)[ key.c_str() ]; | ||
4017 | 1126 | } | ||
4018 | 1127 | |||
4019 | 1128 | |||
4020 | 1129 | const Value & | ||
4021 | 1130 | Value::operator[]( const std::string &key ) const | ||
4022 | 1131 | { | ||
4023 | 1132 | return (*this)[ key.c_str() ]; | ||
4024 | 1133 | } | ||
4025 | 1134 | |||
4026 | 1135 | Value & | ||
4027 | 1136 | Value::operator[]( const StaticString &key ) | ||
4028 | 1137 | { | ||
4029 | 1138 | return resolveReference( key, true ); | ||
4030 | 1139 | } | ||
4031 | 1140 | |||
4032 | 1141 | |||
4033 | 1142 | # ifdef JSON_USE_CPPTL | ||
4034 | 1143 | Value & | ||
4035 | 1144 | Value::operator[]( const CppTL::ConstString &key ) | ||
4036 | 1145 | { | ||
4037 | 1146 | return (*this)[ key.c_str() ]; | ||
4038 | 1147 | } | ||
4039 | 1148 | |||
4040 | 1149 | |||
4041 | 1150 | const Value & | ||
4042 | 1151 | Value::operator[]( const CppTL::ConstString &key ) const | ||
4043 | 1152 | { | ||
4044 | 1153 | return (*this)[ key.c_str() ]; | ||
4045 | 1154 | } | ||
4046 | 1155 | # endif | ||
4047 | 1156 | |||
4048 | 1157 | |||
4049 | 1158 | Value & | ||
4050 | 1159 | Value::append( const Value &value ) | ||
4051 | 1160 | { | ||
4052 | 1161 | return (*this)[size()] = value; | ||
4053 | 1162 | } | ||
4054 | 1163 | |||
4055 | 1164 | |||
4056 | 1165 | Value | ||
4057 | 1166 | Value::get( const char *key, | ||
4058 | 1167 | const Value &defaultValue ) const | ||
4059 | 1168 | { | ||
4060 | 1169 | const Value *value = &((*this)[key]); | ||
4061 | 1170 | return value == &null ? defaultValue : *value; | ||
4062 | 1171 | } | ||
4063 | 1172 | |||
4064 | 1173 | |||
4065 | 1174 | Value | ||
4066 | 1175 | Value::get( const std::string &key, | ||
4067 | 1176 | const Value &defaultValue ) const | ||
4068 | 1177 | { | ||
4069 | 1178 | return get( key.c_str(), defaultValue ); | ||
4070 | 1179 | } | ||
4071 | 1180 | |||
4072 | 1181 | Value | ||
4073 | 1182 | Value::removeMember( const char* key ) | ||
4074 | 1183 | { | ||
4075 | 1184 | JSON_ASSERT( type_ == nullValue || type_ == objectValue ); | ||
4076 | 1185 | if ( type_ == nullValue ) | ||
4077 | 1186 | return null; | ||
4078 | 1187 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4079 | 1188 | CZString actualKey( key, CZString::noDuplication ); | ||
4080 | 1189 | ObjectValues::iterator it = value_.map_->find( actualKey ); | ||
4081 | 1190 | if ( it == value_.map_->end() ) | ||
4082 | 1191 | return null; | ||
4083 | 1192 | Value old(it->second); | ||
4084 | 1193 | value_.map_->erase(it); | ||
4085 | 1194 | return old; | ||
4086 | 1195 | #else | ||
4087 | 1196 | Value *value = value_.map_->find( key ); | ||
4088 | 1197 | if (value){ | ||
4089 | 1198 | Value old(*value); | ||
4090 | 1199 | value_.map_.remove( key ); | ||
4091 | 1200 | return old; | ||
4092 | 1201 | } else { | ||
4093 | 1202 | return null; | ||
4094 | 1203 | } | ||
4095 | 1204 | #endif | ||
4096 | 1205 | } | ||
4097 | 1206 | |||
4098 | 1207 | Value | ||
4099 | 1208 | Value::removeMember( const std::string &key ) | ||
4100 | 1209 | { | ||
4101 | 1210 | return removeMember( key.c_str() ); | ||
4102 | 1211 | } | ||
4103 | 1212 | |||
4104 | 1213 | # ifdef JSON_USE_CPPTL | ||
4105 | 1214 | Value | ||
4106 | 1215 | Value::get( const CppTL::ConstString &key, | ||
4107 | 1216 | const Value &defaultValue ) const | ||
4108 | 1217 | { | ||
4109 | 1218 | return get( key.c_str(), defaultValue ); | ||
4110 | 1219 | } | ||
4111 | 1220 | # endif | ||
4112 | 1221 | |||
4113 | 1222 | bool | ||
4114 | 1223 | Value::isMember( const char *key ) const | ||
4115 | 1224 | { | ||
4116 | 1225 | const Value *value = &((*this)[key]); | ||
4117 | 1226 | return value != &null; | ||
4118 | 1227 | } | ||
4119 | 1228 | |||
4120 | 1229 | |||
4121 | 1230 | bool | ||
4122 | 1231 | Value::isMember( const std::string &key ) const | ||
4123 | 1232 | { | ||
4124 | 1233 | return isMember( key.c_str() ); | ||
4125 | 1234 | } | ||
4126 | 1235 | |||
4127 | 1236 | |||
4128 | 1237 | # ifdef JSON_USE_CPPTL | ||
4129 | 1238 | bool | ||
4130 | 1239 | Value::isMember( const CppTL::ConstString &key ) const | ||
4131 | 1240 | { | ||
4132 | 1241 | return isMember( key.c_str() ); | ||
4133 | 1242 | } | ||
4134 | 1243 | #endif | ||
4135 | 1244 | |||
4136 | 1245 | Value::Members | ||
4137 | 1246 | Value::getMemberNames() const | ||
4138 | 1247 | { | ||
4139 | 1248 | JSON_ASSERT( type_ == nullValue || type_ == objectValue ); | ||
4140 | 1249 | if ( type_ == nullValue ) | ||
4141 | 1250 | return Value::Members(); | ||
4142 | 1251 | Members members; | ||
4143 | 1252 | members.reserve( value_.map_->size() ); | ||
4144 | 1253 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4145 | 1254 | ObjectValues::const_iterator it = value_.map_->begin(); | ||
4146 | 1255 | ObjectValues::const_iterator itEnd = value_.map_->end(); | ||
4147 | 1256 | for ( ; it != itEnd; ++it ) | ||
4148 | 1257 | members.push_back( std::string( (*it).first.c_str() ) ); | ||
4149 | 1258 | #else | ||
4150 | 1259 | ValueInternalMap::IteratorState it; | ||
4151 | 1260 | ValueInternalMap::IteratorState itEnd; | ||
4152 | 1261 | value_.map_->makeBeginIterator( it ); | ||
4153 | 1262 | value_.map_->makeEndIterator( itEnd ); | ||
4154 | 1263 | for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) | ||
4155 | 1264 | members.push_back( std::string( ValueInternalMap::key( it ) ) ); | ||
4156 | 1265 | #endif | ||
4157 | 1266 | return members; | ||
4158 | 1267 | } | ||
4159 | 1268 | // | ||
4160 | 1269 | //# ifdef JSON_USE_CPPTL | ||
4161 | 1270 | //EnumMemberNames | ||
4162 | 1271 | //Value::enumMemberNames() const | ||
4163 | 1272 | //{ | ||
4164 | 1273 | // if ( type_ == objectValue ) | ||
4165 | 1274 | // { | ||
4166 | 1275 | // return CppTL::Enum::any( CppTL::Enum::transform( | ||
4167 | 1276 | // CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ), | ||
4168 | 1277 | // MemberNamesTransform() ) ); | ||
4169 | 1278 | // } | ||
4170 | 1279 | // return EnumMemberNames(); | ||
4171 | 1280 | //} | ||
4172 | 1281 | // | ||
4173 | 1282 | // | ||
4174 | 1283 | //EnumValues | ||
4175 | 1284 | //Value::enumValues() const | ||
4176 | 1285 | //{ | ||
4177 | 1286 | // if ( type_ == objectValue || type_ == arrayValue ) | ||
4178 | 1287 | // return CppTL::Enum::anyValues( *(value_.map_), | ||
4179 | 1288 | // CppTL::Type<const Value &>() ); | ||
4180 | 1289 | // return EnumValues(); | ||
4181 | 1290 | //} | ||
4182 | 1291 | // | ||
4183 | 1292 | //# endif | ||
4184 | 1293 | |||
4185 | 1294 | |||
4186 | 1295 | bool | ||
4187 | 1296 | Value::isNull() const | ||
4188 | 1297 | { | ||
4189 | 1298 | return type_ == nullValue; | ||
4190 | 1299 | } | ||
4191 | 1300 | |||
4192 | 1301 | |||
4193 | 1302 | bool | ||
4194 | 1303 | Value::isBool() const | ||
4195 | 1304 | { | ||
4196 | 1305 | return type_ == booleanValue; | ||
4197 | 1306 | } | ||
4198 | 1307 | |||
4199 | 1308 | |||
4200 | 1309 | bool | ||
4201 | 1310 | Value::isInt() const | ||
4202 | 1311 | { | ||
4203 | 1312 | return type_ == intValue; | ||
4204 | 1313 | } | ||
4205 | 1314 | |||
4206 | 1315 | |||
4207 | 1316 | bool | ||
4208 | 1317 | Value::isUInt() const | ||
4209 | 1318 | { | ||
4210 | 1319 | return type_ == uintValue; | ||
4211 | 1320 | } | ||
4212 | 1321 | |||
4213 | 1322 | |||
4214 | 1323 | bool | ||
4215 | 1324 | Value::isIntegral() const | ||
4216 | 1325 | { | ||
4217 | 1326 | return type_ == intValue | ||
4218 | 1327 | || type_ == uintValue | ||
4219 | 1328 | || type_ == booleanValue; | ||
4220 | 1329 | } | ||
4221 | 1330 | |||
4222 | 1331 | |||
4223 | 1332 | bool | ||
4224 | 1333 | Value::isDouble() const | ||
4225 | 1334 | { | ||
4226 | 1335 | return type_ == realValue; | ||
4227 | 1336 | } | ||
4228 | 1337 | |||
4229 | 1338 | |||
4230 | 1339 | bool | ||
4231 | 1340 | Value::isNumeric() const | ||
4232 | 1341 | { | ||
4233 | 1342 | return isIntegral() || isDouble(); | ||
4234 | 1343 | } | ||
4235 | 1344 | |||
4236 | 1345 | |||
4237 | 1346 | bool | ||
4238 | 1347 | Value::isString() const | ||
4239 | 1348 | { | ||
4240 | 1349 | return type_ == stringValue; | ||
4241 | 1350 | } | ||
4242 | 1351 | |||
4243 | 1352 | |||
4244 | 1353 | bool | ||
4245 | 1354 | Value::isArray() const | ||
4246 | 1355 | { | ||
4247 | 1356 | return type_ == nullValue || type_ == arrayValue; | ||
4248 | 1357 | } | ||
4249 | 1358 | |||
4250 | 1359 | |||
4251 | 1360 | bool | ||
4252 | 1361 | Value::isObject() const | ||
4253 | 1362 | { | ||
4254 | 1363 | return type_ == nullValue || type_ == objectValue; | ||
4255 | 1364 | } | ||
4256 | 1365 | |||
4257 | 1366 | |||
4258 | 1367 | void | ||
4259 | 1368 | Value::setComment( const char *comment, | ||
4260 | 1369 | CommentPlacement placement ) | ||
4261 | 1370 | { | ||
4262 | 1371 | if ( !comments_ ) | ||
4263 | 1372 | comments_ = new CommentInfo[numberOfCommentPlacement]; | ||
4264 | 1373 | comments_[placement].setComment( comment ); | ||
4265 | 1374 | } | ||
4266 | 1375 | |||
4267 | 1376 | |||
4268 | 1377 | void | ||
4269 | 1378 | Value::setComment( const std::string &comment, | ||
4270 | 1379 | CommentPlacement placement ) | ||
4271 | 1380 | { | ||
4272 | 1381 | setComment( comment.c_str(), placement ); | ||
4273 | 1382 | } | ||
4274 | 1383 | |||
4275 | 1384 | |||
4276 | 1385 | bool | ||
4277 | 1386 | Value::hasComment( CommentPlacement placement ) const | ||
4278 | 1387 | { | ||
4279 | 1388 | return comments_ != 0 && comments_[placement].comment_ != 0; | ||
4280 | 1389 | } | ||
4281 | 1390 | |||
4282 | 1391 | std::string | ||
4283 | 1392 | Value::getComment( CommentPlacement placement ) const | ||
4284 | 1393 | { | ||
4285 | 1394 | if ( hasComment(placement) ) | ||
4286 | 1395 | return comments_[placement].comment_; | ||
4287 | 1396 | return ""; | ||
4288 | 1397 | } | ||
4289 | 1398 | |||
4290 | 1399 | |||
4291 | 1400 | std::string | ||
4292 | 1401 | Value::toStyledString() const | ||
4293 | 1402 | { | ||
4294 | 1403 | StyledWriter writer; | ||
4295 | 1404 | return writer.write( *this ); | ||
4296 | 1405 | } | ||
4297 | 1406 | |||
4298 | 1407 | |||
4299 | 1408 | Value::const_iterator | ||
4300 | 1409 | Value::begin() const | ||
4301 | 1410 | { | ||
4302 | 1411 | switch ( type_ ) | ||
4303 | 1412 | { | ||
4304 | 1413 | #ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
4305 | 1414 | case arrayValue: | ||
4306 | 1415 | if ( value_.array_ ) | ||
4307 | 1416 | { | ||
4308 | 1417 | ValueInternalArray::IteratorState it; | ||
4309 | 1418 | value_.array_->makeBeginIterator( it ); | ||
4310 | 1419 | return const_iterator( it ); | ||
4311 | 1420 | } | ||
4312 | 1421 | break; | ||
4313 | 1422 | case objectValue: | ||
4314 | 1423 | if ( value_.map_ ) | ||
4315 | 1424 | { | ||
4316 | 1425 | ValueInternalMap::IteratorState it; | ||
4317 | 1426 | value_.map_->makeBeginIterator( it ); | ||
4318 | 1427 | return const_iterator( it ); | ||
4319 | 1428 | } | ||
4320 | 1429 | break; | ||
4321 | 1430 | #else | ||
4322 | 1431 | case arrayValue: | ||
4323 | 1432 | case objectValue: | ||
4324 | 1433 | if ( value_.map_ ) | ||
4325 | 1434 | return const_iterator( value_.map_->begin() ); | ||
4326 | 1435 | break; | ||
4327 | 1436 | #endif | ||
4328 | 1437 | default: | ||
4329 | 1438 | break; | ||
4330 | 1439 | } | ||
4331 | 1440 | return const_iterator(); | ||
4332 | 1441 | } | ||
4333 | 1442 | |||
4334 | 1443 | Value::const_iterator | ||
4335 | 1444 | Value::end() const | ||
4336 | 1445 | { | ||
4337 | 1446 | switch ( type_ ) | ||
4338 | 1447 | { | ||
4339 | 1448 | #ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
4340 | 1449 | case arrayValue: | ||
4341 | 1450 | if ( value_.array_ ) | ||
4342 | 1451 | { | ||
4343 | 1452 | ValueInternalArray::IteratorState it; | ||
4344 | 1453 | value_.array_->makeEndIterator( it ); | ||
4345 | 1454 | return const_iterator( it ); | ||
4346 | 1455 | } | ||
4347 | 1456 | break; | ||
4348 | 1457 | case objectValue: | ||
4349 | 1458 | if ( value_.map_ ) | ||
4350 | 1459 | { | ||
4351 | 1460 | ValueInternalMap::IteratorState it; | ||
4352 | 1461 | value_.map_->makeEndIterator( it ); | ||
4353 | 1462 | return const_iterator( it ); | ||
4354 | 1463 | } | ||
4355 | 1464 | break; | ||
4356 | 1465 | #else | ||
4357 | 1466 | case arrayValue: | ||
4358 | 1467 | case objectValue: | ||
4359 | 1468 | if ( value_.map_ ) | ||
4360 | 1469 | return const_iterator( value_.map_->end() ); | ||
4361 | 1470 | break; | ||
4362 | 1471 | #endif | ||
4363 | 1472 | default: | ||
4364 | 1473 | break; | ||
4365 | 1474 | } | ||
4366 | 1475 | return const_iterator(); | ||
4367 | 1476 | } | ||
4368 | 1477 | |||
4369 | 1478 | |||
4370 | 1479 | Value::iterator | ||
4371 | 1480 | Value::begin() | ||
4372 | 1481 | { | ||
4373 | 1482 | switch ( type_ ) | ||
4374 | 1483 | { | ||
4375 | 1484 | #ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
4376 | 1485 | case arrayValue: | ||
4377 | 1486 | if ( value_.array_ ) | ||
4378 | 1487 | { | ||
4379 | 1488 | ValueInternalArray::IteratorState it; | ||
4380 | 1489 | value_.array_->makeBeginIterator( it ); | ||
4381 | 1490 | return iterator( it ); | ||
4382 | 1491 | } | ||
4383 | 1492 | break; | ||
4384 | 1493 | case objectValue: | ||
4385 | 1494 | if ( value_.map_ ) | ||
4386 | 1495 | { | ||
4387 | 1496 | ValueInternalMap::IteratorState it; | ||
4388 | 1497 | value_.map_->makeBeginIterator( it ); | ||
4389 | 1498 | return iterator( it ); | ||
4390 | 1499 | } | ||
4391 | 1500 | break; | ||
4392 | 1501 | #else | ||
4393 | 1502 | case arrayValue: | ||
4394 | 1503 | case objectValue: | ||
4395 | 1504 | if ( value_.map_ ) | ||
4396 | 1505 | return iterator( value_.map_->begin() ); | ||
4397 | 1506 | break; | ||
4398 | 1507 | #endif | ||
4399 | 1508 | default: | ||
4400 | 1509 | break; | ||
4401 | 1510 | } | ||
4402 | 1511 | return iterator(); | ||
4403 | 1512 | } | ||
4404 | 1513 | |||
4405 | 1514 | Value::iterator | ||
4406 | 1515 | Value::end() | ||
4407 | 1516 | { | ||
4408 | 1517 | switch ( type_ ) | ||
4409 | 1518 | { | ||
4410 | 1519 | #ifdef JSON_VALUE_USE_INTERNAL_MAP | ||
4411 | 1520 | case arrayValue: | ||
4412 | 1521 | if ( value_.array_ ) | ||
4413 | 1522 | { | ||
4414 | 1523 | ValueInternalArray::IteratorState it; | ||
4415 | 1524 | value_.array_->makeEndIterator( it ); | ||
4416 | 1525 | return iterator( it ); | ||
4417 | 1526 | } | ||
4418 | 1527 | break; | ||
4419 | 1528 | case objectValue: | ||
4420 | 1529 | if ( value_.map_ ) | ||
4421 | 1530 | { | ||
4422 | 1531 | ValueInternalMap::IteratorState it; | ||
4423 | 1532 | value_.map_->makeEndIterator( it ); | ||
4424 | 1533 | return iterator( it ); | ||
4425 | 1534 | } | ||
4426 | 1535 | break; | ||
4427 | 1536 | #else | ||
4428 | 1537 | case arrayValue: | ||
4429 | 1538 | case objectValue: | ||
4430 | 1539 | if ( value_.map_ ) | ||
4431 | 1540 | return iterator( value_.map_->end() ); | ||
4432 | 1541 | break; | ||
4433 | 1542 | #endif | ||
4434 | 1543 | default: | ||
4435 | 1544 | break; | ||
4436 | 1545 | } | ||
4437 | 1546 | return iterator(); | ||
4438 | 1547 | } | ||
4439 | 1548 | |||
4440 | 1549 | |||
4441 | 1550 | // class PathArgument | ||
4442 | 1551 | // ////////////////////////////////////////////////////////////////// | ||
4443 | 1552 | |||
4444 | 1553 | PathArgument::PathArgument() | ||
4445 | 1554 | : kind_( kindNone ) | ||
4446 | 1555 | { | ||
4447 | 1556 | } | ||
4448 | 1557 | |||
4449 | 1558 | |||
4450 | 1559 | PathArgument::PathArgument( Value::UInt index ) | ||
4451 | 1560 | : index_( index ) | ||
4452 | 1561 | , kind_( kindIndex ) | ||
4453 | 1562 | { | ||
4454 | 1563 | } | ||
4455 | 1564 | |||
4456 | 1565 | |||
4457 | 1566 | PathArgument::PathArgument( const char *key ) | ||
4458 | 1567 | : key_( key ) | ||
4459 | 1568 | , kind_( kindKey ) | ||
4460 | 1569 | { | ||
4461 | 1570 | } | ||
4462 | 1571 | |||
4463 | 1572 | |||
4464 | 1573 | PathArgument::PathArgument( const std::string &key ) | ||
4465 | 1574 | : key_( key.c_str() ) | ||
4466 | 1575 | , kind_( kindKey ) | ||
4467 | 1576 | { | ||
4468 | 1577 | } | ||
4469 | 1578 | |||
4470 | 1579 | // class Path | ||
4471 | 1580 | // ////////////////////////////////////////////////////////////////// | ||
4472 | 1581 | |||
4473 | 1582 | Path::Path( const std::string &path, | ||
4474 | 1583 | const PathArgument &a1, | ||
4475 | 1584 | const PathArgument &a2, | ||
4476 | 1585 | const PathArgument &a3, | ||
4477 | 1586 | const PathArgument &a4, | ||
4478 | 1587 | const PathArgument &a5 ) | ||
4479 | 1588 | { | ||
4480 | 1589 | InArgs in; | ||
4481 | 1590 | in.push_back( &a1 ); | ||
4482 | 1591 | in.push_back( &a2 ); | ||
4483 | 1592 | in.push_back( &a3 ); | ||
4484 | 1593 | in.push_back( &a4 ); | ||
4485 | 1594 | in.push_back( &a5 ); | ||
4486 | 1595 | makePath( path, in ); | ||
4487 | 1596 | } | ||
4488 | 1597 | |||
4489 | 1598 | |||
4490 | 1599 | void | ||
4491 | 1600 | Path::makePath( const std::string &path, | ||
4492 | 1601 | const InArgs &in ) | ||
4493 | 1602 | { | ||
4494 | 1603 | const char *current = path.c_str(); | ||
4495 | 1604 | const char *end = current + path.length(); | ||
4496 | 1605 | InArgs::const_iterator itInArg = in.begin(); | ||
4497 | 1606 | while ( current != end ) | ||
4498 | 1607 | { | ||
4499 | 1608 | if ( *current == '[' ) | ||
4500 | 1609 | { | ||
4501 | 1610 | ++current; | ||
4502 | 1611 | if ( *current == '%' ) | ||
4503 | 1612 | addPathInArg( path, in, itInArg, PathArgument::kindIndex ); | ||
4504 | 1613 | else | ||
4505 | 1614 | { | ||
4506 | 1615 | Value::UInt index = 0; | ||
4507 | 1616 | for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) | ||
4508 | 1617 | index = index * 10 + Value::UInt(*current - '0'); | ||
4509 | 1618 | args_.push_back( index ); | ||
4510 | 1619 | } | ||
4511 | 1620 | if ( current == end || *current++ != ']' ) | ||
4512 | 1621 | invalidPath( path, int(current - path.c_str()) ); | ||
4513 | 1622 | } | ||
4514 | 1623 | else if ( *current == '%' ) | ||
4515 | 1624 | { | ||
4516 | 1625 | addPathInArg( path, in, itInArg, PathArgument::kindKey ); | ||
4517 | 1626 | ++current; | ||
4518 | 1627 | } | ||
4519 | 1628 | else if ( *current == '.' ) | ||
4520 | 1629 | { | ||
4521 | 1630 | ++current; | ||
4522 | 1631 | } | ||
4523 | 1632 | else | ||
4524 | 1633 | { | ||
4525 | 1634 | const char *beginName = current; | ||
4526 | 1635 | while ( current != end && !strchr( "[.", *current ) ) | ||
4527 | 1636 | ++current; | ||
4528 | 1637 | args_.push_back( std::string( beginName, current ) ); | ||
4529 | 1638 | } | ||
4530 | 1639 | } | ||
4531 | 1640 | } | ||
4532 | 1641 | |||
4533 | 1642 | |||
4534 | 1643 | void | ||
4535 | 1644 | Path::addPathInArg( const std::string &, | ||
4536 | 1645 | const InArgs &in, | ||
4537 | 1646 | InArgs::const_iterator &itInArg, | ||
4538 | 1647 | PathArgument::Kind kind ) | ||
4539 | 1648 | { | ||
4540 | 1649 | if ( itInArg == in.end() ) | ||
4541 | 1650 | { | ||
4542 | 1651 | // Error: missing argument %d | ||
4543 | 1652 | } | ||
4544 | 1653 | else if ( (*itInArg)->kind_ != kind ) | ||
4545 | 1654 | { | ||
4546 | 1655 | // Error: bad argument type | ||
4547 | 1656 | } | ||
4548 | 1657 | else | ||
4549 | 1658 | { | ||
4550 | 1659 | args_.push_back( **itInArg ); | ||
4551 | 1660 | } | ||
4552 | 1661 | } | ||
4553 | 1662 | |||
4554 | 1663 | |||
4555 | 1664 | void | ||
4556 | 1665 | Path::invalidPath( const std::string &, | ||
4557 | 1666 | int ) | ||
4558 | 1667 | { | ||
4559 | 1668 | // Error: invalid path. | ||
4560 | 1669 | } | ||
4561 | 1670 | |||
4562 | 1671 | |||
4563 | 1672 | const Value & | ||
4564 | 1673 | Path::resolve( const Value &root ) const | ||
4565 | 1674 | { | ||
4566 | 1675 | const Value *node = &root; | ||
4567 | 1676 | for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) | ||
4568 | 1677 | { | ||
4569 | 1678 | const PathArgument &arg = *it; | ||
4570 | 1679 | if ( arg.kind_ == PathArgument::kindIndex ) | ||
4571 | 1680 | { | ||
4572 | 1681 | if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) | ||
4573 | 1682 | { | ||
4574 | 1683 | // Error: unable to resolve path (array value expected at position... | ||
4575 | 1684 | } | ||
4576 | 1685 | node = &((*node)[arg.index_]); | ||
4577 | 1686 | } | ||
4578 | 1687 | else if ( arg.kind_ == PathArgument::kindKey ) | ||
4579 | 1688 | { | ||
4580 | 1689 | if ( !node->isObject() ) | ||
4581 | 1690 | { | ||
4582 | 1691 | // Error: unable to resolve path (object value expected at position...) | ||
4583 | 1692 | } | ||
4584 | 1693 | node = &((*node)[arg.key_]); | ||
4585 | 1694 | if ( node == &Value::null ) | ||
4586 | 1695 | { | ||
4587 | 1696 | // Error: unable to resolve path (object has no member named '' at position...) | ||
4588 | 1697 | } | ||
4589 | 1698 | } | ||
4590 | 1699 | } | ||
4591 | 1700 | return *node; | ||
4592 | 1701 | } | ||
4593 | 1702 | |||
4594 | 1703 | |||
4595 | 1704 | Value | ||
4596 | 1705 | Path::resolve( const Value &root, | ||
4597 | 1706 | const Value &defaultValue ) const | ||
4598 | 1707 | { | ||
4599 | 1708 | const Value *node = &root; | ||
4600 | 1709 | for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) | ||
4601 | 1710 | { | ||
4602 | 1711 | const PathArgument &arg = *it; | ||
4603 | 1712 | if ( arg.kind_ == PathArgument::kindIndex ) | ||
4604 | 1713 | { | ||
4605 | 1714 | if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) | ||
4606 | 1715 | return defaultValue; | ||
4607 | 1716 | node = &((*node)[arg.index_]); | ||
4608 | 1717 | } | ||
4609 | 1718 | else if ( arg.kind_ == PathArgument::kindKey ) | ||
4610 | 1719 | { | ||
4611 | 1720 | if ( !node->isObject() ) | ||
4612 | 1721 | return defaultValue; | ||
4613 | 1722 | node = &((*node)[arg.key_]); | ||
4614 | 1723 | if ( node == &Value::null ) | ||
4615 | 1724 | return defaultValue; | ||
4616 | 1725 | } | ||
4617 | 1726 | } | ||
4618 | 1727 | return *node; | ||
4619 | 1728 | } | ||
4620 | 1729 | |||
4621 | 1730 | |||
4622 | 1731 | Value & | ||
4623 | 1732 | Path::make( Value &root ) const | ||
4624 | 1733 | { | ||
4625 | 1734 | Value *node = &root; | ||
4626 | 1735 | for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) | ||
4627 | 1736 | { | ||
4628 | 1737 | const PathArgument &arg = *it; | ||
4629 | 1738 | if ( arg.kind_ == PathArgument::kindIndex ) | ||
4630 | 1739 | { | ||
4631 | 1740 | if ( !node->isArray() ) | ||
4632 | 1741 | { | ||
4633 | 1742 | // Error: node is not an array at position ... | ||
4634 | 1743 | } | ||
4635 | 1744 | node = &((*node)[arg.index_]); | ||
4636 | 1745 | } | ||
4637 | 1746 | else if ( arg.kind_ == PathArgument::kindKey ) | ||
4638 | 1747 | { | ||
4639 | 1748 | if ( !node->isObject() ) | ||
4640 | 1749 | { | ||
4641 | 1750 | // Error: node is not an object at position... | ||
4642 | 1751 | } | ||
4643 | 1752 | node = &((*node)[arg.key_]); | ||
4644 | 1753 | } | ||
4645 | 1754 | } | ||
4646 | 1755 | return *node; | ||
4647 | 1756 | } | ||
4648 | 1757 | |||
4649 | 1758 | |||
4650 | 1759 | } // namespace Json | ||
4651 | 0 | 1760 | ||
4652 | === added file 'plugin/json_server/json/json_valueiterator.inl' | |||
4653 | --- plugin/json_server/json/json_valueiterator.inl 1970-01-01 00:00:00 +0000 | |||
4654 | +++ plugin/json_server/json/json_valueiterator.inl 2011-05-04 01:52:37 +0000 | |||
4655 | @@ -0,0 +1,330 @@ | |||
4656 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
4657 | 2 | * | ||
4658 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
4659 | 4 | * | ||
4660 | 5 | * Copyright (C) 2011 Stewart Smith | ||
4661 | 6 | * All rights reserved. | ||
4662 | 7 | * | ||
4663 | 8 | * Redistribution and use in source and binary forms, with or without | ||
4664 | 9 | * modification, are permitted provided that the following conditions are | ||
4665 | 10 | * met: | ||
4666 | 11 | * | ||
4667 | 12 | * * Redistributions of source code must retain the above copyright | ||
4668 | 13 | * notice, this list of conditions and the following disclaimer. | ||
4669 | 14 | * | ||
4670 | 15 | * * Redistributions in binary form must reproduce the above | ||
4671 | 16 | * copyright notice, this list of conditions and the following disclaimer | ||
4672 | 17 | * in the documentation and/or other materials provided with the | ||
4673 | 18 | * distribution. | ||
4674 | 19 | * | ||
4675 | 20 | * * The names of its contributors may not be used to endorse or | ||
4676 | 21 | * promote products derived from this software without specific prior | ||
4677 | 22 | * written permission. | ||
4678 | 23 | * | ||
4679 | 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
4680 | 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
4681 | 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
4682 | 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
4683 | 28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
4684 | 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
4685 | 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
4686 | 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
4687 | 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
4688 | 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
4689 | 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
4690 | 35 | * | ||
4691 | 36 | */ | ||
4692 | 37 | |||
4693 | 38 | #pragma once | ||
4694 | 39 | // included by json_value.cpp | ||
4695 | 40 | // everything is within Json namespace | ||
4696 | 41 | |||
4697 | 42 | |||
4698 | 43 | // ////////////////////////////////////////////////////////////////// | ||
4699 | 44 | // ////////////////////////////////////////////////////////////////// | ||
4700 | 45 | // ////////////////////////////////////////////////////////////////// | ||
4701 | 46 | // class ValueIteratorBase | ||
4702 | 47 | // ////////////////////////////////////////////////////////////////// | ||
4703 | 48 | // ////////////////////////////////////////////////////////////////// | ||
4704 | 49 | // ////////////////////////////////////////////////////////////////// | ||
4705 | 50 | |||
4706 | 51 | ValueIteratorBase::ValueIteratorBase() | ||
4707 | 52 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4708 | 53 | : current_() | ||
4709 | 54 | , isNull_( true ) | ||
4710 | 55 | { | ||
4711 | 56 | } | ||
4712 | 57 | #else | ||
4713 | 58 | : isArray_( true ) | ||
4714 | 59 | , isNull_( true ) | ||
4715 | 60 | { | ||
4716 | 61 | iterator_.array_ = ValueInternalArray::IteratorState(); | ||
4717 | 62 | } | ||
4718 | 63 | #endif | ||
4719 | 64 | |||
4720 | 65 | |||
4721 | 66 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4722 | 67 | ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) | ||
4723 | 68 | : current_( current ) | ||
4724 | 69 | , isNull_( false ) | ||
4725 | 70 | { | ||
4726 | 71 | } | ||
4727 | 72 | #else | ||
4728 | 73 | ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) | ||
4729 | 74 | : isArray_( true ) | ||
4730 | 75 | { | ||
4731 | 76 | iterator_.array_ = state; | ||
4732 | 77 | } | ||
4733 | 78 | |||
4734 | 79 | |||
4735 | 80 | ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) | ||
4736 | 81 | : isArray_( false ) | ||
4737 | 82 | { | ||
4738 | 83 | iterator_.map_ = state; | ||
4739 | 84 | } | ||
4740 | 85 | #endif | ||
4741 | 86 | |||
4742 | 87 | Value & | ||
4743 | 88 | ValueIteratorBase::deref() const | ||
4744 | 89 | { | ||
4745 | 90 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4746 | 91 | return current_->second; | ||
4747 | 92 | #else | ||
4748 | 93 | if ( isArray_ ) | ||
4749 | 94 | return ValueInternalArray::dereference( iterator_.array_ ); | ||
4750 | 95 | return ValueInternalMap::value( iterator_.map_ ); | ||
4751 | 96 | #endif | ||
4752 | 97 | } | ||
4753 | 98 | |||
4754 | 99 | |||
4755 | 100 | void | ||
4756 | 101 | ValueIteratorBase::increment() | ||
4757 | 102 | { | ||
4758 | 103 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4759 | 104 | ++current_; | ||
4760 | 105 | #else | ||
4761 | 106 | if ( isArray_ ) | ||
4762 | 107 | ValueInternalArray::increment( iterator_.array_ ); | ||
4763 | 108 | ValueInternalMap::increment( iterator_.map_ ); | ||
4764 | 109 | #endif | ||
4765 | 110 | } | ||
4766 | 111 | |||
4767 | 112 | |||
4768 | 113 | void | ||
4769 | 114 | ValueIteratorBase::decrement() | ||
4770 | 115 | { | ||
4771 | 116 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4772 | 117 | --current_; | ||
4773 | 118 | #else | ||
4774 | 119 | if ( isArray_ ) | ||
4775 | 120 | ValueInternalArray::decrement( iterator_.array_ ); | ||
4776 | 121 | ValueInternalMap::decrement( iterator_.map_ ); | ||
4777 | 122 | #endif | ||
4778 | 123 | } | ||
4779 | 124 | |||
4780 | 125 | |||
4781 | 126 | ValueIteratorBase::difference_type | ||
4782 | 127 | ValueIteratorBase::computeDistance( const SelfType &other ) const | ||
4783 | 128 | { | ||
4784 | 129 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4785 | 130 | # ifdef JSON_USE_CPPTL_SMALLMAP | ||
4786 | 131 | return current_ - other.current_; | ||
4787 | 132 | # else | ||
4788 | 133 | // Iterator for null value are initialized using the default | ||
4789 | 134 | // constructor, which initialize current_ to the default | ||
4790 | 135 | // std::map::iterator. As begin() and end() are two instance | ||
4791 | 136 | // of the default std::map::iterator, they can not be compared. | ||
4792 | 137 | // To allow this, we handle this comparison specifically. | ||
4793 | 138 | if ( isNull_ && other.isNull_ ) | ||
4794 | 139 | { | ||
4795 | 140 | return 0; | ||
4796 | 141 | } | ||
4797 | 142 | |||
4798 | 143 | |||
4799 | 144 | // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, | ||
4800 | 145 | // which is the one used by default). | ||
4801 | 146 | // Using a portable hand-made version for non random iterator instead: | ||
4802 | 147 | // return difference_type( std::distance( current_, other.current_ ) ); | ||
4803 | 148 | difference_type myDistance = 0; | ||
4804 | 149 | for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) | ||
4805 | 150 | { | ||
4806 | 151 | ++myDistance; | ||
4807 | 152 | } | ||
4808 | 153 | return myDistance; | ||
4809 | 154 | # endif | ||
4810 | 155 | #else | ||
4811 | 156 | if ( isArray_ ) | ||
4812 | 157 | return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); | ||
4813 | 158 | return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); | ||
4814 | 159 | #endif | ||
4815 | 160 | } | ||
4816 | 161 | |||
4817 | 162 | |||
4818 | 163 | bool | ||
4819 | 164 | ValueIteratorBase::isEqual( const SelfType &other ) const | ||
4820 | 165 | { | ||
4821 | 166 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4822 | 167 | if ( isNull_ ) | ||
4823 | 168 | { | ||
4824 | 169 | return other.isNull_; | ||
4825 | 170 | } | ||
4826 | 171 | return current_ == other.current_; | ||
4827 | 172 | #else | ||
4828 | 173 | if ( isArray_ ) | ||
4829 | 174 | return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); | ||
4830 | 175 | return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); | ||
4831 | 176 | #endif | ||
4832 | 177 | } | ||
4833 | 178 | |||
4834 | 179 | |||
4835 | 180 | void | ||
4836 | 181 | ValueIteratorBase::copy( const SelfType &other ) | ||
4837 | 182 | { | ||
4838 | 183 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4839 | 184 | current_ = other.current_; | ||
4840 | 185 | #else | ||
4841 | 186 | if ( isArray_ ) | ||
4842 | 187 | iterator_.array_ = other.iterator_.array_; | ||
4843 | 188 | iterator_.map_ = other.iterator_.map_; | ||
4844 | 189 | #endif | ||
4845 | 190 | } | ||
4846 | 191 | |||
4847 | 192 | |||
4848 | 193 | Value | ||
4849 | 194 | ValueIteratorBase::key() const | ||
4850 | 195 | { | ||
4851 | 196 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4852 | 197 | const Value::CZString czstring = (*current_).first; | ||
4853 | 198 | if ( czstring.c_str() ) | ||
4854 | 199 | { | ||
4855 | 200 | if ( czstring.isStaticString() ) | ||
4856 | 201 | return Value( StaticString( czstring.c_str() ) ); | ||
4857 | 202 | return Value( czstring.c_str() ); | ||
4858 | 203 | } | ||
4859 | 204 | return Value( czstring.index() ); | ||
4860 | 205 | #else | ||
4861 | 206 | if ( isArray_ ) | ||
4862 | 207 | return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); | ||
4863 | 208 | bool isStatic; | ||
4864 | 209 | const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); | ||
4865 | 210 | if ( isStatic ) | ||
4866 | 211 | return Value( StaticString( memberName ) ); | ||
4867 | 212 | return Value( memberName ); | ||
4868 | 213 | #endif | ||
4869 | 214 | } | ||
4870 | 215 | |||
4871 | 216 | |||
4872 | 217 | UInt | ||
4873 | 218 | ValueIteratorBase::index() const | ||
4874 | 219 | { | ||
4875 | 220 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4876 | 221 | const Value::CZString czstring = (*current_).first; | ||
4877 | 222 | if ( !czstring.c_str() ) | ||
4878 | 223 | return czstring.index(); | ||
4879 | 224 | return Value::UInt( -1 ); | ||
4880 | 225 | #else | ||
4881 | 226 | if ( isArray_ ) | ||
4882 | 227 | return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); | ||
4883 | 228 | return Value::UInt( -1 ); | ||
4884 | 229 | #endif | ||
4885 | 230 | } | ||
4886 | 231 | |||
4887 | 232 | |||
4888 | 233 | const char * | ||
4889 | 234 | ValueIteratorBase::memberName() const | ||
4890 | 235 | { | ||
4891 | 236 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4892 | 237 | const char *name = (*current_).first.c_str(); | ||
4893 | 238 | return name ? name : ""; | ||
4894 | 239 | #else | ||
4895 | 240 | if ( !isArray_ ) | ||
4896 | 241 | return ValueInternalMap::key( iterator_.map_ ); | ||
4897 | 242 | return ""; | ||
4898 | 243 | #endif | ||
4899 | 244 | } | ||
4900 | 245 | |||
4901 | 246 | |||
4902 | 247 | // ////////////////////////////////////////////////////////////////// | ||
4903 | 248 | // ////////////////////////////////////////////////////////////////// | ||
4904 | 249 | // ////////////////////////////////////////////////////////////////// | ||
4905 | 250 | // class ValueConstIterator | ||
4906 | 251 | // ////////////////////////////////////////////////////////////////// | ||
4907 | 252 | // ////////////////////////////////////////////////////////////////// | ||
4908 | 253 | // ////////////////////////////////////////////////////////////////// | ||
4909 | 254 | |||
4910 | 255 | ValueConstIterator::ValueConstIterator() | ||
4911 | 256 | { | ||
4912 | 257 | } | ||
4913 | 258 | |||
4914 | 259 | |||
4915 | 260 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4916 | 261 | ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) | ||
4917 | 262 | : ValueIteratorBase( current ) | ||
4918 | 263 | { | ||
4919 | 264 | } | ||
4920 | 265 | #else | ||
4921 | 266 | ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) | ||
4922 | 267 | : ValueIteratorBase( state ) | ||
4923 | 268 | { | ||
4924 | 269 | } | ||
4925 | 270 | |||
4926 | 271 | ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) | ||
4927 | 272 | : ValueIteratorBase( state ) | ||
4928 | 273 | { | ||
4929 | 274 | } | ||
4930 | 275 | #endif | ||
4931 | 276 | |||
4932 | 277 | ValueConstIterator & | ||
4933 | 278 | ValueConstIterator::operator =( const ValueIteratorBase &other ) | ||
4934 | 279 | { | ||
4935 | 280 | copy( other ); | ||
4936 | 281 | return *this; | ||
4937 | 282 | } | ||
4938 | 283 | |||
4939 | 284 | |||
4940 | 285 | // ////////////////////////////////////////////////////////////////// | ||
4941 | 286 | // ////////////////////////////////////////////////////////////////// | ||
4942 | 287 | // ////////////////////////////////////////////////////////////////// | ||
4943 | 288 | // class ValueIterator | ||
4944 | 289 | // ////////////////////////////////////////////////////////////////// | ||
4945 | 290 | // ////////////////////////////////////////////////////////////////// | ||
4946 | 291 | // ////////////////////////////////////////////////////////////////// | ||
4947 | 292 | |||
4948 | 293 | ValueIterator::ValueIterator() | ||
4949 | 294 | { | ||
4950 | 295 | } | ||
4951 | 296 | |||
4952 | 297 | |||
4953 | 298 | #ifndef JSON_VALUE_USE_INTERNAL_MAP | ||
4954 | 299 | ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) | ||
4955 | 300 | : ValueIteratorBase( current ) | ||
4956 | 301 | { | ||
4957 | 302 | } | ||
4958 | 303 | #else | ||
4959 | 304 | ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) | ||
4960 | 305 | : ValueIteratorBase( state ) | ||
4961 | 306 | { | ||
4962 | 307 | } | ||
4963 | 308 | |||
4964 | 309 | ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) | ||
4965 | 310 | : ValueIteratorBase( state ) | ||
4966 | 311 | { | ||
4967 | 312 | } | ||
4968 | 313 | #endif | ||
4969 | 314 | |||
4970 | 315 | ValueIterator::ValueIterator( const ValueConstIterator &other ) | ||
4971 | 316 | : ValueIteratorBase( other ) | ||
4972 | 317 | { | ||
4973 | 318 | } | ||
4974 | 319 | |||
4975 | 320 | ValueIterator::ValueIterator( const ValueIterator &other ) | ||
4976 | 321 | : ValueIteratorBase( other ) | ||
4977 | 322 | { | ||
4978 | 323 | } | ||
4979 | 324 | |||
4980 | 325 | ValueIterator & | ||
4981 | 326 | ValueIterator::operator =( const SelfType &other ) | ||
4982 | 327 | { | ||
4983 | 328 | copy( other ); | ||
4984 | 329 | return *this; | ||
4985 | 330 | } | ||
4986 | 0 | 331 | ||
4987 | === added file 'plugin/json_server/json/json_writer.cpp' | |||
4988 | --- plugin/json_server/json/json_writer.cpp 1970-01-01 00:00:00 +0000 | |||
4989 | +++ plugin/json_server/json/json_writer.cpp 2011-05-04 01:52:37 +0000 | |||
4990 | @@ -0,0 +1,862 @@ | |||
4991 | 1 | /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: | ||
4992 | 2 | * | ||
4993 | 3 | * JSON Library, originally from http://jsoncpp.sourceforge.net/ | ||
4994 | 4 | * | ||
4995 | 5 | * Copyright (C) 2011 Stewart Smith | ||
4996 | 6 | * All rights reserved. | ||
4997 | 7 | * | ||
4998 | 8 | * Redistribution and use in source and binary forms, with or without | ||
4999 | 9 | * modification, are permitted provided that the following conditions are | ||
5000 | 10 | * met: |
note that this includes http:// jsoncpp. sourceforge. net/ code, which is in the public domain.