tbx/include/utils/json.h

225 lines
7.5 KiB
C++

/*!
* \file files.h
* \brief
* File functionality header
*
* \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net>
*
* <dl class=\"section copyright\"><dt>License</dt><dd>
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Christos Choutouridis. The intellectual
* and technical concepts contained herein are proprietary to
* Christos Choutouridis and are protected by copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Christos Choutouridis.
* </dd></dl>
*/
#ifndef JSON_H_
#define JSON_H_
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <type_traits>
#include <string_view>
#include <array>
using size_t = std::size_t;
struct jpair_t {
std::string_view key;
std::string_view value;
};
template<size_t N>
struct json_dec_t {
using string_view = std::string_view;
json_dec_t(const char* buffer, size_t size) noexcept :
buffer_(buffer, size), valid_(true) {
enum state_t {
ST=0, KEY, COLON, VALUE, SP
} state = ST;
size_t pairs =0;
char* begin = nullptr;
int s =0;
bool str_value = false; // flag to indicate the value is string
for (size_t i=0 ; i<size ; ++i) {
switch (state) {
case ST:
if (std::isspace(buffer[i]))
continue; // skip white space
if (buffer[i] == '{')
state = KEY;
break;
case KEY:
if (pairs >= N) {
valid_ = false;
break;
}
if (std::isspace(buffer[i]))
continue; // skip white space
if (buffer[i] == '\"') {
if (!begin)
begin = (char*)&buffer[i+1];
else {
s = (char*)&buffer[i] - begin;
if (s > 0)
pairs_[pairs].key = std::string_view{begin, (size_t)s};
else
pairs_[pairs].key = std::string_view{};
begin =nullptr;
s =0;
state = COLON;
}
}
else if (buffer[i] == '}')
return;
break;
case COLON:
if (std::isspace(buffer[i]))
continue; // skip white space
if (buffer[i] == ':')
state = VALUE;
else {
valid_ = false;
return;
}
break;
case VALUE:
if (pairs >= N) {
valid_ = false;
break;
}
if (!begin && std::isspace(buffer[i])) // consume pre-spaces
continue;
else if (!begin && !std::isspace(buffer[i])) { // first character
if (buffer[i] == '\"') {
begin = (char*)&buffer[i+1];
str_value = true;
}
else {
begin = (char*)&buffer[i];
str_value = false;
}
}
else if (begin) {
if (str_value && (buffer[i] == '\"')) {
s = (char*)&buffer[i] - begin;
if (s > 0)
pairs_[pairs].value = std::string_view{begin, (size_t)s};
else
pairs_[pairs].value = std::string_view{};
++pairs;
begin =nullptr;
s =0;
state = SP;
}
else if (!str_value && (std::isspace(buffer[i]) || buffer[i] == ',' || buffer[i] == '}')) {
s = (char*)&buffer[i] - begin;
if (s > 0)
pairs_[pairs].value = std::string_view{begin, (size_t)s};
else
pairs_[pairs].value = std::string_view{};
++pairs;
begin =nullptr;
s =0;
if (std::isspace(buffer[i]))
state = SP;
else if (buffer[i] == ',')
state = KEY;
else if (buffer[i] == '}')
return;
}
}
break;
case SP:
if (std::isspace(buffer[i]))
continue; // skip white space
else if (buffer[i] == ',')
state = KEY;
else if (buffer[i] == '}')
return;
else {
valid_ = false;
return;
}
break;
}
}
}
template<typename T>
T get (const char* key) {
T t{};
for (auto& it : pairs_) {
if (it.key.compare(key) == 0) {
extract_(it.value, &t);
break;
}
}
return t;
}
bool is_valid() const { return valid_; }
private:
/*!
* Convert the text pointed by \c str to a value and store it to
* \c value. The type of conversion is deduced by the compiler
* \tparam T The type of the value
* \param str pointer to string with the value
* \param value pointer to converted value
*/
void extract_(std::string_view str, bool* value) {
*value = (
!std::strncmp(str.data(), "true", str.size()) ||
!std::strncmp(str.data(), "True", str.size()) ||
!std::strncmp(str.data(), "TRUE", str.size()) ||
!std::strncmp(str.data(), "1", str.size())
) ? true : false;
}
void extract_(std::string_view str, int* value) {
*value = std::atoi(str.data());
}
void extract_(std::string_view str, unsigned int* value) {
*value = (unsigned int)std::atoi(str.data());
}
void extract_(std::string_view str, long* value) {
*value = std::atol(str.data());
}
void extract_(std::string_view str, unsigned long* value) {
*value = (unsigned long)std::atol(str.data());
}
void extract_(std::string_view str, double* value) {
*value = std::atof(str.data());
}
void extract_(std::string_view str, char** value) {
*value = (char*)str.data();
}
void extract_(std::string_view str, string_view* value) {
*value = str;
}
//! Specialization (as overload function) to handle void* types
void extract_ (const char* str, void* value) noexcept {
(void)*str; (void)value;
}
private:
std::string_view buffer_;
std::array<jpair_t, N> pairs_;
bool valid_;
};
#endif /* JSON_H_ */