1#pragma once
2
3#include "config_functions.h"
4#if USE_SIMDJSON
5
6#include <common/StringRef.h>
7#include <Common/Exception.h>
8#include <Core/Types.h>
9
10#include <simdjson/jsonparser.h>
11
12
13namespace DB
14{
15namespace ErrorCodes
16{
17 extern const int CANNOT_ALLOCATE_MEMORY;
18}
19
20/// This class can be used as an argument for the template class FunctionJSON.
21/// It provides ability to parse JSONs using simdjson library.
22struct SimdJSONParser
23{
24 static constexpr bool need_preallocate = true;
25
26 void preallocate(size_t max_size)
27 {
28 if (!pj.allocate_capacity(max_size))
29 throw Exception{"Can not allocate memory for " + std::to_string(max_size) + " units when parsing JSON",
30 ErrorCodes::CANNOT_ALLOCATE_MEMORY};
31 }
32
33 bool parse(const StringRef & json) { return !json_parse(json.data, json.size, pj); }
34
35 using Iterator = simdjson::ParsedJson::Iterator;
36 Iterator getRoot() { return Iterator{pj}; }
37
38 static bool isInt64(const Iterator & it) { return it.is_integer(); }
39 static bool isUInt64(const Iterator &) { return false; /* See https://github.com/lemire/simdjson/issues/68 */ }
40 static bool isDouble(const Iterator & it) { return it.is_double(); }
41 static bool isString(const Iterator & it) { return it.is_string(); }
42 static bool isArray(const Iterator & it) { return it.is_array(); }
43 static bool isObject(const Iterator & it) { return it.is_object(); }
44 static bool isBool(const Iterator & it) { return it.get_type() == 't' || it.get_type() == 'f'; }
45 static bool isNull(const Iterator & it) { return it.is_null(); }
46
47 static Int64 getInt64(const Iterator & it) { return it.get_integer(); }
48 static UInt64 getUInt64(const Iterator &) { return 0; /* isUInt64() never returns true */ }
49 static double getDouble(const Iterator & it) { return it.get_double(); }
50 static bool getBool(const Iterator & it) { return it.get_type() == 't'; }
51 static StringRef getString(const Iterator & it) { return StringRef{it.get_string(), it.get_string_length()}; }
52
53 static size_t sizeOfArray(const Iterator & it)
54 {
55 size_t size = 0;
56 Iterator it2 = it;
57 if (it2.down())
58 {
59 do
60 ++size;
61 while (it2.next());
62 }
63 return size;
64 }
65
66 static bool firstArrayElement(Iterator & it) { return it.down(); }
67
68 static bool arrayElementByIndex(Iterator & it, size_t index)
69 {
70 if (!it.down())
71 return false;
72 while (index--)
73 if (!it.next())
74 return false;
75 return true;
76 }
77
78 static bool nextArrayElement(Iterator & it) { return it.next(); }
79
80 static size_t sizeOfObject(const Iterator & it)
81 {
82 size_t size = 0;
83 Iterator it2 = it;
84 if (it2.down())
85 {
86 do
87 ++size;
88 while (it2.next() && it2.next()); //-V501
89 }
90 return size;
91 }
92
93 static bool firstObjectMember(Iterator & it) { return it.down() && it.next(); }
94
95 static bool firstObjectMember(Iterator & it, StringRef & first_key)
96 {
97 if (!it.down())
98 return false;
99 first_key.data = it.get_string();
100 first_key.size = it.get_string_length();
101 return it.next();
102 }
103
104 static bool objectMemberByIndex(Iterator & it, size_t index)
105 {
106 if (!it.down())
107 return false;
108 while (index--)
109 if (!it.next() || !it.next()) //-V501
110 return false;
111 return it.next();
112 }
113
114 static bool objectMemberByName(Iterator & it, const StringRef & name) { return it.move_to_key(name.data); }
115 static bool nextObjectMember(Iterator & it) { return it.next() && it.next(); } //-V501
116
117 static bool nextObjectMember(Iterator & it, StringRef & next_key)
118 {
119 if (!it.next())
120 return false;
121 next_key.data = it.get_string();
122 next_key.size = it.get_string_length();
123 return it.next();
124 }
125
126 static bool isObjectMember(const Iterator & it) { return it.get_scope_type() == '{'; }
127
128 static StringRef getKey(const Iterator & it)
129 {
130 Iterator it2 = it;
131 it2.prev();
132 return StringRef{it2.get_string(), it2.get_string_length()};
133 }
134
135private:
136 simdjson::ParsedJson pj;
137};
138
139}
140#endif
141