Merge lp:~stewart/drizzle/json-interface into lp:~drizzle-trunk/drizzle/development

Proposed by Stewart Smith
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
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.

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.

To post a comment you must log in.
Revision history for this message
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal

note that this includes http://jsoncpp.sourceforge.net/ code, which is in the public domain.

Revision history for this message
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()/HTTP_POST() functions to the server (perhaps just using the interface that libevent provides) or we need to add curl as a build-dep.

Revision history for this message
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).

Revision history for this message
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://jsoncpp.sourceforge.net/LICENSE

is the other thing we should work out how to have in the soure files.

Revision history for this message
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal
Revision history for this message
Mark Atwood (fallenpegasus) wrote :
review: Needs Fixing
Revision history for this message
Stewart Smith (stewart) wrote :
Revision history for this message
Mark Atwood (fallenpegasus) wrote :

>>
>
> looks like something from vj's sp branch, not mine.

Brian and I are looking at it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'drizzled/plugin/client/cached.h'
--- drizzled/plugin/client/cached.h 2011-03-15 23:55:01 +0000
+++ drizzled/plugin/client/cached.h 2011-05-04 01:52:37 +0000
@@ -57,6 +57,7 @@
57 item->make_field(&field);57 item->make_field(&field);
58 max_column++;58 max_column++;
59 }59 }
60 _result_set->setColumnCount(max_column);
60 _result_set->createRow();61 _result_set->createRow();
6162
62 return false;63 return false;
6364
=== modified file 'drizzled/sql/result_set.h'
--- drizzled/sql/result_set.h 2011-03-29 12:45:08 +0000
+++ drizzled/sql/result_set.h 2011-05-04 01:52:37 +0000
@@ -101,6 +101,11 @@
101 {101 {
102 }102 }
103103
104 void setColumnCount(size_t fields)
105 {
106 _meta_data.setColumnCount(fields);
107 }
108
104 ~ResultSet();109 ~ResultSet();
105110
106 void createRow();111 void createRow();
107112
=== modified file 'drizzled/sql/result_set_meta_data.h'
--- drizzled/sql/result_set_meta_data.h 2011-03-29 12:45:08 +0000
+++ drizzled/sql/result_set_meta_data.h 2011-05-04 01:52:37 +0000
@@ -53,10 +53,15 @@
53 {53 {
54 }54 }
5555
56 void setColumnCount(size_t fields)
57 {
58 _columns= fields;
59 }
60
56private: // Member methods61private: // Member methods
5762
58private: // Member variables63private: // Member variables
59 const size_t _columns;64 size_t _columns;
60};65};
6166
62std::ostream& operator<<(std::ostream& output, const ResultSetMetaData &result_set);67std::ostream& operator<<(std::ostream& output, const ResultSetMetaData &result_set);
6368
=== added directory 'plugin/http_functions'
=== added file 'plugin/http_functions/http_functions.cc'
--- plugin/http_functions/http_functions.cc 1970-01-01 00:00:00 +0000
+++ plugin/http_functions/http_functions.cc 2011-05-04 01:52:37 +0000
@@ -0,0 +1,199 @@
1/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3 *
4 * Copyright (C) 2011 Stewart Smith
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#include <config.h>
21
22#include <drizzled/plugin/function.h>
23#include <drizzled/function/str/strfunc.h>
24#include <drizzled/charset.h>
25#include <drizzled/error.h>
26
27#include <curl/curl.h>
28
29using namespace drizzled;
30
31class HttpGetFunction :public Item_str_func
32{
33 String result;
34public:
35 HttpGetFunction() :Item_str_func() {}
36 String *val_str(String *);
37 void fix_length_and_dec();
38 const char *func_name() const { return "http_get"; }
39
40 bool check_argument_count(int n)
41 {
42 return n == 1;
43 }
44};
45
46extern "C" size_t
47http_get_result_cb(void *ptr, size_t size, size_t nmemb, void *data);
48
49extern "C" size_t
50http_get_result_cb(void *ptr, size_t size, size_t nmemb, void *data)
51{
52 size_t realsize= size * nmemb;
53 String *result= (String *)data;
54
55 result->reserve(realsize + 1);
56 result->append((const char*)ptr, realsize);
57
58 return realsize;
59}
60
61
62String *HttpGetFunction::val_str(String *str)
63{
64 assert(fixed == 1);
65 String *url = args[0]->val_str(str);
66 CURL *curl;
67 CURLcode retref;
68
69 if ((null_value=args[0]->null_value))
70 return NULL;
71
72 curl= curl_easy_init();
73 curl_easy_setopt(curl, CURLOPT_URL, url->c_ptr_safe());
74 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_cb);
75 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&result);
76 curl_easy_setopt(curl, CURLOPT_USERAGENT, "drizzle-http-functions/1.0");
77 retref= curl_easy_perform(curl);
78 curl_easy_cleanup(curl);
79
80 if (retref != 0)
81 my_error(ER_GET_ERRMSG, MYF(0), retref, curl_easy_strerror(retref),
82 "http_get");
83
84 return &result;
85}
86
87void HttpGetFunction::fix_length_and_dec()
88{
89 collation.set(args[0]->collation);
90 max_length = ~0;
91}
92
93class HttpPostFunction :public Item_str_func
94{
95 String result;
96public:
97 HttpPostFunction() :Item_str_func() {}
98 String *val_str(String *);
99 void fix_length_and_dec();
100 const char *func_name() const { return "http_post"; }
101
102 bool check_argument_count(int n)
103 {
104 return n == 2;
105 }
106};
107
108class HttpPostData
109{
110private:
111 String *data;
112 size_t progress;
113
114public:
115 HttpPostData(String* d) : data(d), progress(0) {}
116
117 size_t length() { return data->length(); }
118
119 size_t write(void* dest, size_t size)
120 {
121 size_t to_write= size;
122
123 if ((data->length() - progress) < to_write)
124 to_write= data->length() - progress;
125
126 memcpy(dest, data->ptr() + progress, to_write);
127
128 progress+= to_write;
129
130 return to_write;
131 }
132};
133
134extern "C" size_t
135http_post_readfunc(void *ptr, size_t size, size_t nmemb, void *data);
136
137extern "C" size_t
138http_post_readfunc(void *ptr, size_t size, size_t nmemb, void *data)
139{
140 size_t realsize= size * nmemb;
141 HttpPostData *post_data= (HttpPostData *)data;
142
143 return post_data->write(ptr, realsize);
144}
145
146String *HttpPostFunction::val_str(String *str)
147{
148 assert(fixed == 1);
149 String *url = args[0]->val_str(str);
150 CURL *curl;
151 CURLcode retref;
152 String post_storage;
153 HttpPostData post_data(args[1]->val_str(&post_storage));
154
155 if ((null_value=args[0]->null_value))
156 return NULL;
157
158 curl= curl_easy_init();
159 curl_easy_setopt(curl, CURLOPT_URL, url->c_ptr_safe());
160 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_result_cb);
161 curl_easy_setopt(curl, CURLOPT_POST, 1L);
162 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post_data.length());
163 curl_easy_setopt(curl, CURLOPT_READDATA, &post_data);
164 curl_easy_setopt(curl, CURLOPT_READFUNCTION, http_post_readfunc);
165 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&result);
166 curl_easy_setopt(curl, CURLOPT_USERAGENT, "drizzle-http-functions/1.0");
167 retref= curl_easy_perform(curl);
168 curl_easy_cleanup(curl);
169
170 return &result;
171}
172
173void HttpPostFunction::fix_length_and_dec()
174{
175 collation.set(args[0]->collation);
176 max_length = ~0;
177}
178
179static int initialize(drizzled::module::Context &context)
180{
181 curl_global_init(CURL_GLOBAL_ALL);
182 context.add(new plugin::Create_function<HttpGetFunction>("http_get"));
183 context.add(new plugin::Create_function<HttpPostFunction>("http_post"));
184 return 0;
185}
186
187DRIZZLE_DECLARE_PLUGIN
188{
189 DRIZZLE_VERSION_ID,
190 "http_functions",
191 "1.0",
192 "Stewart Smith",
193 "HTTP functions",
194 PLUGIN_LICENSE_GPL,
195 initialize, /* Plugin Init */
196 NULL, /* depends */
197 NULL /* config options */
198}
199DRIZZLE_DECLARE_PLUGIN_END;
0200
=== added file 'plugin/http_functions/plugin.ac'
--- plugin/http_functions/plugin.ac 1970-01-01 00:00:00 +0000
+++ plugin/http_functions/plugin.ac 2011-05-04 01:52:37 +0000
@@ -0,0 +1,4 @@
1PANDORA_HAVE_LIBCURL
2AS_IF([test "x$ac_cv_libcurl" = "xno"],
3 AC_MSG_WARN([libcurl not found: not building http_functions]))
4PANDORA_ADD_PLUGIN_DEP_LIB([${LIBCURL}])
05
=== added file 'plugin/http_functions/plugin.cnf'
--- plugin/http_functions/plugin.cnf 1970-01-01 00:00:00 +0000
+++ plugin/http_functions/plugin.cnf 2011-05-04 01:52:37 +0000
@@ -0,0 +1,2 @@
1plugin-add=http_functions
2
03
=== added file 'plugin/http_functions/plugin.ini'
--- plugin/http_functions/plugin.ini 1970-01-01 00:00:00 +0000
+++ plugin/http_functions/plugin.ini 2011-05-04 01:52:37 +0000
@@ -0,0 +1,6 @@
1[plugin]
2title=HTTP functions
3description=HTTP functions: HTTP_GET() etc
4sources=http_functions.cc
5build_conditional="${ac_cv_libcurl}" = "yes"
6ldflags=${LTLIBCURL}
07
=== added directory 'plugin/json_server'
=== added directory 'plugin/json_server/json'
=== added file 'plugin/json_server/json/autolink.h'
--- plugin/json_server/json/autolink.h 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/autolink.h 2011-05-04 01:52:37 +0000
@@ -0,0 +1,58 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#pragma once
39
40#ifndef JSON_AUTOLINK_H_INCLUDED
41# define JSON_AUTOLINK_H_INCLUDED
42
43# include "config.h"
44
45# ifdef JSON_IN_CPPTL
46# include <cpptl/cpptl_autolink.h>
47# endif
48
49# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
50# define CPPTL_AUTOLINK_NAME "json"
51# undef CPPTL_AUTOLINK_DLL
52# ifdef JSON_DLL
53# define CPPTL_AUTOLINK_DLL
54# endif
55# include "autolink.h"
56# endif
57
58#endif // JSON_AUTOLINK_H_INCLUDED
059
=== added file 'plugin/json_server/json/config.h'
--- plugin/json_server/json/config.h 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/config.h 2011-05-04 01:52:37 +0000
@@ -0,0 +1,81 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#pragma once
39#ifndef JSON_CONFIG_H_INCLUDED
40# define JSON_CONFIG_H_INCLUDED
41
42/// If defined, indicates that json library is embedded in CppTL library.
43//# define JSON_IN_CPPTL 1
44
45/// If defined, indicates that json may leverage CppTL library
46//# define JSON_USE_CPPTL 1
47/// If defined, indicates that cpptl vector based map should be used instead of std::map
48/// as Value container.
49//# define JSON_USE_CPPTL_SMALLMAP 1
50/// If defined, indicates that Json specific container should be used
51/// (hash table & simple deque container with customizable allocator).
52/// THIS FEATURE IS STILL EXPERIMENTAL!
53//# define JSON_VALUE_USE_INTERNAL_MAP 1
54/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
55/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
56/// as if it was a POD) that may cause some validation tool to report errors.
57/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
58//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
59
60/// If defined, indicates that Json use exception to report invalid type manipulation
61/// instead of C assert macro.
62# define JSON_USE_EXCEPTION 1
63
64# ifdef JSON_IN_CPPTL
65# include <cpptl/config.h>
66# ifndef JSON_USE_CPPTL
67# define JSON_USE_CPPTL 1
68# endif
69# endif
70
71# ifdef JSON_IN_CPPTL
72# define JSON_API CPPTL_API
73# elif defined(JSON_DLL_BUILD)
74# define JSON_API __declspec(dllexport)
75# elif defined(JSON_DLL)
76# define JSON_API __declspec(dllimport)
77# else
78# define JSON_API
79# endif
80
81#endif // JSON_CONFIG_H_INCLUDED
082
=== added file 'plugin/json_server/json/features.h'
--- plugin/json_server/json/features.h 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/features.h 2011-05-04 01:52:37 +0000
@@ -0,0 +1,80 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#pragma once
39#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
40# define CPPTL_JSON_FEATURES_H_INCLUDED
41
42# include "forwards.h"
43
44namespace Json {
45
46 /** \brief Configuration passed to reader and writer.
47 * This configuration object can be used to force the Reader or Writer
48 * to behave in a standard conforming way.
49 */
50 class JSON_API Features
51 {
52 public:
53 /** \brief A configuration that allows all features and assumes all strings are UTF-8.
54 * - C & C++ comments are allowed
55 * - Root object can be any JSON value
56 * - Assumes Value strings are encoded in UTF-8
57 */
58 static Features all();
59
60 /** \brief A configuration that is strictly compatible with the JSON specification.
61 * - Comments are forbidden.
62 * - Root object must be either an array or an object value.
63 * - Assumes Value strings are encoded in UTF-8
64 */
65 static Features strictMode();
66
67 /** \brief Initialize the configuration like JsonConfig::allFeatures;
68 */
69 Features();
70
71 /// \c true if comments are allowed. Default: \c true.
72 bool allowComments_;
73
74 /// \c true if root must be either an array or an object value. Default: \c false.
75 bool strictRoot_;
76 };
77
78} // namespace Json
79
80#endif // CPPTL_JSON_FEATURES_H_INCLUDED
081
=== added file 'plugin/json_server/json/forwards.h'
--- plugin/json_server/json/forwards.h 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/forwards.h 2011-05-04 01:52:37 +0000
@@ -0,0 +1,77 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#pragma once
39#ifndef JSON_FORWARDS_H_INCLUDED
40# define JSON_FORWARDS_H_INCLUDED
41
42# include "config.h"
43
44namespace Json {
45
46 // writer.h
47 class FastWriter;
48 class StyledWriter;
49
50 // reader.h
51 class Reader;
52
53 // features.h
54 class Features;
55
56 // value.h
57 typedef int Int;
58 typedef unsigned int UInt;
59 class StaticString;
60 class Path;
61 class PathArgument;
62 class Value;
63 class ValueIteratorBase;
64 class ValueIterator;
65 class ValueConstIterator;
66#ifdef JSON_VALUE_USE_INTERNAL_MAP
67 class ValueAllocator;
68 class ValueMapAllocator;
69 class ValueInternalLink;
70 class ValueInternalArray;
71 class ValueInternalMap;
72#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
73
74} // namespace Json
75
76
77#endif // JSON_FORWARDS_H_INCLUDED
078
=== added file 'plugin/json_server/json/json.h'
--- plugin/json_server/json/json.h 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/json.h 2011-05-04 01:52:37 +0000
@@ -0,0 +1,48 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#pragma once
39#ifndef JSON_JSON_H_INCLUDED
40# define JSON_JSON_H_INCLUDED
41
42# include "autolink.h"
43# include "value.h"
44# include "reader.h"
45# include "writer.h"
46# include "features.h"
47
48#endif // JSON_JSON_H_INCLUDED
049
=== added file 'plugin/json_server/json/json_batchallocator.h'
--- plugin/json_server/json/json_batchallocator.h 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/json_batchallocator.h 2011-05-04 01:52:37 +0000
@@ -0,0 +1,163 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#pragma once
39#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
40# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
41
42# include <stdlib.h>
43# include <assert.h>
44
45# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
46
47namespace Json {
48
49/* Fast memory allocator.
50 *
51 * This memory allocator allocates memory for a batch of object (specified by
52 * the page size, the number of object in each page).
53 *
54 * It does not allow the destruction of a single object. All the allocated objects
55 * can be destroyed at once. The memory can be either released or reused for future
56 * allocation.
57 *
58 * The in-place new operator must be used to construct the object using the pointer
59 * returned by allocate.
60 */
61template<typename AllocatedType
62 ,const unsigned int objectPerAllocation>
63class BatchAllocator
64{
65public:
66 typedef AllocatedType Type;
67
68 BatchAllocator( unsigned int objectsPerPage = 255 )
69 : freeHead_( 0 )
70 , objectsPerPage_( objectsPerPage )
71 {
72// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
73 assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
74 assert( objectsPerPage >= 16 );
75 batches_ = allocateBatch( 0 ); // allocated a dummy page
76 currentBatch_ = batches_;
77 }
78
79 ~BatchAllocator()
80 {
81 for ( BatchInfo *batch = batches_; batch; )
82 {
83 BatchInfo *nextBatch = batch->next_;
84 free( batch );
85 batch = nextBatch;
86 }
87 }
88
89 /// allocate space for an array of objectPerAllocation object.
90 /// @warning it is the responsability of the caller to call objects constructors.
91 AllocatedType *allocate()
92 {
93 if ( freeHead_ ) // returns node from free list.
94 {
95 AllocatedType *object = freeHead_;
96 freeHead_ = *(AllocatedType **)object;
97 return object;
98 }
99 if ( currentBatch_->used_ == currentBatch_->end_ )
100 {
101 currentBatch_ = currentBatch_->next_;
102 while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
103 currentBatch_ = currentBatch_->next_;
104
105 if ( !currentBatch_ ) // no free batch found, allocate a new one
106 {
107 currentBatch_ = allocateBatch( objectsPerPage_ );
108 currentBatch_->next_ = batches_; // insert at the head of the list
109 batches_ = currentBatch_;
110 }
111 }
112 AllocatedType *allocated = currentBatch_->used_;
113 currentBatch_->used_ += objectPerAllocation;
114 return allocated;
115 }
116
117 /// Release the object.
118 /// @warning it is the responsability of the caller to actually destruct the object.
119 void release( AllocatedType *object )
120 {
121 assert( object != 0 );
122 *(AllocatedType **)object = freeHead_;
123 freeHead_ = object;
124 }
125
126private:
127 struct BatchInfo
128 {
129 BatchInfo *next_;
130 AllocatedType *used_;
131 AllocatedType *end_;
132 AllocatedType buffer_[objectPerAllocation];
133 };
134
135 // disabled copy constructor and assignement operator.
136 BatchAllocator( const BatchAllocator & );
137 void operator =( const BatchAllocator &);
138
139 static BatchInfo *allocateBatch( unsigned int objectsPerPage )
140 {
141 const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
142 + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
143 BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
144 batch->next_ = 0;
145 batch->used_ = batch->buffer_;
146 batch->end_ = batch->buffer_ + objectsPerPage;
147 return batch;
148 }
149
150 BatchInfo *batches_;
151 BatchInfo *currentBatch_;
152 /// Head of a single linked list within the allocated space of freeed object
153 AllocatedType *freeHead_;
154 unsigned int objectsPerPage_;
155};
156
157
158} // namespace Json
159
160# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
161
162#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
163
0164
=== added file 'plugin/json_server/json/json_internalarray.inl'
--- plugin/json_server/json/json_internalarray.inl 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/json_internalarray.inl 2011-05-04 01:52:37 +0000
@@ -0,0 +1,486 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#pragma once
39// included by json_value.cpp
40// everything is within Json namespace
41
42// //////////////////////////////////////////////////////////////////
43// //////////////////////////////////////////////////////////////////
44// //////////////////////////////////////////////////////////////////
45// class ValueInternalArray
46// //////////////////////////////////////////////////////////////////
47// //////////////////////////////////////////////////////////////////
48// //////////////////////////////////////////////////////////////////
49
50ValueArrayAllocator::~ValueArrayAllocator()
51{
52}
53
54// //////////////////////////////////////////////////////////////////
55// class DefaultValueArrayAllocator
56// //////////////////////////////////////////////////////////////////
57#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
58class DefaultValueArrayAllocator : public ValueArrayAllocator
59{
60public: // overridden from ValueArrayAllocator
61 virtual ~DefaultValueArrayAllocator()
62 {
63 }
64
65 virtual ValueInternalArray *newArray()
66 {
67 return new ValueInternalArray();
68 }
69
70 virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
71 {
72 return new ValueInternalArray( other );
73 }
74
75 virtual void destructArray( ValueInternalArray *array )
76 {
77 delete array;
78 }
79
80 virtual void reallocateArrayPageIndex( Value **&indexes,
81 ValueInternalArray::PageIndex &indexCount,
82 ValueInternalArray::PageIndex minNewIndexCount )
83 {
84 ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
85 if ( minNewIndexCount > newIndexCount )
86 newIndexCount = minNewIndexCount;
87 void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
88 if ( !newIndexes )
89 throw std::bad_alloc();
90 indexCount = newIndexCount;
91 indexes = static_cast<Value **>( newIndexes );
92 }
93 virtual void releaseArrayPageIndex( Value **indexes,
94 ValueInternalArray::PageIndex indexCount )
95 {
96 if ( indexes )
97 free( indexes );
98 }
99
100 virtual Value *allocateArrayPage()
101 {
102 return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
103 }
104
105 virtual void releaseArrayPage( Value *value )
106 {
107 if ( value )
108 free( value );
109 }
110};
111
112#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
113/// @todo make this thread-safe (lock when accessign batch allocator)
114class DefaultValueArrayAllocator : public ValueArrayAllocator
115{
116public: // overridden from ValueArrayAllocator
117 virtual ~DefaultValueArrayAllocator()
118 {
119 }
120
121 virtual ValueInternalArray *newArray()
122 {
123 ValueInternalArray *array = arraysAllocator_.allocate();
124 new (array) ValueInternalArray(); // placement new
125 return array;
126 }
127
128 virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
129 {
130 ValueInternalArray *array = arraysAllocator_.allocate();
131 new (array) ValueInternalArray( other ); // placement new
132 return array;
133 }
134
135 virtual void destructArray( ValueInternalArray *array )
136 {
137 if ( array )
138 {
139 array->~ValueInternalArray();
140 arraysAllocator_.release( array );
141 }
142 }
143
144 virtual void reallocateArrayPageIndex( Value **&indexes,
145 ValueInternalArray::PageIndex &indexCount,
146 ValueInternalArray::PageIndex minNewIndexCount )
147 {
148 ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
149 if ( minNewIndexCount > newIndexCount )
150 newIndexCount = minNewIndexCount;
151 void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
152 if ( !newIndexes )
153 throw std::bad_alloc();
154 indexCount = newIndexCount;
155 indexes = static_cast<Value **>( newIndexes );
156 }
157 virtual void releaseArrayPageIndex( Value **indexes,
158 ValueInternalArray::PageIndex indexCount )
159 {
160 if ( indexes )
161 free( indexes );
162 }
163
164 virtual Value *allocateArrayPage()
165 {
166 return static_cast<Value *>( pagesAllocator_.allocate() );
167 }
168
169 virtual void releaseArrayPage( Value *value )
170 {
171 if ( value )
172 pagesAllocator_.release( value );
173 }
174private:
175 BatchAllocator<ValueInternalArray,1> arraysAllocator_;
176 BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
177};
178#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
179
180static ValueArrayAllocator *&arrayAllocator()
181{
182 static DefaultValueArrayAllocator defaultAllocator;
183 static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
184 return arrayAllocator;
185}
186
187static struct DummyArrayAllocatorInitializer {
188 DummyArrayAllocatorInitializer()
189 {
190 arrayAllocator(); // ensure arrayAllocator() statics are initialized before main().
191 }
192} dummyArrayAllocatorInitializer;
193
194// //////////////////////////////////////////////////////////////////
195// class ValueInternalArray
196// //////////////////////////////////////////////////////////////////
197bool
198ValueInternalArray::equals( const IteratorState &x,
199 const IteratorState &other )
200{
201 return x.array_ == other.array_
202 && x.currentItemIndex_ == other.currentItemIndex_
203 && x.currentPageIndex_ == other.currentPageIndex_;
204}
205
206
207void
208ValueInternalArray::increment( IteratorState &it )
209{
210 JSON_ASSERT_MESSAGE( it.array_ &&
211 (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
212 != it.array_->size_,
213 "ValueInternalArray::increment(): moving iterator beyond end" );
214 ++(it.currentItemIndex_);
215 if ( it.currentItemIndex_ == itemsPerPage )
216 {
217 it.currentItemIndex_ = 0;
218 ++(it.currentPageIndex_);
219 }
220}
221
222
223void
224ValueInternalArray::decrement( IteratorState &it )
225{
226 JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_
227 && it.currentItemIndex_ == 0,
228 "ValueInternalArray::decrement(): moving iterator beyond end" );
229 if ( it.currentItemIndex_ == 0 )
230 {
231 it.currentItemIndex_ = itemsPerPage-1;
232 --(it.currentPageIndex_);
233 }
234 else
235 {
236 --(it.currentItemIndex_);
237 }
238}
239
240
241Value &
242ValueInternalArray::unsafeDereference( const IteratorState &it )
243{
244 return (*(it.currentPageIndex_))[it.currentItemIndex_];
245}
246
247
248Value &
249ValueInternalArray::dereference( const IteratorState &it )
250{
251 JSON_ASSERT_MESSAGE( it.array_ &&
252 (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
253 < it.array_->size_,
254 "ValueInternalArray::dereference(): dereferencing invalid iterator" );
255 return unsafeDereference( it );
256}
257
258void
259ValueInternalArray::makeBeginIterator( IteratorState &it ) const
260{
261 it.array_ = const_cast<ValueInternalArray *>( this );
262 it.currentItemIndex_ = 0;
263 it.currentPageIndex_ = pages_;
264}
265
266
267void
268ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
269{
270 it.array_ = const_cast<ValueInternalArray *>( this );
271 it.currentItemIndex_ = index % itemsPerPage;
272 it.currentPageIndex_ = pages_ + index / itemsPerPage;
273}
274
275
276void
277ValueInternalArray::makeEndIterator( IteratorState &it ) const
278{
279 makeIterator( it, size_ );
280}
281
282
283ValueInternalArray::ValueInternalArray()
284 : pages_( 0 )
285 , size_( 0 )
286 , pageCount_( 0 )
287{
288}
289
290
291ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
292 : pages_( 0 )
293 , pageCount_( 0 )
294 , size_( other.size_ )
295{
296 PageIndex minNewPages = other.size_ / itemsPerPage;
297 arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
298 JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages,
299 "ValueInternalArray::reserve(): bad reallocation" );
300 IteratorState itOther;
301 other.makeBeginIterator( itOther );
302 Value *value;
303 for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
304 {
305 if ( index % itemsPerPage == 0 )
306 {
307 PageIndex pageIndex = index / itemsPerPage;
308 value = arrayAllocator()->allocateArrayPage();
309 pages_[pageIndex] = value;
310 }
311 new (value) Value( dereference( itOther ) );
312 }
313}
314
315
316ValueInternalArray &
317ValueInternalArray::operator =( const ValueInternalArray &other )
318{
319 ValueInternalArray temp( other );
320 swap( temp );
321 return *this;
322}
323
324
325ValueInternalArray::~ValueInternalArray()
326{
327 // destroy all constructed items
328 IteratorState it;
329 IteratorState itEnd;
330 makeBeginIterator( it);
331 makeEndIterator( itEnd );
332 for ( ; !equals(it,itEnd); increment(it) )
333 {
334 Value *value = &dereference(it);
335 value->~Value();
336 }
337 // release all pages
338 PageIndex lastPageIndex = size_ / itemsPerPage;
339 for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
340 arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
341 // release pages index
342 arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
343}
344
345
346void
347ValueInternalArray::swap( ValueInternalArray &other )
348{
349 Value **tempPages = pages_;
350 pages_ = other.pages_;
351 other.pages_ = tempPages;
352 ArrayIndex tempSize = size_;
353 size_ = other.size_;
354 other.size_ = tempSize;
355 PageIndex tempPageCount = pageCount_;
356 pageCount_ = other.pageCount_;
357 other.pageCount_ = tempPageCount;
358}
359
360void
361ValueInternalArray::clear()
362{
363 ValueInternalArray dummy;
364 swap( dummy );
365}
366
367
368void
369ValueInternalArray::resize( ArrayIndex newSize )
370{
371 if ( newSize == 0 )
372 clear();
373 else if ( newSize < size_ )
374 {
375 IteratorState it;
376 IteratorState itEnd;
377 makeIterator( it, newSize );
378 makeIterator( itEnd, size_ );
379 for ( ; !equals(it,itEnd); increment(it) )
380 {
381 Value *value = &dereference(it);
382 value->~Value();
383 }
384 PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
385 PageIndex lastPageIndex = size_ / itemsPerPage;
386 for ( ; pageIndex < lastPageIndex; ++pageIndex )
387 arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
388 size_ = newSize;
389 }
390 else if ( newSize > size_ )
391 resolveReference( newSize );
392}
393
394
395void
396ValueInternalArray::makeIndexValid( ArrayIndex index )
397{
398 // Need to enlarge page index ?
399 if ( index >= pageCount_ * itemsPerPage )
400 {
401 PageIndex minNewPages = (index + 1) / itemsPerPage;
402 arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
403 JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
404 }
405
406 // Need to allocate new pages ?
407 ArrayIndex nextPageIndex =
408 (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
409 : size_;
410 if ( nextPageIndex <= index )
411 {
412 PageIndex pageIndex = nextPageIndex / itemsPerPage;
413 PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
414 for ( ; pageToAllocate-- > 0; ++pageIndex )
415 pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
416 }
417
418 // Initialize all new entries
419 IteratorState it;
420 IteratorState itEnd;
421 makeIterator( it, size_ );
422 size_ = index + 1;
423 makeIterator( itEnd, size_ );
424 for ( ; !equals(it,itEnd); increment(it) )
425 {
426 Value *value = &dereference(it);
427 new (value) Value(); // Construct a default value using placement new
428 }
429}
430
431Value &
432ValueInternalArray::resolveReference( ArrayIndex index )
433{
434 if ( index >= size_ )
435 makeIndexValid( index );
436 return pages_[index/itemsPerPage][index%itemsPerPage];
437}
438
439Value *
440ValueInternalArray::find( ArrayIndex index ) const
441{
442 if ( index >= size_ )
443 return 0;
444 return &(pages_[index/itemsPerPage][index%itemsPerPage]);
445}
446
447ValueInternalArray::ArrayIndex
448ValueInternalArray::size() const
449{
450 return size_;
451}
452
453int
454ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
455{
456 return indexOf(y) - indexOf(x);
457}
458
459
460ValueInternalArray::ArrayIndex
461ValueInternalArray::indexOf( const IteratorState &iterator )
462{
463 if ( !iterator.array_ )
464 return ArrayIndex(-1);
465 return ArrayIndex(
466 (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage
467 + iterator.currentItemIndex_ );
468}
469
470
471int
472ValueInternalArray::compare( const ValueInternalArray &other ) const
473{
474 int sizeDiff( size_ - other.size_ );
475 if ( sizeDiff != 0 )
476 return sizeDiff;
477
478 for ( ArrayIndex index =0; index < size_; ++index )
479 {
480 int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare(
481 other.pages_[index/itemsPerPage][index%itemsPerPage] );
482 if ( diff != 0 )
483 return diff;
484 }
485 return 0;
486}
0487
=== added file 'plugin/json_server/json/json_internalmap.inl'
--- plugin/json_server/json/json_internalmap.inl 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/json_internalmap.inl 2011-05-04 01:52:37 +0000
@@ -0,0 +1,645 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#pragma once
39// included by json_value.cpp
40// everything is within Json namespace
41
42// //////////////////////////////////////////////////////////////////
43// //////////////////////////////////////////////////////////////////
44// //////////////////////////////////////////////////////////////////
45// class ValueInternalMap
46// //////////////////////////////////////////////////////////////////
47// //////////////////////////////////////////////////////////////////
48// //////////////////////////////////////////////////////////////////
49
50/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
51 * This optimization is used by the fast allocator.
52 */
53ValueInternalLink::ValueInternalLink()
54 : previous_( 0 )
55 , next_( 0 )
56{
57}
58
59ValueInternalLink::~ValueInternalLink()
60{
61 for ( int index =0; index < itemPerLink; ++index )
62 {
63 if ( !items_[index].isItemAvailable() )
64 {
65 if ( !items_[index].isMemberNameStatic() )
66 free( keys_[index] );
67 }
68 else
69 break;
70 }
71}
72
73
74
75ValueMapAllocator::~ValueMapAllocator()
76{
77}
78
79#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
80class DefaultValueMapAllocator : public ValueMapAllocator
81{
82public: // overridden from ValueMapAllocator
83 virtual ValueInternalMap *newMap()
84 {
85 return new ValueInternalMap();
86 }
87
88 virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
89 {
90 return new ValueInternalMap( other );
91 }
92
93 virtual void destructMap( ValueInternalMap *map )
94 {
95 delete map;
96 }
97
98 virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
99 {
100 return new ValueInternalLink[size];
101 }
102
103 virtual void releaseMapBuckets( ValueInternalLink *links )
104 {
105 delete [] links;
106 }
107
108 virtual ValueInternalLink *allocateMapLink()
109 {
110 return new ValueInternalLink();
111 }
112
113 virtual void releaseMapLink( ValueInternalLink *link )
114 {
115 delete link;
116 }
117};
118#else
119/// @todo make this thread-safe (lock when accessign batch allocator)
120class DefaultValueMapAllocator : public ValueMapAllocator
121{
122public: // overridden from ValueMapAllocator
123 virtual ValueInternalMap *newMap()
124 {
125 ValueInternalMap *map = mapsAllocator_.allocate();
126 new (map) ValueInternalMap(); // placement new
127 return map;
128 }
129
130 virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
131 {
132 ValueInternalMap *map = mapsAllocator_.allocate();
133 new (map) ValueInternalMap( other ); // placement new
134 return map;
135 }
136
137 virtual void destructMap( ValueInternalMap *map )
138 {
139 if ( map )
140 {
141 map->~ValueInternalMap();
142 mapsAllocator_.release( map );
143 }
144 }
145
146 virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
147 {
148 return new ValueInternalLink[size];
149 }
150
151 virtual void releaseMapBuckets( ValueInternalLink *links )
152 {
153 delete [] links;
154 }
155
156 virtual ValueInternalLink *allocateMapLink()
157 {
158 ValueInternalLink *link = linksAllocator_.allocate();
159 memset( link, 0, sizeof(ValueInternalLink) );
160 return link;
161 }
162
163 virtual void releaseMapLink( ValueInternalLink *link )
164 {
165 link->~ValueInternalLink();
166 linksAllocator_.release( link );
167 }
168private:
169 BatchAllocator<ValueInternalMap,1> mapsAllocator_;
170 BatchAllocator<ValueInternalLink,1> linksAllocator_;
171};
172#endif
173
174static ValueMapAllocator *&mapAllocator()
175{
176 static DefaultValueMapAllocator defaultAllocator;
177 static ValueMapAllocator *mapAllocator = &defaultAllocator;
178 return mapAllocator;
179}
180
181static struct DummyMapAllocatorInitializer {
182 DummyMapAllocatorInitializer()
183 {
184 mapAllocator(); // ensure mapAllocator() statics are initialized before main().
185 }
186} dummyMapAllocatorInitializer;
187
188
189
190// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
191
192/*
193use linked list hash map.
194buckets array is a container.
195linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
196value have extra state: valid, available, deleted
197*/
198
199
200ValueInternalMap::ValueInternalMap()
201 : buckets_( 0 )
202 , tailLink_( 0 )
203 , bucketsSize_( 0 )
204 , itemCount_( 0 )
205{
206}
207
208
209ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
210 : buckets_( 0 )
211 , tailLink_( 0 )
212 , bucketsSize_( 0 )
213 , itemCount_( 0 )
214{
215 reserve( other.itemCount_ );
216 IteratorState it;
217 IteratorState itEnd;
218 other.makeBeginIterator( it );
219 other.makeEndIterator( itEnd );
220 for ( ; !equals(it,itEnd); increment(it) )
221 {
222 bool isStatic;
223 const char *memberName = key( it, isStatic );
224 const Value &aValue = value( it );
225 resolveReference(memberName, isStatic) = aValue;
226 }
227}
228
229
230ValueInternalMap &
231ValueInternalMap::operator =( const ValueInternalMap &other )
232{
233 ValueInternalMap dummy( other );
234 swap( dummy );
235 return *this;
236}
237
238
239ValueInternalMap::~ValueInternalMap()
240{
241 if ( buckets_ )
242 {
243 for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
244 {
245 ValueInternalLink *link = buckets_[bucketIndex].next_;
246 while ( link )
247 {
248 ValueInternalLink *linkToRelease = link;
249 link = link->next_;
250 mapAllocator()->releaseMapLink( linkToRelease );
251 }
252 }
253 mapAllocator()->releaseMapBuckets( buckets_ );
254 }
255}
256
257
258void
259ValueInternalMap::swap( ValueInternalMap &other )
260{
261 ValueInternalLink *tempBuckets = buckets_;
262 buckets_ = other.buckets_;
263 other.buckets_ = tempBuckets;
264 ValueInternalLink *tempTailLink = tailLink_;
265 tailLink_ = other.tailLink_;
266 other.tailLink_ = tempTailLink;
267 BucketIndex tempBucketsSize = bucketsSize_;
268 bucketsSize_ = other.bucketsSize_;
269 other.bucketsSize_ = tempBucketsSize;
270 BucketIndex tempItemCount = itemCount_;
271 itemCount_ = other.itemCount_;
272 other.itemCount_ = tempItemCount;
273}
274
275
276void
277ValueInternalMap::clear()
278{
279 ValueInternalMap dummy;
280 swap( dummy );
281}
282
283
284ValueInternalMap::BucketIndex
285ValueInternalMap::size() const
286{
287 return itemCount_;
288}
289
290bool
291ValueInternalMap::reserveDelta( BucketIndex growth )
292{
293 return reserve( itemCount_ + growth );
294}
295
296bool
297ValueInternalMap::reserve( BucketIndex newItemCount )
298{
299 if ( !buckets_ && newItemCount > 0 )
300 {
301 buckets_ = mapAllocator()->allocateMapBuckets( 1 );
302 bucketsSize_ = 1;
303 tailLink_ = &buckets_[0];
304 }
305// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
306 return true;
307}
308
309
310const Value *
311ValueInternalMap::find( const char *key ) const
312{
313 if ( !bucketsSize_ )
314 return 0;
315 HashKey hashedKey = hash( key );
316 BucketIndex bucketIndex = hashedKey % bucketsSize_;
317 for ( const ValueInternalLink *current = &buckets_[bucketIndex];
318 current != 0;
319 current = current->next_ )
320 {
321 for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
322 {
323 if ( current->items_[index].isItemAvailable() )
324 return 0;
325 if ( strcmp( key, current->keys_[index] ) == 0 )
326 return &current->items_[index];
327 }
328 }
329 return 0;
330}
331
332
333Value *
334ValueInternalMap::find( const char *key )
335{
336 const ValueInternalMap *constThis = this;
337 return const_cast<Value *>( constThis->find( key ) );
338}
339
340
341Value &
342ValueInternalMap::resolveReference( const char *key,
343 bool isStatic )
344{
345 HashKey hashedKey = hash( key );
346 if ( bucketsSize_ )
347 {
348 BucketIndex bucketIndex = hashedKey % bucketsSize_;
349 ValueInternalLink **previous = 0;
350 BucketIndex index;
351 for ( ValueInternalLink *current = &buckets_[bucketIndex];
352 current != 0;
353 previous = &current->next_, current = current->next_ )
354 {
355 for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
356 {
357 if ( current->items_[index].isItemAvailable() )
358 return setNewItem( key, isStatic, current, index );
359 if ( strcmp( key, current->keys_[index] ) == 0 )
360 return current->items_[index];
361 }
362 }
363 }
364
365 reserveDelta( 1 );
366 return unsafeAdd( key, isStatic, hashedKey );
367}
368
369
370void
371ValueInternalMap::remove( const char *key )
372{
373 HashKey hashedKey = hash( key );
374 if ( !bucketsSize_ )
375 return;
376 BucketIndex bucketIndex = hashedKey % bucketsSize_;
377 for ( ValueInternalLink *link = &buckets_[bucketIndex];
378 link != 0;
379 link = link->next_ )
380 {
381 BucketIndex index;
382 for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
383 {
384 if ( link->items_[index].isItemAvailable() )
385 return;
386 if ( strcmp( key, link->keys_[index] ) == 0 )
387 {
388 doActualRemove( link, index, bucketIndex );
389 return;
390 }
391 }
392 }
393}
394
395void
396ValueInternalMap::doActualRemove( ValueInternalLink *link,
397 BucketIndex index,
398 BucketIndex bucketIndex )
399{
400 // find last item of the bucket and swap it with the 'removed' one.
401 // set removed items flags to 'available'.
402 // if last page only contains 'available' items, then desallocate it (it's empty)
403 ValueInternalLink *&lastLink = getLastLinkInBucket( index );
404 BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
405 for ( ;
406 lastItemIndex < ValueInternalLink::itemPerLink;
407 ++lastItemIndex ) // may be optimized with dicotomic search
408 {
409 if ( lastLink->items_[lastItemIndex].isItemAvailable() )
410 break;
411 }
412
413 BucketIndex lastUsedIndex = lastItemIndex - 1;
414 Value *valueToDelete = &link->items_[index];
415 Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
416 if ( valueToDelete != valueToPreserve )
417 valueToDelete->swap( *valueToPreserve );
418 if ( lastUsedIndex == 0 ) // page is now empty
419 { // remove it from bucket linked list and delete it.
420 ValueInternalLink *linkPreviousToLast = lastLink->previous_;
421 if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
422 {
423 mapAllocator()->releaseMapLink( lastLink );
424 linkPreviousToLast->next_ = 0;
425 lastLink = linkPreviousToLast;
426 }
427 }
428 else
429 {
430 Value dummy;
431 valueToPreserve->swap( dummy ); // restore deleted to default Value.
432 valueToPreserve->setItemUsed( false );
433 }
434 --itemCount_;
435}
436
437
438ValueInternalLink *&
439ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
440{
441 if ( bucketIndex == bucketsSize_ - 1 )
442 return tailLink_;
443 ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
444 if ( !previous )
445 previous = &buckets_[bucketIndex];
446 return previous;
447}
448
449
450Value &
451ValueInternalMap::setNewItem( const char *key,
452 bool isStatic,
453 ValueInternalLink *link,
454 BucketIndex index )
455{
456 char *duplicatedKey = valueAllocator()->makeMemberName( key );
457 ++itemCount_;
458 link->keys_[index] = duplicatedKey;
459 link->items_[index].setItemUsed();
460 link->items_[index].setMemberNameIsStatic( isStatic );
461 return link->items_[index]; // items already default constructed.
462}
463
464
465Value &
466ValueInternalMap::unsafeAdd( const char *key,
467 bool isStatic,
468 HashKey hashedKey )
469{
470 JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
471 BucketIndex bucketIndex = hashedKey % bucketsSize_;
472 ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
473 ValueInternalLink *link = previousLink;
474 BucketIndex index;
475 for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
476 {
477 if ( link->items_[index].isItemAvailable() )
478 break;
479 }
480 if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
481 {
482 ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
483 index = 0;
484 link->next_ = newLink;
485 previousLink = newLink;
486 link = newLink;
487 }
488 return setNewItem( key, isStatic, link, index );
489}
490
491
492ValueInternalMap::HashKey
493ValueInternalMap::hash( const char *key ) const
494{
495 HashKey hash = 0;
496 while ( *key )
497 hash += *key++ * 37;
498 return hash;
499}
500
501
502int
503ValueInternalMap::compare( const ValueInternalMap &other ) const
504{
505 int sizeDiff( itemCount_ - other.itemCount_ );
506 if ( sizeDiff != 0 )
507 return sizeDiff;
508 // Strict order guaranty is required. Compare all keys FIRST, then compare values.
509 IteratorState it;
510 IteratorState itEnd;
511 makeBeginIterator( it );
512 makeEndIterator( itEnd );
513 for ( ; !equals(it,itEnd); increment(it) )
514 {
515 if ( !other.find( key( it ) ) )
516 return 1;
517 }
518
519 // All keys are equals, let's compare values
520 makeBeginIterator( it );
521 for ( ; !equals(it,itEnd); increment(it) )
522 {
523 const Value *otherValue = other.find( key( it ) );
524 int valueDiff = value(it).compare( *otherValue );
525 if ( valueDiff != 0 )
526 return valueDiff;
527 }
528 return 0;
529}
530
531
532void
533ValueInternalMap::makeBeginIterator( IteratorState &it ) const
534{
535 it.map_ = const_cast<ValueInternalMap *>( this );
536 it.bucketIndex_ = 0;
537 it.itemIndex_ = 0;
538 it.link_ = buckets_;
539}
540
541
542void
543ValueInternalMap::makeEndIterator( IteratorState &it ) const
544{
545 it.map_ = const_cast<ValueInternalMap *>( this );
546 it.bucketIndex_ = bucketsSize_;
547 it.itemIndex_ = 0;
548 it.link_ = 0;
549}
550
551
552bool
553ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
554{
555 return x.map_ == other.map_
556 && x.bucketIndex_ == other.bucketIndex_
557 && x.link_ == other.link_
558 && x.itemIndex_ == other.itemIndex_;
559}
560
561
562void
563ValueInternalMap::incrementBucket( IteratorState &iterator )
564{
565 ++iterator.bucketIndex_;
566 JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
567 "ValueInternalMap::increment(): attempting to iterate beyond end." );
568 if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
569 iterator.link_ = 0;
570 else
571 iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
572 iterator.itemIndex_ = 0;
573}
574
575
576void
577ValueInternalMap::increment( IteratorState &iterator )
578{
579 JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
580 ++iterator.itemIndex_;
581 if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
582 {
583 JSON_ASSERT_MESSAGE( iterator.link_ != 0,
584 "ValueInternalMap::increment(): attempting to iterate beyond end." );
585 iterator.link_ = iterator.link_->next_;
586 if ( iterator.link_ == 0 )
587 incrementBucket( iterator );
588 }
589 else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
590 {
591 incrementBucket( iterator );
592 }
593}
594
595
596void
597ValueInternalMap::decrement( IteratorState &iterator )
598{
599 if ( iterator.itemIndex_ == 0 )
600 {
601 JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
602 if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
603 {
604 JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
605 --(iterator.bucketIndex_);
606 }
607 iterator.link_ = iterator.link_->previous_;
608 iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
609 }
610}
611
612
613const char *
614ValueInternalMap::key( const IteratorState &iterator )
615{
616 JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
617 return iterator.link_->keys_[iterator.itemIndex_];
618}
619
620const char *
621ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
622{
623 JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
624 isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
625 return iterator.link_->keys_[iterator.itemIndex_];
626}
627
628
629Value &
630ValueInternalMap::value( const IteratorState &iterator )
631{
632 JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
633 return iterator.link_->items_[iterator.itemIndex_];
634}
635
636
637int
638ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
639{
640 int offset = 0;
641 IteratorState it = x;
642 while ( !equals( it, y ) )
643 increment( it );
644 return offset;
645}
0646
=== added file 'plugin/json_server/json/json_reader.cpp'
--- plugin/json_server/json/json_reader.cpp 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/json_reader.cpp 2011-05-04 01:52:37 +0000
@@ -0,0 +1,921 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#include <config.h>
39
40#include <plugin/json_server/json/reader.h>
41#include <plugin/json_server/json/value.h>
42
43#include <cassert>
44#include <cstdio>
45#include <cstring>
46#include <iostream>
47#include <stdexcept>
48#include <utility>
49
50namespace Json {
51
52// Implementation of class Features
53// ////////////////////////////////
54
55Features::Features()
56 : allowComments_( true )
57 , strictRoot_( false )
58{
59}
60
61
62Features
63Features::all()
64{
65 return Features();
66}
67
68
69Features
70Features::strictMode()
71{
72 Features features;
73 features.allowComments_ = false;
74 features.strictRoot_ = true;
75 return features;
76}
77
78// Implementation of class Reader
79// ////////////////////////////////
80
81
82static inline bool
83in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
84{
85 return c == c1 || c == c2 || c == c3 || c == c4;
86}
87
88static inline bool
89in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
90{
91 return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
92}
93
94
95static bool
96containsNewLine( Reader::Location begin,
97 Reader::Location end )
98{
99 for ( ;begin < end; ++begin )
100 if ( *begin == '\n' || *begin == '\r' )
101 return true;
102 return false;
103}
104
105static std::string codePointToUTF8(unsigned int cp)
106{
107 std::string result;
108
109 // based on description from http://en.wikipedia.org/wiki/UTF-8
110
111 if (cp <= 0x7f)
112 {
113 result.resize(1);
114 result[0] = static_cast<char>(cp);
115 }
116 else if (cp <= 0x7FF)
117 {
118 result.resize(2);
119 result[1] = static_cast<char>(0x80 | (0x3f & cp));
120 result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
121 }
122 else if (cp <= 0xFFFF)
123 {
124 result.resize(3);
125 result[2] = static_cast<char>(0x80 | (0x3f & cp));
126 result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
127 result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
128 }
129 else if (cp <= 0x10FFFF)
130 {
131 result.resize(4);
132 result[3] = static_cast<char>(0x80 | (0x3f & cp));
133 result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
134 result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
135 result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
136 }
137
138 return result;
139}
140
141
142// Class Reader
143// //////////////////////////////////////////////////////////////////
144
145Reader::Reader()
146 : features_( Features::all() )
147{
148}
149
150
151Reader::Reader( const Features &features )
152 : features_( features )
153{
154}
155
156
157bool
158Reader::parse( const std::string &document,
159 Value &root,
160 bool collectComments )
161{
162 document_ = document;
163 const char *begin = document_.c_str();
164 const char *end = begin + document_.length();
165 return parse( begin, end, root, collectComments );
166}
167
168
169bool
170Reader::parse( std::istream& sin,
171 Value &root,
172 bool collectComments )
173{
174 //std::istream_iterator<char> begin(sin);
175 //std::istream_iterator<char> end;
176 // Those would allow streamed input from a file, if parse() were a
177 // template function.
178
179 // Since std::string is reference-counted, this at least does not
180 // create an extra copy.
181 std::string doc;
182 std::getline(sin, doc, (char)EOF);
183 return parse( doc, root, collectComments );
184}
185
186bool
187Reader::parse( const char *beginDoc, const char *endDoc,
188 Value &root,
189 bool collectComments )
190{
191 if ( !features_.allowComments_ )
192 {
193 collectComments = false;
194 }
195
196 begin_ = beginDoc;
197 end_ = endDoc;
198 collectComments_ = collectComments;
199 current_ = begin_;
200 lastValueEnd_ = 0;
201 lastValue_ = 0;
202 commentsBefore_ = "";
203 errors_.clear();
204 while ( !nodes_.empty() )
205 nodes_.pop();
206 nodes_.push( &root );
207
208 bool successful = readValue();
209 Token token;
210 skipCommentTokens( token );
211 if ( collectComments_ && !commentsBefore_.empty() )
212 root.setComment( commentsBefore_, commentAfter );
213 if ( features_.strictRoot_ )
214 {
215 if ( !root.isArray() && !root.isObject() )
216 {
217 // Set error location to start of doc, ideally should be first token found in doc
218 token.type_ = tokenError;
219 token.start_ = beginDoc;
220 token.end_ = endDoc;
221 addError( "A valid JSON document must be either an array or an object value.",
222 token );
223 return false;
224 }
225 }
226 return successful;
227}
228
229
230bool
231Reader::readValue()
232{
233 Token token;
234 skipCommentTokens( token );
235 bool successful = true;
236
237 if ( collectComments_ && !commentsBefore_.empty() )
238 {
239 currentValue().setComment( commentsBefore_, commentBefore );
240 commentsBefore_ = "";
241 }
242
243
244 switch ( token.type_ )
245 {
246 case tokenObjectBegin:
247 successful = readObject( token );
248 break;
249 case tokenArrayBegin:
250 successful = readArray( token );
251 break;
252 case tokenNumber:
253 successful = decodeNumber( token );
254 break;
255 case tokenString:
256 successful = decodeString( token );
257 break;
258 case tokenTrue:
259 currentValue() = true;
260 break;
261 case tokenFalse:
262 currentValue() = false;
263 break;
264 case tokenNull:
265 currentValue() = Value();
266 break;
267 default:
268 return addError( "Syntax error: value, object or array expected.", token );
269 }
270
271 if ( collectComments_ )
272 {
273 lastValueEnd_ = current_;
274 lastValue_ = &currentValue();
275 }
276
277 return successful;
278}
279
280
281void
282Reader::skipCommentTokens( Token &token )
283{
284 if ( features_.allowComments_ )
285 {
286 do
287 {
288 readToken( token );
289 }
290 while ( token.type_ == tokenComment );
291 }
292 else
293 {
294 readToken( token );
295 }
296}
297
298
299bool
300Reader::expectToken( TokenType type, Token &token, const char *message )
301{
302 readToken( token );
303 if ( token.type_ != type )
304 return addError( message, token );
305 return true;
306}
307
308
309bool
310Reader::readToken( Token &token )
311{
312 skipSpaces();
313 token.start_ = current_;
314 Char c = getNextChar();
315 bool ok = true;
316 switch ( c )
317 {
318 case '{':
319 token.type_ = tokenObjectBegin;
320 break;
321 case '}':
322 token.type_ = tokenObjectEnd;
323 break;
324 case '[':
325 token.type_ = tokenArrayBegin;
326 break;
327 case ']':
328 token.type_ = tokenArrayEnd;
329 break;
330 case '"':
331 token.type_ = tokenString;
332 ok = readString();
333 break;
334 case '/':
335 token.type_ = tokenComment;
336 ok = readComment();
337 break;
338 case '0':
339 case '1':
340 case '2':
341 case '3':
342 case '4':
343 case '5':
344 case '6':
345 case '7':
346 case '8':
347 case '9':
348 case '-':
349 token.type_ = tokenNumber;
350 readNumber();
351 break;
352 case 't':
353 token.type_ = tokenTrue;
354 ok = match( "rue", 3 );
355 break;
356 case 'f':
357 token.type_ = tokenFalse;
358 ok = match( "alse", 4 );
359 break;
360 case 'n':
361 token.type_ = tokenNull;
362 ok = match( "ull", 3 );
363 break;
364 case ',':
365 token.type_ = tokenArraySeparator;
366 break;
367 case ':':
368 token.type_ = tokenMemberSeparator;
369 break;
370 case 0:
371 token.type_ = tokenEndOfStream;
372 break;
373 default:
374 ok = false;
375 break;
376 }
377 if ( !ok )
378 token.type_ = tokenError;
379 token.end_ = current_;
380 return true;
381}
382
383
384void
385Reader::skipSpaces()
386{
387 while ( current_ != end_ )
388 {
389 Char c = *current_;
390 if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' )
391 ++current_;
392 else
393 break;
394 }
395}
396
397
398bool
399Reader::match( Location pattern,
400 int patternLength )
401{
402 if ( end_ - current_ < patternLength )
403 return false;
404 int index = patternLength;
405 while ( index-- )
406 if ( current_[index] != pattern[index] )
407 return false;
408 current_ += patternLength;
409 return true;
410}
411
412
413bool
414Reader::readComment()
415{
416 Location commentBegin = current_ - 1;
417 Char c = getNextChar();
418 bool successful = false;
419 if ( c == '*' )
420 successful = readCStyleComment();
421 else if ( c == '/' )
422 successful = readCppStyleComment();
423 if ( !successful )
424 return false;
425
426 if ( collectComments_ )
427 {
428 CommentPlacement placement = commentBefore;
429 if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) )
430 {
431 if ( c != '*' || !containsNewLine( commentBegin, current_ ) )
432 placement = commentAfterOnSameLine;
433 }
434
435 addComment( commentBegin, current_, placement );
436 }
437 return true;
438}
439
440
441void
442Reader::addComment( Location begin,
443 Location end,
444 CommentPlacement placement )
445{
446 assert( collectComments_ );
447 if ( placement == commentAfterOnSameLine )
448 {
449 assert( lastValue_ != 0 );
450 lastValue_->setComment( std::string( begin, end ), placement );
451 }
452 else
453 {
454 if ( !commentsBefore_.empty() )
455 commentsBefore_ += "\n";
456 commentsBefore_ += std::string( begin, end );
457 }
458}
459
460
461bool
462Reader::readCStyleComment()
463{
464 while ( current_ != end_ )
465 {
466 Char c = getNextChar();
467 if ( c == '*' && *current_ == '/' )
468 break;
469 }
470 return getNextChar() == '/';
471}
472
473
474bool
475Reader::readCppStyleComment()
476{
477 while ( current_ != end_ )
478 {
479 Char c = getNextChar();
480 if ( c == '\r' || c == '\n' )
481 break;
482 }
483 return true;
484}
485
486
487void
488Reader::readNumber()
489{
490 while ( current_ != end_ )
491 {
492 if ( !(*current_ >= '0' && *current_ <= '9') &&
493 !in( *current_, '.', 'e', 'E', '+', '-' ) )
494 break;
495 ++current_;
496 }
497}
498
499bool
500Reader::readString()
501{
502 Char c = 0;
503 while ( current_ != end_ )
504 {
505 c = getNextChar();
506 if ( c == '\\' )
507 getNextChar();
508 else if ( c == '"' )
509 break;
510 }
511 return c == '"';
512}
513
514
515bool
516Reader::readObject( Token & )
517{
518 Token tokenName;
519 std::string name;
520 currentValue() = Value( objectValue );
521 while ( readToken( tokenName ) )
522 {
523 bool initialTokenOk = true;
524 while ( tokenName.type_ == tokenComment && initialTokenOk )
525 initialTokenOk = readToken( tokenName );
526 if ( !initialTokenOk )
527 break;
528 if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object
529 return true;
530 if ( tokenName.type_ != tokenString )
531 break;
532
533 name = "";
534 if ( !decodeString( tokenName, name ) )
535 return recoverFromError( tokenObjectEnd );
536
537 Token colon;
538 if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
539 {
540 return addErrorAndRecover( "Missing ':' after object member name",
541 colon,
542 tokenObjectEnd );
543 }
544 Value &value = currentValue()[ name ];
545 nodes_.push( &value );
546 bool ok = readValue();
547 nodes_.pop();
548 if ( !ok ) // error already set
549 return recoverFromError( tokenObjectEnd );
550
551 Token comma;
552 if ( !readToken( comma )
553 || ( comma.type_ != tokenObjectEnd &&
554 comma.type_ != tokenArraySeparator &&
555 comma.type_ != tokenComment ) )
556 {
557 return addErrorAndRecover( "Missing ',' or '}' in object declaration",
558 comma,
559 tokenObjectEnd );
560 }
561 bool finalizeTokenOk = true;
562 while ( comma.type_ == tokenComment &&
563 finalizeTokenOk )
564 finalizeTokenOk = readToken( comma );
565 if ( comma.type_ == tokenObjectEnd )
566 return true;
567 }
568 return addErrorAndRecover( "Missing '}' or object member name",
569 tokenName,
570 tokenObjectEnd );
571}
572
573
574bool
575Reader::readArray( Token & )
576{
577 currentValue() = Value( arrayValue );
578 skipSpaces();
579 if ( *current_ == ']' ) // empty array
580 {
581 Token endArray;
582 readToken( endArray );
583 return true;
584 }
585 int index = 0;
586 while ( true )
587 {
588 Value &value = currentValue()[ index++ ];
589 nodes_.push( &value );
590 bool ok = readValue();
591 nodes_.pop();
592 if ( !ok ) // error already set
593 return recoverFromError( tokenArrayEnd );
594
595 Token token;
596 // Accept Comment after last item in the array.
597 ok = readToken( token );
598 while ( token.type_ == tokenComment && ok )
599 {
600 ok = readToken( token );
601 }
602 bool badTokenType = ( token.type_ == tokenArraySeparator &&
603 token.type_ == tokenArrayEnd );
604 if ( !ok || badTokenType )
605 {
606 return addErrorAndRecover( "Missing ',' or ']' in array declaration",
607 token,
608 tokenArrayEnd );
609 }
610 if ( token.type_ == tokenArrayEnd )
611 break;
612 }
613 return true;
614}
615
616
617bool
618Reader::decodeNumber( Token &token )
619{
620 bool isDouble = false;
621 for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
622 {
623 isDouble = isDouble
624 || in( *inspect, '.', 'e', 'E', '+' )
625 || ( *inspect == '-' && inspect != token.start_ );
626 }
627 if ( isDouble )
628 return decodeDouble( token );
629 Location current = token.start_;
630 bool isNegative = *current == '-';
631 if ( isNegative )
632 ++current;
633 Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt)
634 : Value::maxUInt) / 10;
635 Value::UInt value = 0;
636 while ( current < token.end_ )
637 {
638 Char c = *current++;
639 if ( c < '0' || c > '9' )
640 return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
641 if ( value >= threshold )
642 return decodeDouble( token );
643 value = value * 10 + Value::UInt(c - '0');
644 }
645 if ( isNegative )
646 currentValue() = -Value::Int( value );
647 else if ( value <= Value::UInt(Value::maxInt) )
648 currentValue() = Value::Int( value );
649 else
650 currentValue() = value;
651 return true;
652}
653
654
655bool
656Reader::decodeDouble( Token &token )
657{
658 double value = 0;
659 const int bufferSize = 32;
660 int count;
661 int length = int(token.end_ - token.start_);
662 if ( length <= bufferSize )
663 {
664 Char buffer[bufferSize];
665 memcpy( buffer, token.start_, length );
666 buffer[length] = 0;
667 count = sscanf( buffer, "%lf", &value );
668 }
669 else
670 {
671 std::string buffer( token.start_, token.end_ );
672 count = sscanf( buffer.c_str(), "%lf", &value );
673 }
674
675 if ( count != 1 )
676 return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
677 currentValue() = value;
678 return true;
679}
680
681
682bool
683Reader::decodeString( Token &token )
684{
685 std::string decoded;
686 if ( !decodeString( token, decoded ) )
687 return false;
688 currentValue() = decoded;
689 return true;
690}
691
692
693bool
694Reader::decodeString( Token &token, std::string &decoded )
695{
696 decoded.reserve( token.end_ - token.start_ - 2 );
697 Location current = token.start_ + 1; // skip '"'
698 Location end = token.end_ - 1; // do not include '"'
699 while ( current != end )
700 {
701 Char c = *current++;
702 if ( c == '"' )
703 break;
704 else if ( c == '\\' )
705 {
706 if ( current == end )
707 return addError( "Empty escape sequence in string", token, current );
708 Char escape = *current++;
709 switch ( escape )
710 {
711 case '"': decoded += '"'; break;
712 case '/': decoded += '/'; break;
713 case '\\': decoded += '\\'; break;
714 case 'b': decoded += '\b'; break;
715 case 'f': decoded += '\f'; break;
716 case 'n': decoded += '\n'; break;
717 case 'r': decoded += '\r'; break;
718 case 't': decoded += '\t'; break;
719 case 'u':
720 {
721 unsigned int unicode;
722 if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
723 return false;
724 decoded += codePointToUTF8(unicode);
725 }
726 break;
727 default:
728 return addError( "Bad escape sequence in string", token, current );
729 }
730 }
731 else
732 {
733 decoded += c;
734 }
735 }
736 return true;
737}
738
739bool
740Reader::decodeUnicodeCodePoint( Token &token,
741 Location &current,
742 Location end,
743 unsigned int &unicode )
744{
745
746 if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
747 return false;
748 if (unicode >= 0xD800 && unicode <= 0xDBFF)
749 {
750 // surrogate pairs
751 if (end - current < 6)
752 return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
753 unsigned int surrogatePair;
754 if (*(current++) == '\\' && *(current++)== 'u')
755 {
756 if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
757 {
758 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
759 }
760 else
761 return false;
762 }
763 else
764 return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
765 }
766 return true;
767}
768
769bool
770Reader::decodeUnicodeEscapeSequence( Token &token,
771 Location &current,
772 Location end,
773 unsigned int &unicode )
774{
775 if ( end - current < 4 )
776 return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
777 unicode = 0;
778 for ( int index =0; index < 4; ++index )
779 {
780 Char c = *current++;
781 unicode *= 16;
782 if ( c >= '0' && c <= '9' )
783 unicode += c - '0';
784 else if ( c >= 'a' && c <= 'f' )
785 unicode += c - 'a' + 10;
786 else if ( c >= 'A' && c <= 'F' )
787 unicode += c - 'A' + 10;
788 else
789 return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
790 }
791 return true;
792}
793
794
795bool
796Reader::addError( const std::string &message,
797 Token &token,
798 Location extra )
799{
800 ErrorInfo info;
801 info.token_ = token;
802 info.message_ = message;
803 info.extra_ = extra;
804 errors_.push_back( info );
805 return false;
806}
807
808
809bool
810Reader::recoverFromError( TokenType skipUntilToken )
811{
812 int errorCount = int(errors_.size());
813 Token skip;
814 while ( true )
815 {
816 if ( !readToken(skip) )
817 errors_.resize( errorCount ); // discard errors caused by recovery
818 if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
819 break;
820 }
821 errors_.resize( errorCount );
822 return false;
823}
824
825
826bool
827Reader::addErrorAndRecover( const std::string &message,
828 Token &token,
829 TokenType skipUntilToken )
830{
831 addError( message, token );
832 return recoverFromError( skipUntilToken );
833}
834
835
836Value &
837Reader::currentValue()
838{
839 return *(nodes_.top());
840}
841
842
843Reader::Char
844Reader::getNextChar()
845{
846 if ( current_ == end_ )
847 return 0;
848 return *current_++;
849}
850
851
852void
853Reader::getLocationLineAndColumn( Location location,
854 int &line,
855 int &column ) const
856{
857 Location current = begin_;
858 Location lastLineStart = current;
859 line = 0;
860 while ( current < location && current != end_ )
861 {
862 Char c = *current++;
863 if ( c == '\r' )
864 {
865 if ( *current == '\n' )
866 ++current;
867 lastLineStart = current;
868 ++line;
869 }
870 else if ( c == '\n' )
871 {
872 lastLineStart = current;
873 ++line;
874 }
875 }
876 // column & line start at 1
877 column = int(location - lastLineStart) + 1;
878 ++line;
879}
880
881
882std::string
883Reader::getLocationLineAndColumn( Location location ) const
884{
885 int line, column;
886 getLocationLineAndColumn( location, line, column );
887 char buffer[18+16+16+1];
888 sprintf( buffer, "Line %d, Column %d", line, column );
889 return buffer;
890}
891
892
893std::string
894Reader::getFormatedErrorMessages() const
895{
896 std::string formattedMessage;
897 for ( Errors::const_iterator itError = errors_.begin();
898 itError != errors_.end();
899 ++itError )
900 {
901 const ErrorInfo &error = *itError;
902 formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
903 formattedMessage += " " + error.message_ + "\n";
904 if ( error.extra_ )
905 formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
906 }
907 return formattedMessage;
908}
909
910
911std::istream& operator>>( std::istream &sin, Value &root )
912{
913 Json::Reader reader;
914 bool ok = reader.parse(sin, root, true);
915 //JSON_ASSERT( ok );
916 if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
917 return sin;
918}
919
920
921} // namespace Json
0922
=== added file 'plugin/json_server/json/json_value.cpp'
--- plugin/json_server/json/json_value.cpp 1970-01-01 00:00:00 +0000
+++ plugin/json_server/json/json_value.cpp 2011-05-04 01:52:37 +0000
@@ -0,0 +1,1759 @@
1/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * JSON Library, originally from http://jsoncpp.sourceforge.net/
4 *
5 * Copyright (C) 2011 Stewart Smith
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#include <config.h>
39
40#include <plugin/json_server/json/value.h>
41#include <plugin/json_server/json/writer.h>
42
43#include <cassert>
44#include <cstring>
45#include <iostream>
46#include <stdexcept>
47#include <utility>
48
49#ifdef JSON_USE_CPPTL
50# include <cpptl/conststring.h>
51#endif
52#include <cstddef> // size_t
53#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
54# include "json_batchallocator.h"
55#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
56
57#define JSON_ASSERT_UNREACHABLE assert( false )
58#define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw
59#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) throw std::runtime_error( message );
60
61namespace Json {
62
63const Value Value::null;
64const Int Value::minInt = Int( ~(UInt(-1)/2) );
65const Int Value::maxInt = Int( UInt(-1)/2 );
66const UInt Value::maxUInt = UInt(-1);
67
68// A "safe" implementation of strdup. Allow null pointer to be passed.
69// Also avoid warning on msvc80.
70//
71//inline char *safeStringDup( const char *czstring )
72//{
73// if ( czstring )
74// {
75// const size_t length = (unsigned int)( strlen(czstring) + 1 );
76// char *newString = static_cast<char *>( malloc( length ) );
77// memcpy( newString, czstring, length );
78// return newString;
79// }
80// return 0;
81//}
82//
83//inline char *safeStringDup( const std::string &str )
84//{
85// if ( !str.empty() )
86// {
87// const size_t length = str.length();
88// char *newString = static_cast<char *>( malloc( length + 1 ) );
89// memcpy( newString, str.c_str(), length );
90// newString[length] = 0;
91// return newString;
92// }
93// return 0;
94//}
95
96ValueAllocator::~ValueAllocator()
97{
98}
99
100class DefaultValueAllocator : public ValueAllocator
101{
102public:
103 virtual ~DefaultValueAllocator()
104 {
105 }
106
107 virtual char *makeMemberName( const char *memberName )
108 {
109 return duplicateStringValue( memberName );
110 }
111
112 virtual void releaseMemberName( char *memberName )
113 {
114 releaseStringValue( memberName );
115 }
116
117 virtual char *duplicateStringValue( const char *value,
118 unsigned int length = unknown )
119 {
120 //@todo invesgate this old optimization
121 //if ( !value || value[0] == 0 )
122 // return 0;
123
124 if ( length == unknown )
125 length = (unsigned int)strlen(value);
126 char *newString = static_cast<char *>( malloc( length + 1 ) );
127 memcpy( newString, value, length );
128 newString[length] = 0;
129 return newString;
130 }
131
132 virtual void releaseStringValue( char *value )
133 {
134 if ( value )
135 free( value );
136 }
137};
138
139static ValueAllocator *&valueAllocator()
140{
141 static DefaultValueAllocator defaultAllocator;
142 static ValueAllocator *valueAllocator = &defaultAllocator;
143 return valueAllocator;
144}
145
146static struct DummyValueAllocatorInitializer {
147 DummyValueAllocatorInitializer()
148 {
149 valueAllocator(); // ensure valueAllocator() statics are initialized before main().
150 }
151} dummyValueAllocatorInitializer;
152
153
154
155// //////////////////////////////////////////////////////////////////
156// //////////////////////////////////////////////////////////////////
157// //////////////////////////////////////////////////////////////////
158// ValueInternals...
159// //////////////////////////////////////////////////////////////////
160// //////////////////////////////////////////////////////////////////
161// //////////////////////////////////////////////////////////////////
162#ifdef JSON_VALUE_USE_INTERNAL_MAP
163# include "json_internalarray.inl"
164# include "json_internalmap.inl"
165#endif // JSON_VALUE_USE_INTERNAL_MAP
166
167# include "json_valueiterator.inl"
168
169
170// //////////////////////////////////////////////////////////////////
171// //////////////////////////////////////////////////////////////////
172// //////////////////////////////////////////////////////////////////
173// class Value::CommentInfo
174// //////////////////////////////////////////////////////////////////
175// //////////////////////////////////////////////////////////////////
176// //////////////////////////////////////////////////////////////////
177
178
179Value::CommentInfo::CommentInfo()
180 : comment_( 0 )
181{
182}
183
184Value::CommentInfo::~CommentInfo()
185{
186 if ( comment_ )
187 valueAllocator()->releaseStringValue( comment_ );
188}
189
190
191void
192Value::CommentInfo::setComment( const char *text )
193{
194 if ( comment_ )
195 valueAllocator()->releaseStringValue( comment_ );
196 JSON_ASSERT( text );
197 JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /");
198 // It seems that /**/ style comments are acceptable as well.
199 comment_ = valueAllocator()->duplicateStringValue( text );
200}
201
202
203// //////////////////////////////////////////////////////////////////
204// //////////////////////////////////////////////////////////////////
205// //////////////////////////////////////////////////////////////////
206// class Value::CZString
207// //////////////////////////////////////////////////////////////////
208// //////////////////////////////////////////////////////////////////
209// //////////////////////////////////////////////////////////////////
210# ifndef JSON_VALUE_USE_INTERNAL_MAP
211
212// Notes: index_ indicates if the string was allocated when
213// a string is stored.
214
215Value::CZString::CZString( int index_arg )
216 : cstr_( 0 )
217 , index_( index_arg )
218{
219}
220
221Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate )
222 : cstr_( allocate == duplicate ? valueAllocator()->makeMemberName(cstr)
223 : cstr )
224 , index_( allocate )
225{
226}
227
228Value::CZString::CZString( const CZString &other )
229: cstr_( other.index_ != noDuplication && other.cstr_ != 0
230 ? valueAllocator()->makeMemberName( other.cstr_ )
231 : other.cstr_ )
232 , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)
233 : other.index_ )
234{
235}
236
237Value::CZString::~CZString()
238{
239 if ( cstr_ && index_ == duplicate )
240 valueAllocator()->releaseMemberName( const_cast<char *>( cstr_ ) );
241}
242
243void
244Value::CZString::swap( CZString &other )
245{
246 std::swap( cstr_, other.cstr_ );
247 std::swap( index_, other.index_ );
248}
249
250Value::CZString &
251Value::CZString::operator =( const CZString &other )
252{
253 CZString temp( other );
254 swap( temp );
255 return *this;
256}
257
258bool
259Value::CZString::operator<( const CZString &other ) const
260{
261 if ( cstr_ )
262 return strcmp( cstr_, other.cstr_ ) < 0;
263 return index_ < other.index_;
264}
265
266bool
267Value::CZString::operator==( const CZString &other ) const
268{
269 if ( cstr_ )
270 return strcmp( cstr_, other.cstr_ ) == 0;
271 return index_ == other.index_;
272}
273
274
275int
276Value::CZString::index() const
277{
278 return index_;
279}
280
281
282const char *
283Value::CZString::c_str() const
284{
285 return cstr_;
286}
287
288bool
289Value::CZString::isStaticString() const
290{
291 return index_ == noDuplication;
292}
293
294#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
295
296
297// //////////////////////////////////////////////////////////////////
298// //////////////////////////////////////////////////////////////////
299// //////////////////////////////////////////////////////////////////
300// class Value::Value
301// //////////////////////////////////////////////////////////////////
302// //////////////////////////////////////////////////////////////////
303// //////////////////////////////////////////////////////////////////
304
305/*! \internal Default constructor initialization must be equivalent to:
306 * memset( this, 0, sizeof(Value) )
307 * This optimization is used in ValueInternalMap fast allocator.
308 */
309Value::Value( ValueType type_arg )
310 : type_( type_arg )
311 , allocated_( 0 )
312 , comments_( 0 )
313# ifdef JSON_VALUE_USE_INTERNAL_MAP
314 , itemIsUsed_( 0 )
315#endif
316{
317 switch ( type_arg )
318 {
319 case nullValue:
320 break;
321 case intValue:
322 case uintValue:
323 value_.int_ = 0;
324 break;
325 case realValue:
326 value_.real_ = 0.0;
327 break;
328 case stringValue:
329 value_.string_ = 0;
330 break;
331#ifndef JSON_VALUE_USE_INTERNAL_MAP
332 case arrayValue:
333 case objectValue:
334 value_.map_ = new ObjectValues();
335 break;
336#else
337 case arrayValue:
338 value_.array_ = arrayAllocator()->newArray();
339 break;
340 case objectValue:
341 value_.map_ = mapAllocator()->newMap();
342 break;
343#endif
344 case booleanValue:
345 value_.bool_ = false;
346 break;
347 default:
348 JSON_ASSERT_UNREACHABLE;
349 }
350}
351
352
353Value::Value( Int value )
354 : type_( intValue )
355 , comments_( 0 )
356# ifdef JSON_VALUE_USE_INTERNAL_MAP
357 , itemIsUsed_( 0 )
358#endif
359{
360 value_.int_ = value;
361}
362
363
364Value::Value( UInt value )
365 : type_( uintValue )
366 , comments_( 0 )
367# ifdef JSON_VALUE_USE_INTERNAL_MAP
368 , itemIsUsed_( 0 )
369#endif
370{
371 value_.uint_ = value;
372}
373
374Value::Value( double value )
375 : type_( realValue )
376 , comments_( 0 )
377# ifdef JSON_VALUE_USE_INTERNAL_MAP
378 , itemIsUsed_( 0 )
379#endif
380{
381 value_.real_ = value;
382}
383
384Value::Value( const char *value )
385 : type_( stringValue )
386 , allocated_( true )
387 , comments_( NULL )
388# ifdef JSON_VALUE_USE_INTERNAL_MAP
389 , itemIsUsed_( 0 )
390#endif
391{
392 value_.string_ = valueAllocator()->duplicateStringValue( value );
393}
394
395
396Value::Value( const char *beginValue,
397 const char *endValue )
398 : type_( stringValue )
399 , allocated_( true )
400 , comments_( NULL )
401# ifdef JSON_VALUE_USE_INTERNAL_MAP
402 , itemIsUsed_( 0 )
403#endif
404{
405 value_.string_ = valueAllocator()->duplicateStringValue( beginValue,
406 UInt(endValue - beginValue) );
407}
408
409
410Value::Value( const std::string &value )
411 : type_( stringValue )
412 , allocated_( true )
413 , comments_( 0 )
414# ifdef JSON_VALUE_USE_INTERNAL_MAP
415 , itemIsUsed_( 0 )
416#endif
417{
418 value_.string_ = valueAllocator()->duplicateStringValue( value.c_str(),
419 (unsigned int)value.length() );
420
421}
422
423Value::Value( const StaticString &value )
424 : type_( stringValue )
425 , allocated_( false )
426 , comments_( 0 )
427# ifdef JSON_VALUE_USE_INTERNAL_MAP
428 , itemIsUsed_( 0 )
429#endif
430{
431 value_.string_ = const_cast<char *>( value.c_str() );
432}
433
434
435# ifdef JSON_USE_CPPTL
436Value::Value( const CppTL::ConstString &value )
437 : type_( stringValue )
438 , allocated_( true )
439 , comments_( 0 )
440# ifdef JSON_VALUE_USE_INTERNAL_MAP
441 , itemIsUsed_( 0 )
442#endif
443{
444 value_.string_ = valueAllocator()->duplicateStringValue( value, value.length() );
445}
446# endif
447
448Value::Value( bool value )
449 : type_( booleanValue )
450 , comments_( 0 )
451# ifdef JSON_VALUE_USE_INTERNAL_MAP
452 , itemIsUsed_( 0 )
453#endif
454{
455 value_.bool_ = value;
456}
457
458
459Value::Value( const Value &other )
460 : type_( other.type_ )
461 , comments_( 0 )
462# ifdef JSON_VALUE_USE_INTERNAL_MAP
463 , itemIsUsed_( 0 )
464#endif
465{
466 switch ( type_ )
467 {
468 case nullValue:
469 case intValue:
470 case uintValue:
471 case realValue:
472 case booleanValue:
473 value_ = other.value_;
474 break;
475 case stringValue:
476 if ( other.value_.string_ )
477 {
478 value_.string_ = valueAllocator()->duplicateStringValue( other.value_.string_ );
479 allocated_ = true;
480 }
481 else
482 value_.string_ = 0;
483 break;
484#ifndef JSON_VALUE_USE_INTERNAL_MAP
485 case arrayValue:
486 case objectValue:
487 value_.map_ = new ObjectValues( *other.value_.map_ );
488 break;
489#else
490 case arrayValue:
491 value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ );
492 break;
493 case objectValue:
494 value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ );
495 break;
496#endif
497 default:
498 JSON_ASSERT_UNREACHABLE;
499 }
500 if ( other.comments_ )
501 {
502 comments_ = new CommentInfo[numberOfCommentPlacement];
503 for ( int comment =0; comment < numberOfCommentPlacement; ++comment )
504 {
505 const CommentInfo &otherComment = other.comments_[comment];
506 if ( otherComment.comment_ )
507 comments_[comment].setComment( otherComment.comment_ );
508 }
509 }
510}
511
512
513Value::~Value()
514{
515 switch ( type_ )
516 {
517 case nullValue:
518 case intValue:
519 case uintValue:
520 case realValue:
521 case booleanValue:
522 break;
523 case stringValue:
524 if ( allocated_ )
525 valueAllocator()->releaseStringValue( value_.string_ );
526 break;
527#ifndef JSON_VALUE_USE_INTERNAL_MAP
528 case arrayValue:
529 case objectValue:
530 delete value_.map_;
531 break;
532#else
533 case arrayValue:
534 arrayAllocator()->destructArray( value_.array_ );
535 break;
536 case objectValue:
537 mapAllocator()->destructMap( value_.map_ );
538 break;
539#endif
540 default:
541 JSON_ASSERT_UNREACHABLE;
542 }
543
544 if ( comments_ )
545 delete[] comments_;
546}
547
548Value &
549Value::operator=( const Value &other )
550{
551 Value temp( other );
552 swap( temp );
553 return *this;
554}
555
556void
557Value::swap( Value &other )
558{
559 ValueType temp = type_;
560 type_ = other.type_;
561 other.type_ = temp;
562 std::swap( value_, other.value_ );
563 int temp2 = allocated_;
564 allocated_ = other.allocated_;
565 other.allocated_ = temp2;
566}
567
568ValueType
569Value::type() const
570{
571 return type_;
572}
573
574
575int
576Value::compare( const Value & )
577{
578 /*
579 int typeDelta = other.type_ - type_;
580 switch ( type_ )
581 {
582 case nullValue:
583
584 return other.type_ == type_;
585 case intValue:
586 if ( other.type_.isNumeric()
587 case uintValue:
588 case realValue:
589 case booleanValue:
590 break;
591 case stringValue,
592 break;
593 case arrayValue:
594 delete value_.array_;
595 break;
596 case objectValue:
597 delete value_.map_;
598 default:
599 JSON_ASSERT_UNREACHABLE;
600 }
601 */
602 return 0; // unreachable
603}
604
605bool
606Value::operator <( const Value &other ) const
607{
608 int typeDelta = type_ - other.type_;
609 if ( typeDelta )
610 return typeDelta < 0 ? true : false;
611 switch ( type_ )
612 {
613 case nullValue:
614 return false;
615 case intValue:
616 return value_.int_ < other.value_.int_;
617 case uintValue:
618 return value_.uint_ < other.value_.uint_;
619 case realValue:
620 return value_.real_ < other.value_.real_;
621 case booleanValue:
622 return value_.bool_ < other.value_.bool_;
623 case stringValue:
624 return ( value_.string_ == 0 && other.value_.string_ )
625 || ( other.value_.string_
626 && value_.string_
627 && strcmp( value_.string_, other.value_.string_ ) < 0 );
628#ifndef JSON_VALUE_USE_INTERNAL_MAP
629 case arrayValue:
630 case objectValue:
631 {
632 int delta = int( value_.map_->size() - other.value_.map_->size() );
633 if ( delta )
634 return delta < 0;
635 return (*value_.map_) < (*other.value_.map_);
636 }
637#else
638 case arrayValue:
639 return value_.array_->compare( *(other.value_.array_) ) < 0;
640 case objectValue:
641 return value_.map_->compare( *(other.value_.map_) ) < 0;
642#endif
643 default:
644 JSON_ASSERT_UNREACHABLE;
645 }
646 return 0; // unreachable
647}
648
649bool
650Value::operator <=( const Value &other ) const
651{
652 return !(other > *this);
653}
654
655bool
656Value::operator >=( const Value &other ) const
657{
658 return !(*this < other);
659}
660
661bool
662Value::operator >( const Value &other ) const
663{
664 return other < *this;
665}
666
667bool
668Value::operator ==( const Value &other ) const
669{
670 //if ( type_ != other.type_ )
671 // GCC 2.95.3 says:
672 // attempt to take address of bit-field structure member `Json::Value::type_'
673 // Beats me, but a temp solves the problem.
674 int temp = other.type_;
675 if ( type_ != temp )
676 return false;
677 switch ( type_ )
678 {
679 case nullValue:
680 return true;
681 case intValue:
682 return value_.int_ == other.value_.int_;
683 case uintValue:
684 return value_.uint_ == other.value_.uint_;
685 case realValue:
686 return value_.real_ == other.value_.real_;
687 case booleanValue:
688 return value_.bool_ == other.value_.bool_;
689 case stringValue:
690 return ( value_.string_ == other.value_.string_ )
691 || ( other.value_.string_
692 && value_.string_
693 && strcmp( value_.string_, other.value_.string_ ) == 0 );
694#ifndef JSON_VALUE_USE_INTERNAL_MAP
695 case arrayValue:
696 case objectValue:
697 return value_.map_->size() == other.value_.map_->size()
698 && (*value_.map_) == (*other.value_.map_);
699#else
700 case arrayValue:
701 return value_.array_->compare( *(other.value_.array_) ) == 0;
702 case objectValue:
703 return value_.map_->compare( *(other.value_.map_) ) == 0;
704#endif
705 default:
706 JSON_ASSERT_UNREACHABLE;
707 }
708 return 0; // unreachable
709}
710
711bool
712Value::operator !=( const Value &other ) const
713{
714 return !( *this == other );
715}
716
717const char *
718Value::asCString() const
719{
720 JSON_ASSERT( type_ == stringValue );
721 return value_.string_;
722}
723
724
725std::string
726Value::asString() const
727{
728 switch ( type_ )
729 {
730 case nullValue:
731 return "";
732 case stringValue:
733 return value_.string_ ? value_.string_ : "";
734 case booleanValue:
735 return value_.bool_ ? "true" : "false";
736 case intValue:
737 case uintValue:
738 case realValue:
739 case arrayValue:
740 case objectValue:
741 JSON_ASSERT_MESSAGE( false, "Type is not convertible to string" );
742 default:
743 JSON_ASSERT_UNREACHABLE;
744 }
745 return ""; // unreachable
746}
747
748# ifdef JSON_USE_CPPTL
749CppTL::ConstString
750Value::asConstString() const
751{
752 return CppTL::ConstString( asString().c_str() );
753}
754# endif
755
756Value::Int
757Value::asInt() const
758{
759 switch ( type_ )
760 {
761 case nullValue:
762 return 0;
763 case intValue:
764 return value_.int_;
765 case uintValue:
766 JSON_ASSERT_MESSAGE( value_.uint_ < (unsigned)maxInt, "integer out of signed integer range" );
767 return value_.uint_;
768 case realValue:
769 JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" );
770 return Int( value_.real_ );
771 case booleanValue:
772 return value_.bool_ ? 1 : 0;
773 case stringValue:
774 case arrayValue:
775 case objectValue:
776 JSON_ASSERT_MESSAGE( false, "Type is not convertible to int" );
777 default:
778 JSON_ASSERT_UNREACHABLE;
779 }
780 return 0; // unreachable;
781}
782
783Value::UInt
784Value::asUInt() const
785{
786 switch ( type_ )
787 {
788 case nullValue:
789 return 0;
790 case intValue:
791 JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" );
792 return value_.int_;
793 case uintValue:
794 return value_.uint_;
795 case realValue:
796 JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" );
797 return UInt( value_.real_ );
798 case booleanValue:
799 return value_.bool_ ? 1 : 0;
800 case stringValue:
801 case arrayValue:
802 case objectValue:
803 JSON_ASSERT_MESSAGE( false, "Type is not convertible to uint" );
804 default:
805 JSON_ASSERT_UNREACHABLE;
806 }
807 return 0; // unreachable;
808}
809
810double
811Value::asDouble() const
812{
813 switch ( type_ )
814 {
815 case nullValue:
816 return 0.0;
817 case intValue: