Zserio C++ runtime library  1.1.0
Built for Zserio 2.15.0
JsonTokenizer.h
Go to the documentation of this file.
1 #ifndef ZSERIO_JSON_TOKENIZER_H_INC
2 #define ZSERIO_JSON_TOKENIZER_H_INC
3 
4 #include <array>
5 #include <istream>
6 #include <memory>
7 
8 #include "zserio/AnyHolder.h"
10 #include "zserio/JsonDecoder.h"
11 #include "zserio/Types.h"
12 
13 namespace zserio
14 {
15 
19 enum class JsonToken : int8_t
20 {
21  UNKNOWN = -1,
25  END_OBJECT,
27  END_ARRAY,
30  VALUE
31 };
32 
37 {
38 public:
40 };
41 
51 
55 template <typename ALLOC = std::allocator<uint8_t>>
57 {
58 public:
65  BasicJsonTokenizer(std::istream& in, const ALLOC& allocator) :
66  m_buffer(),
67  m_in(in),
68  m_decoder(allocator),
69  m_decoderResult(0, allocator),
70  m_content(readContent(allocator)),
71  m_value(allocator)
72  {
73  m_token = m_content.empty() ? JsonToken::END_OF_FILE : JsonToken::BEGIN_OF_FILE;
74  }
75 
83 
90  {
91  return m_token;
92  }
93 
102  const AnyHolder<ALLOC>& getValue() const
103  {
104  return m_value;
105  }
106 
112  size_t getLine() const
113  {
114  return m_lineNumber;
115  }
116 
122  size_t getColumn() const
123  {
124  return m_tokenColumnNumber;
125  }
126 
127 private:
128  string<ALLOC> readContent(const ALLOC& allocator);
129 
130  bool decodeNext();
131  bool skipWhitespaces();
132 
133  template <typename T>
134  void setToken(JsonToken token, T&& value);
135  void setToken(JsonToken token, AnyHolder<ALLOC>&& value);
136  void setToken(JsonToken token);
137  void setPosition(size_t newPos, size_t newColumnNumber);
138  void setTokenValue();
139 
140  static constexpr size_t BUFFER_SIZE = 64 * 1024;
141  std::array<char, BUFFER_SIZE> m_buffer;
142 
143  std::istream& m_in;
144  BasicJsonDecoder<ALLOC> m_decoder;
145  typename BasicJsonDecoder<ALLOC>::DecoderResult m_decoderResult;
146  string<ALLOC> m_content;
147  size_t m_lineNumber = 1;
148  size_t m_columnNumber = 1;
149  size_t m_tokenColumnNumber = 1;
150  size_t m_pos = 0;
151  JsonToken m_token;
152  AnyHolder<ALLOC> m_value;
153 };
154 
155 template <typename ALLOC>
157 {
158  while (!decodeNext())
159  {
160  string<ALLOC> newContent = readContent(m_content.get_allocator());
161  if (newContent.empty())
162  {
163  if (m_token == JsonToken::END_OF_FILE)
164  {
165  m_tokenColumnNumber = m_columnNumber;
166  }
167  else
168  {
169  // stream is finished but last token is not EOF => value must be at the end
170  setTokenValue();
171  }
172 
173  return m_token;
174  }
175 
176  m_content = m_content.substr(m_pos) + newContent;
177  m_pos = 0;
178  }
179 
180  return m_token;
181 }
182 
183 template <typename ALLOC>
185 {
186  const size_t count = static_cast<size_t>(m_in.rdbuf()->sgetn(m_buffer.data(), BUFFER_SIZE));
187  return string<ALLOC>(m_buffer.data(), count, allocator);
188 }
189 
190 template <typename ALLOC>
191 bool BasicJsonTokenizer<ALLOC>::decodeNext()
192 {
193  if (!skipWhitespaces())
194  {
195  return false;
196  }
197 
198  m_tokenColumnNumber = m_columnNumber;
199 
200  const char nextChar = m_content[m_pos];
201  switch (nextChar)
202  {
203  case '{':
204  setToken(JsonToken::BEGIN_OBJECT, nextChar);
205  setPosition(m_pos + 1, m_columnNumber + 1);
206  break;
207  case '}':
208  setToken(JsonToken::END_OBJECT, nextChar);
209  setPosition(m_pos + 1, m_columnNumber + 1);
210  break;
211  case '[':
212  setToken(JsonToken::BEGIN_ARRAY, nextChar);
213  setPosition(m_pos + 1, m_columnNumber + 1);
214  break;
215  case ']':
216  setToken(JsonToken::END_ARRAY, nextChar);
217  setPosition(m_pos + 1, m_columnNumber + 1);
218  break;
219  case ':':
220  setToken(JsonToken::KEY_SEPARATOR, nextChar);
221  setPosition(m_pos + 1, m_columnNumber + 1);
222  break;
223  case ',':
224  setToken(JsonToken::ITEM_SEPARATOR, nextChar);
225  setPosition(m_pos + 1, m_columnNumber + 1);
226  break;
227  default:
228  m_decoderResult = m_decoder.decodeValue(StringView(m_content.data()).substr(m_pos));
229  if (m_pos + m_decoderResult.numReadChars >= m_content.size())
230  {
231  return false; // we are at the end of chunk => read more
232  }
233 
234  setTokenValue();
235  break;
236  }
237 
238  return true;
239 }
240 
241 template <typename ALLOC>
242 bool BasicJsonTokenizer<ALLOC>::skipWhitespaces()
243 {
244  while (true)
245  {
246  if (m_pos >= m_content.size())
247  {
248  setToken(JsonToken::END_OF_FILE);
249  return false;
250  }
251 
252  const char nextChar = m_content[m_pos];
253  switch (nextChar)
254  {
255  case ' ':
256  case '\t':
257  setPosition(m_pos + 1, m_columnNumber + 1);
258  break;
259  case '\n':
260  m_lineNumber++;
261  setPosition(m_pos + 1, 1);
262  break;
263  case '\r':
264  if (m_pos + 1 >= m_content.size())
265  {
266  setToken(JsonToken::END_OF_FILE);
267  return false;
268  }
269  m_lineNumber++;
270  setPosition(m_pos + (m_content[m_pos + 1] == '\n' ? 2 : 1), 1);
271  break;
272  default:
273  return true;
274  }
275  }
276 }
277 
278 template <typename ALLOC>
279 template <typename T>
280 void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token, T&& value)
281 {
282  m_token = token;
283  m_value.set(std::forward<T>(value));
284 }
285 
286 template <typename ALLOC>
287 void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token, AnyHolder<ALLOC>&& value)
288 {
289  m_token = token;
290  m_value = std::move(value);
291 }
292 
293 template <typename ALLOC>
294 void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token)
295 {
296  m_token = token;
297  m_value.reset();
298 }
299 
300 template <typename ALLOC>
301 void BasicJsonTokenizer<ALLOC>::setPosition(size_t newPos, size_t newColumnNumber)
302 {
303  m_pos = newPos;
304  m_columnNumber = newColumnNumber;
305 }
306 
307 template <typename ALLOC>
308 void BasicJsonTokenizer<ALLOC>::setTokenValue()
309 {
310  if (!m_decoderResult.value.hasValue())
311  {
312  throw JsonParserException("JsonTokenizer:")
313  << m_lineNumber << ":" << m_tokenColumnNumber << ": "
314  << (m_decoderResult.integerOverflow ? "Value is outside of the 64-bit integer range!"
315  : "Unknown token!");
316  }
317 
318  setToken(JsonToken::VALUE, std::move(m_decoderResult.value));
319  setPosition(m_pos + m_decoderResult.numReadChars, m_columnNumber + m_decoderResult.numReadChars);
320 }
321 
322 } // namespace zserio
323 
324 #endif // ZSERIO_JSON_TOKENIZER_H_INC
JsonToken getToken() const
Definition: JsonTokenizer.h:89
const AnyHolder< ALLOC > & getValue() const
BasicJsonTokenizer(std::istream &in, const ALLOC &allocator)
Definition: JsonTokenizer.h:65
BasicStringView substr(size_type pos=0, size_type count=npos) const
Definition: StringView.h:338
CppRuntimeException(const char *message="")
BasicStringView< char, std::char_traits< char > > StringView
Definition: StringView.h:968
std::basic_string< char, std::char_traits< char >, RebindAlloc< ALLOC, char > > string
Definition: String.h:17
CppRuntimeException & operator<<(CppRuntimeException &exception, const BasicBitBuffer< ALLOC > &bitBuffer)
Definition: BitBuffer.h:455