/Users/deen/code/yugabyte-db/src/yb/rocksdb/utilities/document/json_document.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | #ifndef ROCKSDB_LITE |
21 | | |
22 | | #include "yb/rocksdb/utilities/json_document.h" |
23 | | |
24 | | #ifndef __STDC_FORMAT_MACROS |
25 | | #define __STDC_FORMAT_MACROS |
26 | | #endif |
27 | | |
28 | | #include <assert.h> |
29 | | #include <inttypes.h> |
30 | | #include <string.h> |
31 | | |
32 | | #include <functional> |
33 | | #include <limits> |
34 | | #include <map> |
35 | | #include <memory> |
36 | | #include <string> |
37 | | #include <vector> |
38 | | |
39 | | |
40 | | #include "yb/rocksdb/third-party/fbson/FbsonDocument.h" |
41 | | #include "yb/rocksdb/third-party/fbson/FbsonJsonParser.h" |
42 | | #include "yb/rocksdb/third-party/fbson/FbsonUtil.h" |
43 | | #include "yb/rocksdb/util/coding.h" |
44 | | |
45 | | namespace { |
46 | | |
47 | | using namespace std::placeholders; |
48 | | |
49 | 50 | size_t ObjectNumElem(const fbson::ObjectVal& objectVal) { |
50 | 50 | size_t size = 0; |
51 | 88 | for (auto keyValuePair : objectVal) { |
52 | 88 | (void)keyValuePair; |
53 | 88 | ++size; |
54 | 88 | } |
55 | 50 | return size; |
56 | 50 | } |
57 | | |
58 | | template <typename Func> |
59 | | void InitJSONDocument(std::unique_ptr<char[]>* data, |
60 | | fbson::FbsonValue** value, |
61 | 79 | Func f) { |
62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? |
63 | 79 | fbson::FbsonWriter writer; |
64 | 79 | bool res __attribute__((unused)) = writer.writeStartArray(); |
65 | 79 | assert(res); |
66 | 79 | uint32_t bytesWritten __attribute__((unused)) = f(writer); |
67 | 79 | assert(bytesWritten != 0); |
68 | 79 | res = writer.writeEndArray(); |
69 | 79 | assert(res); |
70 | 79 | char* buf = new char[writer.getOutput()->getSize()]; |
71 | 79 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); |
72 | | |
73 | 79 | *value = ((fbson::FbsonDocument *)buf)->getValue(); |
74 | 79 | assert((*value)->isArray()); |
75 | 79 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); |
76 | 79 | *value = ((fbson::ArrayVal*)*value)->get(0); |
77 | 79 | data->reset(buf); |
78 | 79 | } json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIZNS_10InitStringEPNS1_10unique_ptrIA_cNS1_14default_deleteIS4_EEEEPPN5fbson10FbsonValueERKNS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEE3$_0JRKNS1_12placeholders4__phILi1EEESK_EEEEEvS8_SC_T_ Line | Count | Source | 61 | 8 | Func f) { | 62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? | 63 | 8 | fbson::FbsonWriter writer; | 64 | 8 | bool res __attribute__((unused)) = writer.writeStartArray(); | 65 | 8 | assert(res); | 66 | 8 | uint32_t bytesWritten __attribute__((unused)) = f(writer); | 67 | 8 | assert(bytesWritten != 0); | 68 | 8 | res = writer.writeEndArray(); | 69 | 8 | assert(res); | 70 | 8 | char* buf = new char[writer.getOutput()->getSize()]; | 71 | 8 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); | 72 | | | 73 | 8 | *value = ((fbson::FbsonDocument *)buf)->getValue(); | 74 | 8 | assert((*value)->isArray()); | 75 | 8 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); | 76 | 8 | *value = ((fbson::ArrayVal*)*value)->get(0); | 77 | 8 | data->reset(buf); | 78 | 8 | } |
json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjvEJRKNS1_12placeholders4__phILi1EEEEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISG_EEEEPPNS3_10FbsonValueET_ Line | Count | Source | 61 | 42 | Func f) { | 62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? | 63 | 42 | fbson::FbsonWriter writer; | 64 | 42 | bool res __attribute__((unused)) = writer.writeStartArray(); | 65 | 42 | assert(res); | 66 | 42 | uint32_t bytesWritten __attribute__((unused)) = f(writer); | 67 | 42 | assert(bytesWritten != 0); | 68 | 42 | res = writer.writeEndArray(); | 69 | 42 | assert(res); | 70 | 42 | char* buf = new char[writer.getOutput()->getSize()]; | 71 | 42 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); | 72 | | | 73 | 42 | *value = ((fbson::FbsonDocument *)buf)->getValue(); | 74 | 42 | assert((*value)->isArray()); | 75 | 42 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); | 76 | 42 | *value = ((fbson::ArrayVal*)*value)->get(0); | 77 | 42 | data->reset(buf); | 78 | 42 | } |
json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjbEJRKNS1_12placeholders4__phILi1EEERbEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISH_EEEEPPNS3_10FbsonValueET_ Line | Count | Source | 61 | 9 | Func f) { | 62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? | 63 | 9 | fbson::FbsonWriter writer; | 64 | 9 | bool res __attribute__((unused)) = writer.writeStartArray(); | 65 | 9 | assert(res); | 66 | 9 | uint32_t bytesWritten __attribute__((unused)) = f(writer); | 67 | 9 | assert(bytesWritten != 0); | 68 | 9 | res = writer.writeEndArray(); | 69 | 9 | assert(res); | 70 | 9 | char* buf = new char[writer.getOutput()->getSize()]; | 71 | 9 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); | 72 | | | 73 | 9 | *value = ((fbson::FbsonDocument *)buf)->getValue(); | 74 | 9 | assert((*value)->isArray()); | 75 | 9 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); | 76 | 9 | *value = ((fbson::ArrayVal*)*value)->get(0); | 77 | 9 | data->reset(buf); | 78 | 9 | } |
json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjdEJRKNS1_12placeholders4__phILi1EEERdEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISH_EEEEPPNS3_10FbsonValueET_ Line | Count | Source | 61 | 6 | Func f) { | 62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? | 63 | 6 | fbson::FbsonWriter writer; | 64 | 6 | bool res __attribute__((unused)) = writer.writeStartArray(); | 65 | 6 | assert(res); | 66 | 6 | uint32_t bytesWritten __attribute__((unused)) = f(writer); | 67 | 6 | assert(bytesWritten != 0); | 68 | 6 | res = writer.writeEndArray(); | 69 | 6 | assert(res); | 70 | 6 | char* buf = new char[writer.getOutput()->getSize()]; | 71 | 6 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); | 72 | | | 73 | 6 | *value = ((fbson::FbsonDocument *)buf)->getValue(); | 74 | 6 | assert((*value)->isArray()); | 75 | 6 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); | 76 | 6 | *value = ((fbson::ArrayVal*)*value)->get(0); | 77 | 6 | data->reset(buf); | 78 | 6 | } |
Unexecuted instantiation: json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjaEJRKNS1_12placeholders4__phILi1EEERaEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISH_EEEEPPNS3_10FbsonValueET_ Unexecuted instantiation: json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjsEJRKNS1_12placeholders4__phILi1EEERsEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISH_EEEEPPNS3_10FbsonValueET_ json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjiEJRKNS1_12placeholders4__phILi1EEERiEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISH_EEEEPPNS3_10FbsonValueET_ Line | Count | Source | 61 | 2 | Func f) { | 62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? | 63 | 2 | fbson::FbsonWriter writer; | 64 | 2 | bool res __attribute__((unused)) = writer.writeStartArray(); | 65 | 2 | assert(res); | 66 | 2 | uint32_t bytesWritten __attribute__((unused)) = f(writer); | 67 | 2 | assert(bytesWritten != 0); | 68 | 2 | res = writer.writeEndArray(); | 69 | 2 | assert(res); | 70 | 2 | char* buf = new char[writer.getOutput()->getSize()]; | 71 | 2 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); | 72 | | | 73 | 2 | *value = ((fbson::FbsonDocument *)buf)->getValue(); | 74 | 2 | assert((*value)->isArray()); | 75 | 2 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); | 76 | 2 | *value = ((fbson::ArrayVal*)*value)->get(0); | 77 | 2 | data->reset(buf); | 78 | 2 | } |
json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjxEJRKNS1_12placeholders4__phILi1EEERxEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISH_EEEEPPNS3_10FbsonValueET_ Line | Count | Source | 61 | 9 | Func f) { | 62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? | 63 | 9 | fbson::FbsonWriter writer; | 64 | 9 | bool res __attribute__((unused)) = writer.writeStartArray(); | 65 | 9 | assert(res); | 66 | 9 | uint32_t bytesWritten __attribute__((unused)) = f(writer); | 67 | 9 | assert(bytesWritten != 0); | 68 | 9 | res = writer.writeEndArray(); | 69 | 9 | assert(res); | 70 | 9 | char* buf = new char[writer.getOutput()->getSize()]; | 71 | 9 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); | 72 | | | 73 | 9 | *value = ((fbson::FbsonDocument *)buf)->getValue(); | 74 | 9 | assert((*value)->isArray()); | 75 | 9 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); | 76 | 9 | *value = ((fbson::ArrayVal*)*value)->get(0); | 77 | 9 | data->reset(buf); | 78 | 9 | } |
json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjbEJRKNS1_12placeholders4__phILi1EEEbEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISG_EEEEPPNS3_10FbsonValueET_ Line | Count | Source | 61 | 1 | Func f) { | 62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? | 63 | 1 | fbson::FbsonWriter writer; | 64 | 1 | bool res __attribute__((unused)) = writer.writeStartArray(); | 65 | 1 | assert(res); | 66 | 1 | uint32_t bytesWritten __attribute__((unused)) = f(writer); | 67 | 1 | assert(bytesWritten != 0); | 68 | 1 | res = writer.writeEndArray(); | 69 | 1 | assert(res); | 70 | 1 | char* buf = new char[writer.getOutput()->getSize()]; | 71 | 1 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); | 72 | | | 73 | 1 | *value = ((fbson::FbsonDocument *)buf)->getValue(); | 74 | 1 | assert((*value)->isArray()); | 75 | 1 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); | 76 | 1 | *value = ((fbson::ArrayVal*)*value)->get(0); | 77 | 1 | data->reset(buf); | 78 | 1 | } |
json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjdEJRKNS1_12placeholders4__phILi1EEEdEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISG_EEEEPPNS3_10FbsonValueET_ Line | Count | Source | 61 | 1 | Func f) { | 62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? | 63 | 1 | fbson::FbsonWriter writer; | 64 | 1 | bool res __attribute__((unused)) = writer.writeStartArray(); | 65 | 1 | assert(res); | 66 | 1 | uint32_t bytesWritten __attribute__((unused)) = f(writer); | 67 | 1 | assert(bytesWritten != 0); | 68 | 1 | res = writer.writeEndArray(); | 69 | 1 | assert(res); | 70 | 1 | char* buf = new char[writer.getOutput()->getSize()]; | 71 | 1 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); | 72 | | | 73 | 1 | *value = ((fbson::FbsonDocument *)buf)->getValue(); | 74 | 1 | assert((*value)->isArray()); | 75 | 1 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); | 76 | 1 | *value = ((fbson::ArrayVal*)*value)->get(0); | 77 | 1 | data->reset(buf); | 78 | 1 | } |
json_document.cc:_ZN12_GLOBAL__N_116InitJSONDocumentINSt3__16__bindIMN5fbson12FbsonWriterTINS3_14FbsonOutStreamEEEFjxEJRKNS1_12placeholders4__phILi1EEEiEEEEEvPNS1_10unique_ptrIA_cNS1_14default_deleteISG_EEEEPPNS3_10FbsonValueET_ Line | Count | Source | 61 | 1 | Func f) { | 62 | | // TODO(stash): maybe add function to FbsonDocument to avoid creating array? | 63 | 1 | fbson::FbsonWriter writer; | 64 | 1 | bool res __attribute__((unused)) = writer.writeStartArray(); | 65 | 1 | assert(res); | 66 | 1 | uint32_t bytesWritten __attribute__((unused)) = f(writer); | 67 | 1 | assert(bytesWritten != 0); | 68 | 1 | res = writer.writeEndArray(); | 69 | 1 | assert(res); | 70 | 1 | char* buf = new char[writer.getOutput()->getSize()]; | 71 | 1 | memcpy(buf, writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); | 72 | | | 73 | 1 | *value = ((fbson::FbsonDocument *)buf)->getValue(); | 74 | 1 | assert((*value)->isArray()); | 75 | 1 | assert(((fbson::ArrayVal*)*value)->numElem() == 1); | 76 | 1 | *value = ((fbson::ArrayVal*)*value)->get(0); | 77 | 1 | data->reset(buf); | 78 | 1 | } |
|
79 | | |
80 | | void InitString(std::unique_ptr<char[]>* data, |
81 | | fbson::FbsonValue** value, |
82 | 8 | const std::string& s) { |
83 | 8 | InitJSONDocument(data, value, std::bind( |
84 | 8 | [](fbson::FbsonWriter& writer, const std::string& str) -> uint32_t { |
85 | 8 | bool res __attribute__((unused)) = writer.writeStartString(); |
86 | 8 | assert(res); |
87 | 8 | auto bytesWritten = writer.writeString(str.c_str(), |
88 | 8 | static_cast<uint32_t>(str.length())); |
89 | 8 | res = writer.writeEndString(); |
90 | 8 | assert(res); |
91 | | // If the string is empty, then bytesWritten == 0, and assert in |
92 | | // InitJsonDocument will fail. |
93 | 8 | return bytesWritten + static_cast<uint32_t>(str.empty()); |
94 | 8 | }, |
95 | 8 | _1, s)); |
96 | 8 | } |
97 | | |
98 | 55 | bool IsNumeric(fbson::FbsonValue* value) { |
99 | 55 | return value->isInt8() || value->isInt16() || |
100 | 40 | value->isInt32() || value->isInt64(); |
101 | 55 | } |
102 | | |
103 | 364 | int64_t GetInt64ValFromFbsonNumericType(fbson::FbsonValue* value) { |
104 | 364 | switch (value->type()) { |
105 | 306 | case fbson::FbsonType::T_Int8: |
106 | 306 | return reinterpret_cast<fbson::Int8Val*>(value)->val(); |
107 | 1 | case fbson::FbsonType::T_Int16: |
108 | 1 | return reinterpret_cast<fbson::Int16Val*>(value)->val(); |
109 | 3 | case fbson::FbsonType::T_Int32: |
110 | 3 | return reinterpret_cast<fbson::Int32Val*>(value)->val(); |
111 | 54 | case fbson::FbsonType::T_Int64: |
112 | 54 | return reinterpret_cast<fbson::Int64Val*>(value)->val(); |
113 | 0 | default: |
114 | 0 | assert(false); |
115 | 364 | } |
116 | 0 | return 0; |
117 | 364 | } |
118 | | |
119 | 50 | bool IsComparable(fbson::FbsonValue* left, fbson::FbsonValue* right) { |
120 | 50 | if (left->type() == right->type()) { |
121 | 39 | return true; |
122 | 39 | } |
123 | 11 | if (IsNumeric(left) && IsNumeric(right)) { |
124 | 5 | return true; |
125 | 5 | } |
126 | 6 | return false; |
127 | 6 | } |
128 | | |
129 | 1 | void CreateArray(std::unique_ptr<char[]>* data, fbson::FbsonValue** value) { |
130 | 1 | fbson::FbsonWriter writer; |
131 | 1 | bool res __attribute__((unused)) = writer.writeStartArray(); |
132 | 1 | assert(res); |
133 | 1 | res = writer.writeEndArray(); |
134 | 1 | assert(res); |
135 | 1 | data->reset(new char[writer.getOutput()->getSize()]); |
136 | 1 | memcpy(data->get(), |
137 | 1 | writer.getOutput()->getBuffer(), |
138 | 1 | writer.getOutput()->getSize()); |
139 | 1 | *value = reinterpret_cast<fbson::FbsonDocument*>(data->get())->getValue(); |
140 | 1 | } |
141 | | |
142 | 1 | void CreateObject(std::unique_ptr<char[]>* data, fbson::FbsonValue** value) { |
143 | 1 | fbson::FbsonWriter writer; |
144 | 1 | bool res __attribute__((unused)) = writer.writeStartObject(); |
145 | 1 | assert(res); |
146 | 1 | res = writer.writeEndObject(); |
147 | 1 | assert(res); |
148 | 1 | data->reset(new char[writer.getOutput()->getSize()]); |
149 | 1 | memcpy(data->get(), |
150 | 1 | writer.getOutput()->getBuffer(), |
151 | 1 | writer.getOutput()->getSize()); |
152 | 1 | *value = reinterpret_cast<fbson::FbsonDocument*>(data->get())->getValue(); |
153 | 1 | } |
154 | | |
155 | | } // namespace |
156 | | |
157 | | namespace rocksdb { |
158 | | |
159 | | |
160 | | // TODO(stash): find smth easier |
161 | 41 | JSONDocument::JSONDocument() { |
162 | 41 | InitJSONDocument(&data_, |
163 | 41 | &value_, |
164 | 41 | std::bind(&fbson::FbsonWriter::writeNull, _1)); |
165 | 41 | } |
166 | | |
167 | 9 | JSONDocument::JSONDocument(bool b) { |
168 | 9 | InitJSONDocument(&data_, |
169 | 9 | &value_, |
170 | 9 | std::bind(&fbson::FbsonWriter::writeBool, _1, b)); |
171 | 9 | } |
172 | | |
173 | 6 | JSONDocument::JSONDocument(double d) { |
174 | 6 | InitJSONDocument(&data_, |
175 | 6 | &value_, |
176 | 6 | std::bind(&fbson::FbsonWriter::writeDouble, _1, d)); |
177 | 6 | } |
178 | | |
179 | 0 | JSONDocument::JSONDocument(int8_t i) { |
180 | 0 | InitJSONDocument(&data_, |
181 | 0 | &value_, |
182 | 0 | std::bind(&fbson::FbsonWriter::writeInt8, _1, i)); |
183 | 0 | } |
184 | | |
185 | 0 | JSONDocument::JSONDocument(int16_t i) { |
186 | 0 | InitJSONDocument(&data_, |
187 | 0 | &value_, |
188 | 0 | std::bind(&fbson::FbsonWriter::writeInt16, _1, i)); |
189 | 0 | } |
190 | | |
191 | 2 | JSONDocument::JSONDocument(int32_t i) { |
192 | 2 | InitJSONDocument(&data_, |
193 | 2 | &value_, |
194 | 2 | std::bind(&fbson::FbsonWriter::writeInt32, _1, i)); |
195 | 2 | } |
196 | | |
197 | 9 | JSONDocument::JSONDocument(int64_t i) { |
198 | 9 | InitJSONDocument(&data_, |
199 | 9 | &value_, |
200 | 9 | std::bind(&fbson::FbsonWriter::writeInt64, _1, i)); |
201 | 9 | } |
202 | | |
203 | 7 | JSONDocument::JSONDocument(const std::string& s) { |
204 | 7 | InitString(&data_, &value_, s); |
205 | 7 | } |
206 | | |
207 | 7 | JSONDocument::JSONDocument(const char* s) : JSONDocument(std::string(s)) { |
208 | 7 | } Unexecuted instantiation: _ZN7rocksdb12JSONDocumentC2EPKc _ZN7rocksdb12JSONDocumentC1EPKc Line | Count | Source | 207 | 7 | JSONDocument::JSONDocument(const char* s) : JSONDocument(std::string(s)) { | 208 | 7 | } |
|
209 | | |
210 | 206 | void JSONDocument::InitFromValue(const fbson::FbsonValue* val) { |
211 | 206 | data_.reset(new char[val->numPackedBytes()]); |
212 | 206 | memcpy(data_.get(), val, val->numPackedBytes()); |
213 | 206 | value_ = reinterpret_cast<fbson::FbsonValue*>(data_.get()); |
214 | 206 | } |
215 | | |
216 | | // Private constructor |
217 | 867 | JSONDocument::JSONDocument(fbson::FbsonValue* val, bool makeCopy) { |
218 | 867 | if (makeCopy) { |
219 | 189 | InitFromValue(val); |
220 | 678 | } else { |
221 | 678 | value_ = val; |
222 | 678 | } |
223 | 867 | } |
224 | | |
225 | 7 | JSONDocument::JSONDocument(Type _type) { |
226 | | // TODO(icanadi) make all of this better by using templates |
227 | 7 | switch (_type) { |
228 | 1 | case kNull: |
229 | 1 | InitJSONDocument(&data_, &value_, |
230 | 1 | std::bind(&fbson::FbsonWriter::writeNull, _1)); |
231 | 1 | break; |
232 | 1 | case kObject: |
233 | 1 | CreateObject(&data_, &value_); |
234 | 1 | break; |
235 | 1 | case kBool: |
236 | 1 | InitJSONDocument(&data_, &value_, |
237 | 1 | std::bind(&fbson::FbsonWriter::writeBool, _1, false)); |
238 | 1 | break; |
239 | 1 | case kDouble: |
240 | 1 | InitJSONDocument(&data_, &value_, |
241 | 1 | std::bind(&fbson::FbsonWriter::writeDouble, _1, 0.)); |
242 | 1 | break; |
243 | 1 | case kArray: |
244 | 1 | CreateArray(&data_, &value_); |
245 | 1 | break; |
246 | 1 | case kInt64: |
247 | 1 | InitJSONDocument(&data_, &value_, |
248 | 1 | std::bind(&fbson::FbsonWriter::writeInt64, _1, 0)); |
249 | 1 | break; |
250 | 1 | case kString: |
251 | 1 | InitString(&data_, &value_, ""); |
252 | 1 | break; |
253 | 0 | default: |
254 | 0 | assert(false); |
255 | 7 | } |
256 | 7 | } |
257 | | |
258 | 79 | JSONDocument::JSONDocument(const JSONDocument& jsonDocument) { |
259 | 79 | if (jsonDocument.IsOwner()) { |
260 | 17 | InitFromValue(jsonDocument.value_); |
261 | 62 | } else { |
262 | 62 | value_ = jsonDocument.value_; |
263 | 62 | } |
264 | 79 | } |
265 | | |
266 | 212 | JSONDocument::JSONDocument(JSONDocument&& jsonDocument) { |
267 | 212 | value_ = jsonDocument.value_; |
268 | 212 | data_.swap(jsonDocument.data_); |
269 | 212 | } |
270 | | |
271 | 37 | JSONDocument& JSONDocument::operator=(JSONDocument jsonDocument) { |
272 | 37 | value_ = jsonDocument.value_; |
273 | 37 | data_.swap(jsonDocument.data_); |
274 | 37 | return *this; |
275 | 37 | } |
276 | | |
277 | 1.09k | JSONDocument::Type JSONDocument::type() const { |
278 | 1.09k | switch (value_->type()) { |
279 | 0 | case fbson::FbsonType::T_Null: |
280 | 0 | return JSONDocument::kNull; |
281 | | |
282 | 0 | case fbson::FbsonType::T_True: |
283 | 0 | case fbson::FbsonType::T_False: |
284 | 0 | return JSONDocument::kBool; |
285 | |
|
286 | 477 | case fbson::FbsonType::T_Int8: |
287 | 477 | case fbson::FbsonType::T_Int16: |
288 | 479 | case fbson::FbsonType::T_Int32: |
289 | 523 | case fbson::FbsonType::T_Int64: |
290 | 523 | return JSONDocument::kInt64; |
291 | | |
292 | 211 | case fbson::FbsonType::T_Double: |
293 | 211 | return JSONDocument::kDouble; |
294 | | |
295 | 363 | case fbson::FbsonType::T_String: |
296 | 363 | return JSONDocument::kString; |
297 | | |
298 | 0 | case fbson::FbsonType::T_Object: |
299 | 0 | return JSONDocument::kObject; |
300 | | |
301 | 0 | case fbson::FbsonType::T_Array: |
302 | 0 | return JSONDocument::kArray; |
303 | | |
304 | 0 | case fbson::FbsonType::T_Binary: |
305 | 0 | assert(false); |
306 | | // Added to avoid a compile error of the YugaByte codebase (we treat unannotated fall-through |
307 | | // as an error). |
308 | 0 | break; |
309 | | |
310 | 0 | default: |
311 | 0 | assert(false); |
312 | 1.09k | } |
313 | 0 | return JSONDocument::kNull; |
314 | 1.09k | } |
315 | | |
316 | 364 | bool JSONDocument::Contains(const std::string& key) const { |
317 | 364 | assert(IsObject()); |
318 | 364 | auto objectVal = reinterpret_cast<fbson::ObjectVal*>(value_); |
319 | 364 | return objectVal->find(key.c_str()) != nullptr; |
320 | 364 | } |
321 | | |
322 | 469 | JSONDocument JSONDocument::operator[](const std::string& key) const { |
323 | 469 | assert(IsObject()); |
324 | 469 | auto objectVal = reinterpret_cast<fbson::ObjectVal*>(value_); |
325 | 469 | auto foundValue = objectVal->find(key.c_str()); |
326 | 469 | assert(foundValue != nullptr); |
327 | | // No need to save paths in const objects |
328 | 469 | JSONDocument ans(foundValue, false); |
329 | 469 | return ans; |
330 | 469 | } |
331 | | |
332 | 71 | size_t JSONDocument::Count() const { |
333 | 71 | assert(IsObject() || IsArray()); |
334 | 71 | if (IsObject()) { |
335 | | // TODO(stash): add to fbson? |
336 | 36 | const fbson::ObjectVal& objectVal = |
337 | 36 | *reinterpret_cast<fbson::ObjectVal*>(value_); |
338 | 36 | return ObjectNumElem(objectVal); |
339 | 35 | } else if (IsArray()) { |
340 | 35 | auto arrayVal = reinterpret_cast<fbson::ArrayVal*>(value_); |
341 | 35 | return arrayVal->numElem(); |
342 | 35 | } |
343 | 0 | assert(false); |
344 | 0 | return 0; |
345 | 0 | } |
346 | | |
347 | 53 | JSONDocument JSONDocument::operator[](size_t i) const { |
348 | 53 | assert(IsArray()); |
349 | 53 | auto arrayVal = reinterpret_cast<fbson::ArrayVal*>(value_); |
350 | 53 | auto foundValue = arrayVal->get(static_cast<int>(i)); |
351 | 53 | JSONDocument ans(foundValue, false); |
352 | 53 | return ans; |
353 | 53 | } |
354 | | |
355 | 356 | bool JSONDocument::IsNull() const { |
356 | 356 | return value_->isNull(); |
357 | 356 | } |
358 | | |
359 | 175 | bool JSONDocument::IsArray() const { |
360 | 175 | return value_->isArray(); |
361 | 175 | } |
362 | | |
363 | 15 | bool JSONDocument::IsBool() const { |
364 | 15 | return value_->isTrue() || value_->isFalse(); |
365 | 15 | } |
366 | | |
367 | 132 | bool JSONDocument::IsDouble() const { |
368 | 132 | return value_->isDouble(); |
369 | 132 | } |
370 | | |
371 | 394 | bool JSONDocument::IsInt64() const { |
372 | 394 | return value_->isInt8() || value_->isInt16() || |
373 | 59 | value_->isInt32() || value_->isInt64(); |
374 | 394 | } |
375 | | |
376 | 1.51k | bool JSONDocument::IsObject() const { |
377 | 1.51k | return value_->isObject(); |
378 | 1.51k | } |
379 | | |
380 | 268 | bool JSONDocument::IsString() const { |
381 | 268 | return value_->isString(); |
382 | 268 | } |
383 | | |
384 | 5 | bool JSONDocument::GetBool() const { |
385 | 5 | assert(IsBool()); |
386 | 5 | return value_->isTrue(); |
387 | 5 | } |
388 | | |
389 | 121 | double JSONDocument::GetDouble() const { |
390 | 121 | assert(IsDouble()); |
391 | 121 | return ((fbson::DoubleVal*)value_)->val(); |
392 | 121 | } |
393 | | |
394 | 344 | int64_t JSONDocument::GetInt64() const { |
395 | 344 | assert(IsInt64()); |
396 | 344 | return GetInt64ValFromFbsonNumericType(value_); |
397 | 344 | } |
398 | | |
399 | 208 | std::string JSONDocument::GetString() const { |
400 | 208 | assert(IsString()); |
401 | 208 | fbson::StringVal* stringVal = (fbson::StringVal*)value_; |
402 | 208 | return std::string(stringVal->getBlob(), stringVal->getBlobLen()); |
403 | 208 | } |
404 | | |
405 | | namespace { |
406 | | |
407 | | // FbsonValue can be int8, int16, int32, int64 |
408 | 10 | bool CompareNumeric(fbson::FbsonValue* left, fbson::FbsonValue* right) { |
409 | 10 | assert(IsNumeric(left) && IsNumeric(right)); |
410 | 10 | return GetInt64ValFromFbsonNumericType(left) == |
411 | 10 | GetInt64ValFromFbsonNumericType(right); |
412 | 10 | } |
413 | | |
414 | 17 | bool CompareSimpleTypes(fbson::FbsonValue* left, fbson::FbsonValue* right) { |
415 | 17 | if (IsNumeric(left)) { |
416 | 0 | return CompareNumeric(left, right); |
417 | 0 | } |
418 | 17 | if (left->numPackedBytes() != right->numPackedBytes()) { |
419 | 0 | return false; |
420 | 0 | } |
421 | 17 | return memcmp(left, right, left->numPackedBytes()) == 0; |
422 | 17 | } |
423 | | |
424 | 50 | bool CompareFbsonValue(fbson::FbsonValue* left, fbson::FbsonValue* right) { |
425 | 50 | if (!IsComparable(left, right)) { |
426 | 6 | return false; |
427 | 6 | } |
428 | | |
429 | 44 | switch (left->type()) { |
430 | 2 | case fbson::FbsonType::T_True: |
431 | 3 | case fbson::FbsonType::T_False: |
432 | 5 | case fbson::FbsonType::T_Null: |
433 | 5 | return true; |
434 | 6 | case fbson::FbsonType::T_Int8: |
435 | 7 | case fbson::FbsonType::T_Int16: |
436 | 8 | case fbson::FbsonType::T_Int32: |
437 | 10 | case fbson::FbsonType::T_Int64: |
438 | 10 | return CompareNumeric(left, right); |
439 | 12 | case fbson::FbsonType::T_String: |
440 | 17 | case fbson::FbsonType::T_Double: |
441 | 17 | return CompareSimpleTypes(left, right); |
442 | 7 | case fbson::FbsonType::T_Object: |
443 | 7 | { |
444 | 7 | auto leftObject = reinterpret_cast<fbson::ObjectVal*>(left); |
445 | 7 | auto rightObject = reinterpret_cast<fbson::ObjectVal*>(right); |
446 | 7 | if (ObjectNumElem(*leftObject) != ObjectNumElem(*rightObject)) { |
447 | 0 | return false; |
448 | 0 | } |
449 | 17 | for (auto && keyValue : *leftObject) { |
450 | 17 | std::string str(keyValue.getKeyStr(), keyValue.klen()); |
451 | 17 | if (rightObject->find(str.c_str()) == nullptr) { |
452 | 0 | return false; |
453 | 0 | } |
454 | 17 | if (!CompareFbsonValue(keyValue.value(), |
455 | 3 | rightObject->find(str.c_str()))) { |
456 | 3 | return false; |
457 | 3 | } |
458 | 17 | } |
459 | 4 | return true; |
460 | 7 | } |
461 | 5 | case fbson::FbsonType::T_Array: |
462 | 5 | { |
463 | 5 | auto leftArr = reinterpret_cast<fbson::ArrayVal*>(left); |
464 | 5 | auto rightArr = reinterpret_cast<fbson::ArrayVal*>(right); |
465 | 5 | if (leftArr->numElem() != rightArr->numElem()) { |
466 | 0 | return false; |
467 | 0 | } |
468 | 18 | for (int i = 0; i < static_cast<int>(leftArr->numElem()); ++i) { |
469 | 14 | if (!CompareFbsonValue(leftArr->get(i), rightArr->get(i))) { |
470 | 1 | return false; |
471 | 1 | } |
472 | 14 | } |
473 | 4 | return true; |
474 | 5 | } |
475 | 0 | default: |
476 | 0 | assert(false); |
477 | 44 | } |
478 | 0 | return false; |
479 | 44 | } |
480 | | |
481 | | } // namespace |
482 | | |
483 | 19 | bool JSONDocument::operator==(const JSONDocument& rhs) const { |
484 | 19 | return CompareFbsonValue(value_, rhs.value_); |
485 | 19 | } |
486 | | |
487 | 7 | bool JSONDocument::operator!=(const JSONDocument& rhs) const { |
488 | 7 | return !(*this == rhs); |
489 | 7 | } |
490 | | |
491 | 19 | JSONDocument JSONDocument::Copy() const { |
492 | 19 | return JSONDocument(value_, true); |
493 | 19 | } |
494 | | |
495 | 184 | bool JSONDocument::IsOwner() const { |
496 | 184 | return data_.get() != nullptr; |
497 | 184 | } |
498 | | |
499 | 0 | std::string JSONDocument::DebugString() const { |
500 | 0 | fbson::FbsonToJson fbsonToJson; |
501 | 0 | return fbsonToJson.json(value_); |
502 | 0 | } |
503 | | |
504 | 84 | JSONDocument::ItemsIteratorGenerator JSONDocument::Items() const { |
505 | 84 | assert(IsObject()); |
506 | 84 | return ItemsIteratorGenerator(*(reinterpret_cast<fbson::ObjectVal*>(value_))); |
507 | 84 | } |
508 | | |
509 | | // TODO(icanadi) (perf) allocate objects with arena |
510 | 54 | JSONDocument* JSONDocument::ParseJSON(const char* json) { |
511 | 54 | fbson::FbsonJsonParser parser; |
512 | 54 | if (!parser.parse(json)) { |
513 | 1 | return nullptr; |
514 | 1 | } |
515 | | |
516 | 53 | auto fbsonVal = fbson::FbsonDocument::createValue( |
517 | 53 | parser.getWriter().getOutput()->getBuffer(), |
518 | 53 | static_cast<uint32_t>(parser.getWriter().getOutput()->getSize())); |
519 | | |
520 | 53 | if (fbsonVal == nullptr) { |
521 | 0 | return nullptr; |
522 | 0 | } |
523 | | |
524 | 53 | return new JSONDocument(fbsonVal, true); |
525 | 53 | } |
526 | | |
527 | 25 | void JSONDocument::Serialize(std::string* dst) const { |
528 | | // first byte is reserved for header |
529 | | // currently, header is only version number. that will help us provide |
530 | | // backwards compatility. we might also store more information here if |
531 | | // necessary |
532 | 25 | dst->push_back(kSerializationFormatVersion); |
533 | 25 | dst->push_back(FBSON_VER); |
534 | 25 | dst->append(reinterpret_cast<char*>(value_), value_->numPackedBytes()); |
535 | 25 | } |
536 | | |
537 | | const char JSONDocument::kSerializationFormatVersion = 2; |
538 | | |
539 | 97 | JSONDocument* JSONDocument::Deserialize(const Slice& src) { |
540 | 97 | Slice input(src); |
541 | 97 | if (src.size() == 0) { |
542 | 0 | return nullptr; |
543 | 0 | } |
544 | 97 | char header = input[0]; |
545 | 97 | if (header == 1) { |
546 | 0 | assert(false); |
547 | 0 | } |
548 | 97 | input.remove_prefix(1); |
549 | 97 | auto value = fbson::FbsonDocument::createValue(input.cdata(), |
550 | 97 | static_cast<uint32_t>(input.size())); |
551 | 97 | if (value == nullptr) { |
552 | 1 | return nullptr; |
553 | 1 | } |
554 | | |
555 | 96 | return new JSONDocument(value, true); |
556 | 96 | } |
557 | | |
558 | | class JSONDocument::const_item_iterator::Impl { |
559 | | public: |
560 | | typedef fbson::ObjectVal::const_iterator It; |
561 | | |
562 | 149 | explicit Impl(It it) : it_(it) {} |
563 | | |
564 | 156 | const char* getKeyStr() const { |
565 | 156 | return it_->getKeyStr(); |
566 | 156 | } |
567 | | |
568 | 156 | uint8_t klen() const { |
569 | 156 | return it_->klen(); |
570 | 156 | } |
571 | | |
572 | 137 | It& operator++() { |
573 | 137 | return ++it_; |
574 | 137 | } |
575 | | |
576 | 202 | bool operator!=(const Impl& other) { |
577 | 202 | return it_ != other.it_; |
578 | 202 | } |
579 | | |
580 | 156 | fbson::FbsonValue* value() const { |
581 | 156 | return it_->value(); |
582 | 156 | } |
583 | | |
584 | | private: |
585 | | It it_; |
586 | | }; |
587 | | |
588 | | JSONDocument::const_item_iterator::const_item_iterator(Impl* impl) |
589 | 149 | : it_(impl) {} |
590 | | |
591 | | JSONDocument::const_item_iterator::const_item_iterator(const_item_iterator&& a) |
592 | 0 | : it_(std::move(a.it_)) {} |
593 | | |
594 | | JSONDocument::const_item_iterator& |
595 | 137 | JSONDocument::const_item_iterator::operator++() { |
596 | 137 | ++(*it_); |
597 | 137 | return *this; |
598 | 137 | } |
599 | | |
600 | | bool JSONDocument::const_item_iterator::operator!=( |
601 | 202 | const const_item_iterator& other) { |
602 | 202 | return *it_ != *(other.it_); |
603 | 202 | } |
604 | | |
605 | 149 | JSONDocument::const_item_iterator::~const_item_iterator() { |
606 | 149 | } |
607 | | |
608 | | JSONDocument::const_item_iterator::value_type |
609 | 156 | JSONDocument::const_item_iterator::operator*() { |
610 | 156 | return JSONDocument::const_item_iterator::value_type(std::string(it_->getKeyStr(), it_->klen()), |
611 | 156 | JSONDocument(it_->value(), false)); |
612 | 156 | } |
613 | | |
614 | | JSONDocument::ItemsIteratorGenerator::ItemsIteratorGenerator( |
615 | | const fbson::ObjectVal& object) |
616 | 84 | : object_(object) {} |
617 | | |
618 | | JSONDocument::const_item_iterator |
619 | 84 | JSONDocument::ItemsIteratorGenerator::begin() const { |
620 | 84 | return const_item_iterator(new const_item_iterator::Impl(object_.begin())); |
621 | 84 | } |
622 | | |
623 | | JSONDocument::const_item_iterator |
624 | 65 | JSONDocument::ItemsIteratorGenerator::end() const { |
625 | 65 | return const_item_iterator(new const_item_iterator::Impl(object_.end())); |
626 | 65 | } |
627 | | |
628 | | } // namespace rocksdb |
629 | | #endif // ROCKSDB_LITE |