Zserio C++ runtime library  1.0.1
Built for Zserio 2.14.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  return false;
195 
196  m_tokenColumnNumber = m_columnNumber;
197 
198  const char nextChar = m_content[m_pos];
199  switch (nextChar)
200  {
201  case '{':
202  setToken(JsonToken::BEGIN_OBJECT, nextChar);
203  setPosition(m_pos + 1, m_columnNumber + 1);
204  break;
205  case '}':
206  setToken(JsonToken::END_OBJECT, nextChar);
207  setPosition(m_pos + 1, m_columnNumber + 1);
208  break;
209  case '[':
210  setToken(JsonToken::BEGIN_ARRAY, nextChar);
211  setPosition(m_pos + 1, m_columnNumber + 1);
212  break;
213  case ']':
214  setToken(JsonToken::END_ARRAY, nextChar);
215  setPosition(m_pos + 1, m_columnNumber + 1);
216  break;
217  case ':':
218  setToken(JsonToken::KEY_SEPARATOR, nextChar);
219  setPosition(m_pos + 1, m_columnNumber + 1);
220  break;
221  case ',':
222  setToken(JsonToken::ITEM_SEPARATOR, nextChar);
223  setPosition(m_pos + 1, m_columnNumber + 1);
224  break;
225  default:
226  m_decoderResult = m_decoder.decodeValue(StringView(m_content.data()).substr(m_pos));
227  if (m_pos + m_decoderResult.numReadChars >= m_content.size())
228  return false; // we are at the end of chunk => read more
229 
230  setTokenValue();
231  break;
232  }
233 
234  return true;
235 }
236 
237 template <typename ALLOC>
238 bool BasicJsonTokenizer<ALLOC>::skipWhitespaces()
239 {
240  while (true)
241  {
242  if (m_pos >= m_content.size())
243  {
244  setToken(JsonToken::END_OF_FILE);
245  return false;
246  }
247 
248  const char nextChar = m_content[m_pos];
249  switch (nextChar)
250  {
251  case ' ':
252  case '\t':
253  setPosition(m_pos + 1, m_columnNumber + 1);
254  break;
255  case '\n':
256  m_lineNumber++;
257  setPosition(m_pos + 1, 1);
258  break;
259  case '\r':
260  if (m_pos + 1 >= m_content.size())
261  {
262  setToken(JsonToken::END_OF_FILE);
263  return false;
264  }
265  m_lineNumber++;
266  setPosition(m_pos + (m_content[m_pos + 1] == '\n' ? 2 : 1), 1);
267  break;
268  default:
269  return true;
270  }
271  }
272 }
273 
274 template <typename ALLOC>
275 template <typename T>
276 void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token, T&& value)
277 {
278  m_token = token;
279  m_value.set(std::forward<T>(value));
280 }
281 
282 template <typename ALLOC>
283 void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token, AnyHolder<ALLOC>&& value)
284 {
285  m_token = token;
286  m_value = std::move(value);
287 }
288 
289 template <typename ALLOC>
290 void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token)
291 {
292  m_token = token;
293  m_value.reset();
294 }
295 
296 template <typename ALLOC>
297 void BasicJsonTokenizer<ALLOC>::setPosition(size_t newPos, size_t newColumnNumber)
298 {
299  m_pos = newPos;
300  m_columnNumber = newColumnNumber;
301 }
302 
303 template <typename ALLOC>
304 void BasicJsonTokenizer<ALLOC>::setTokenValue()
305 {
306  if (!m_decoderResult.value.hasValue())
307  {
308  throw JsonParserException("JsonTokenizer:")
309  << m_lineNumber << ":" << m_tokenColumnNumber << ": "
310  << (m_decoderResult.integerOverflow ? "Value is outside of the 64-bit integer range!"
311  : "Unknown token!");
312  }
313 
314  setToken(JsonToken::VALUE, std::move(m_decoderResult.value));
315  setPosition(m_pos + m_decoderResult.numReadChars, m_columnNumber + m_decoderResult.numReadChars);
316 }
317 
318 } // namespace zserio
319 
320 #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:936
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:435