Zserio C++ runtime library  1.0.0
Built for Zserio 2.13.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 <memory>
5 #include <istream>
6 #include <array>
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 
33 
38 {
39 public:
41 };
42 
52 
56 template <typename ALLOC = std::allocator<uint8_t>>
58 {
59 public:
66  BasicJsonTokenizer(std::istream& in, const ALLOC& allocator) :
67  m_buffer(), m_in(in), m_decoder(allocator), m_decoderResult(0, allocator),
68  m_content(readContent(allocator)), m_value(allocator)
69  {
70  m_token = m_content.empty() ? JsonToken::END_OF_FILE : JsonToken::BEGIN_OF_FILE;
71  }
72 
79  JsonToken next();
80 
86  JsonToken getToken() const { return m_token; }
87 
96  const AnyHolder<ALLOC>& getValue() const { return m_value; }
97 
103  size_t getLine() const { return m_lineNumber; }
104 
110  size_t getColumn() const { return m_tokenColumnNumber; }
111 
112 private:
113  string<ALLOC> readContent(const ALLOC& allocator);
114 
115  bool decodeNext();
116  bool skipWhitespaces();
117 
118  template <typename T>
119  void setToken(JsonToken token, T&& value);
120  void setToken(JsonToken token, AnyHolder<ALLOC>&& value);
121  void setToken(JsonToken token);
122  void setPosition(size_t newPos, size_t newColumnNumber);
123  void setTokenValue();
124 
125  static constexpr size_t BUFFER_SIZE = 64 * 1024;
126  std::array<char, BUFFER_SIZE> m_buffer;
127 
128  std::istream& m_in;
129  BasicJsonDecoder<ALLOC> m_decoder;
130  typename BasicJsonDecoder<ALLOC>::DecoderResult m_decoderResult;
131  string<ALLOC> m_content;
132  size_t m_lineNumber = 1;
133  size_t m_columnNumber = 1;
134  size_t m_tokenColumnNumber = 1;
135  size_t m_pos = 0;
136  JsonToken m_token;
137  AnyHolder<ALLOC> m_value;
138 };
139 
140 template <typename ALLOC>
142 {
143  while (!decodeNext())
144  {
145  string<ALLOC> newContent = readContent(m_content.get_allocator());
146  if (newContent.empty())
147  {
148  if (m_token == JsonToken::END_OF_FILE)
149  {
150  m_tokenColumnNumber = m_columnNumber;
151  }
152  else
153  {
154  // stream is finished but last token is not EOF => value must be at the end
155  setTokenValue();
156  }
157 
158  return m_token;
159  }
160 
161  m_content = m_content.substr(m_pos) + newContent;
162  m_pos = 0;
163  }
164 
165  return m_token;
166 }
167 
168 template <typename ALLOC>
170 {
171  const size_t count = static_cast<size_t>(m_in.rdbuf()->sgetn(m_buffer.data(), BUFFER_SIZE));
172  return string<ALLOC>(m_buffer.data(), count, allocator);
173 }
174 
175 template <typename ALLOC>
177 {
178  if (!skipWhitespaces())
179  return false;
180 
181  m_tokenColumnNumber = m_columnNumber;
182 
183  const char nextChar = m_content[m_pos];
184  switch (nextChar)
185  {
186  case '{':
187  setToken(JsonToken::BEGIN_OBJECT, nextChar);
188  setPosition(m_pos + 1, m_columnNumber + 1);
189  break;
190  case '}':
191  setToken(JsonToken::END_OBJECT, nextChar);
192  setPosition(m_pos + 1, m_columnNumber + 1);
193  break;
194  case '[':
195  setToken(JsonToken::BEGIN_ARRAY, nextChar);
196  setPosition(m_pos + 1, m_columnNumber + 1);
197  break;
198  case ']':
199  setToken(JsonToken::END_ARRAY, nextChar);
200  setPosition(m_pos + 1, m_columnNumber + 1);
201  break;
202  case ':':
203  setToken(JsonToken::KEY_SEPARATOR, nextChar);
204  setPosition(m_pos + 1, m_columnNumber + 1);
205  break;
206  case ',':
207  setToken(JsonToken::ITEM_SEPARATOR, nextChar);
208  setPosition(m_pos + 1, m_columnNumber + 1);
209  break;
210  default:
211  m_decoderResult = m_decoder.decodeValue(StringView(m_content.data()).substr(m_pos));
212  if (m_pos + m_decoderResult.numReadChars >= m_content.size())
213  return false; // we are at the end of chunk => read more
214 
215  setTokenValue();
216  break;
217  }
218 
219  return true;
220 }
221 
222 template <typename ALLOC>
224 {
225  while (true)
226  {
227  if (m_pos >= m_content.size())
228  {
229  setToken(JsonToken::END_OF_FILE);
230  return false;
231  }
232 
233  const char nextChar = m_content[m_pos];
234  switch (nextChar)
235  {
236  case ' ':
237  case '\t':
238  setPosition(m_pos + 1, m_columnNumber + 1);
239  break;
240  case '\n':
241  m_lineNumber++;
242  setPosition(m_pos + 1, 1);
243  break;
244  case '\r':
245  if (m_pos + 1 >= m_content.size())
246  {
247  setToken(JsonToken::END_OF_FILE);
248  return false;
249  }
250  m_lineNumber++;
251  setPosition(m_pos + (m_content[m_pos + 1] == '\n' ? 2 : 1), 1);
252  break;
253  default:
254  return true;
255  }
256  }
257 }
258 
259 template <typename ALLOC>
260 template <typename T>
261 void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token, T&& value)
262 {
263  m_token = token;
264  m_value.set(std::forward<T>(value));
265 }
266 
267 template <typename ALLOC>
269 {
270  m_token = token;
271  m_value = std::move(value);
272 }
273 
274 template <typename ALLOC>
276 {
277  m_token = token;
278  m_value.reset();
279 }
280 
281 template <typename ALLOC>
282 void BasicJsonTokenizer<ALLOC>::setPosition(size_t newPos, size_t newColumnNumber)
283 {
284  m_pos = newPos;
285  m_columnNumber = newColumnNumber;
286 }
287 
288 template <typename ALLOC>
290 {
291  if (!m_decoderResult.value.hasValue())
292  {
293  throw JsonParserException("JsonTokenizer:") << m_lineNumber << ":" << m_tokenColumnNumber << ": " <<
294  (m_decoderResult.integerOverflow
295  ? "Value is outside of the 64-bit integer range!"
296  : "Unknown token!");
297  }
298 
299  setToken(JsonToken::VALUE, std::move(m_decoderResult.value));
300  setPosition(m_pos + m_decoderResult.numReadChars, m_columnNumber + m_decoderResult.numReadChars);
301 }
302 
303 } // namespace zserio
304 
305 #endif // ZSERIO_JSON_TOKENIZER_H_INC
BasicJsonTokenizer(std::istream &in, const ALLOC &allocator)
Definition: JsonTokenizer.h:66
const AnyHolder< ALLOC > & getValue() const
Definition: JsonTokenizer.h:96
BasicStringView< char, std::char_traits< char >> StringView
Definition: StringView.h:933
std::basic_string< char, std::char_traits< char >, RebindAlloc< ALLOC, char >> string
Definition: String.h:16
JsonToken getToken() const
Definition: JsonTokenizer.h:86
CppRuntimeException(const char *message="")
CppRuntimeException & operator<<(CppRuntimeException &exception, const BasicBitBuffer< ALLOC > &bitBuffer)
Definition: BitBuffer.h:432