A C++ toolbox repo until the pair uTL/dTL arives
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

203 lines
6.6 KiB

  1. /*!
  2. * \file files.h
  3. * \brief
  4. * File functionality header
  5. *
  6. * \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net>
  7. *
  8. * <dl class=\"section copyright\"><dt>License</dt><dd>
  9. * All Rights Reserved.
  10. *
  11. * NOTICE: All information contained herein is, and remains
  12. * the property of Christos Choutouridis. The intellectual
  13. * and technical concepts contained herein are proprietary to
  14. * Christos Choutouridis and are protected by copyright law.
  15. * Dissemination of this information or reproduction of this material
  16. * is strictly forbidden unless prior written permission is obtained
  17. * from Christos Choutouridis.
  18. * </dd></dl>
  19. */
  20. #ifndef JSON_H_
  21. #define JSON_H_
  22. #include <cstddef>
  23. #include <cstdlib>
  24. #include <cstring>
  25. #include <cctype>
  26. #include <type_traits>
  27. #include <string_view>
  28. #include <array>
  29. using size_t = std::size_t;
  30. struct jpair_t {
  31. std::string_view key;
  32. std::string_view value;
  33. };
  34. template<size_t N>
  35. struct json_dec_t {
  36. using string_view = std::string_view;
  37. json_dec_t(const char* buffer, size_t size) noexcept :
  38. buffer_(buffer, size), valid_(true) {
  39. enum state_t {
  40. ST=0, KEY, COLON, VALUE, SP
  41. } state = ST;
  42. size_t pairs =0;
  43. char* begin = nullptr;
  44. int s =0;
  45. for (size_t i=0 ; i<size ; ++i) {
  46. switch (state) {
  47. case ST:
  48. if (std::isspace(buffer[i]))
  49. continue; // skip white space
  50. if (buffer[i] == '{')
  51. state = KEY;
  52. break;
  53. case KEY:
  54. if (pairs >= N) {
  55. valid_ = false;
  56. break;
  57. }
  58. if (std::isspace(buffer[i]))
  59. continue; // skip white space
  60. if (buffer[i] == '\"') {
  61. if (!begin)
  62. begin = (char*)&buffer[i+1];
  63. else {
  64. s = (char*)&buffer[i] - begin;
  65. if (s > 0)
  66. pairs_[pairs].key = std::string_view{begin, (size_t)s};
  67. else
  68. pairs_[pairs].key = std::string_view{};
  69. begin =nullptr;
  70. s =0;
  71. state = COLON;
  72. }
  73. }
  74. else if (buffer[i] == '}')
  75. return;
  76. break;
  77. case COLON:
  78. if (std::isspace(buffer[i]))
  79. continue; // skip white space
  80. if (buffer[i] == ':')
  81. state = VALUE;
  82. else {
  83. valid_ = false;
  84. return;
  85. }
  86. break;
  87. case VALUE:
  88. if (pairs >= N) {
  89. valid_ = false;
  90. break;
  91. }
  92. if (!begin && std::isspace(buffer[i]))
  93. continue;
  94. else if (!begin && !std::isspace(buffer[i]))
  95. begin = (buffer[i] != '\"') ? (char*)&buffer[i] : (char*)&buffer[i+1];
  96. else if (begin && (std::isspace(buffer[i]) || buffer[i] == ',' || buffer[i] == '}')) {
  97. s = (char*)&buffer[i] - begin;
  98. s -= (buffer[i-1] == '\"') ? 1:0;
  99. if (s > 0)
  100. pairs_[pairs].value = std::string_view{begin, (size_t)s};
  101. else
  102. pairs_[pairs].value = std::string_view{};
  103. ++pairs;
  104. begin =nullptr;
  105. s =0;
  106. if (std::isspace(buffer[i]))
  107. state = SP;
  108. else if (buffer[i] == ',')
  109. state = KEY;
  110. else if (buffer[i] == '}')
  111. return;
  112. }
  113. break;
  114. case SP:
  115. if (std::isspace(buffer[i]))
  116. continue; // skip white space
  117. else if (buffer[i] == ',')
  118. state = KEY;
  119. else if (buffer[i] == '}')
  120. return;
  121. else {
  122. valid_ = false;
  123. return;
  124. }
  125. break;
  126. }
  127. }
  128. }
  129. template<typename T>
  130. T get (const char* key) {
  131. T t{};
  132. for (auto& it : pairs_) {
  133. if (it.key.compare(key) == 0) {
  134. extract_(it.value, &t);
  135. break;
  136. }
  137. }
  138. return t;
  139. }
  140. bool is_valid() const { return valid_; }
  141. private:
  142. /*!
  143. * Convert the text pointed by \c str to a value and store it to
  144. * \c value. The type of conversion is deduced by the compiler
  145. * \tparam T The type of the value
  146. * \param str pointer to string with the value
  147. * \param value pointer to converted value
  148. */
  149. void extract_(std::string_view str, bool* value) {
  150. *value = (
  151. !std::strncmp(str.data(), "true", str.size()) ||
  152. !std::strncmp(str.data(), "True", str.size()) ||
  153. !std::strncmp(str.data(), "TRUE", str.size()) ||
  154. !std::strncmp(str.data(), "1", str.size())
  155. ) ? true : false;
  156. }
  157. void extract_(std::string_view str, int* value) {
  158. *value = std::atoi(str.data());
  159. }
  160. void extract_(std::string_view str, unsigned int* value) {
  161. *value = (unsigned int)std::atoi(str.data());
  162. }
  163. void extract_(std::string_view str, long* value) {
  164. *value = std::atol(str.data());
  165. }
  166. void extract_(std::string_view str, unsigned long* value) {
  167. *value = (unsigned long)std::atol(str.data());
  168. }
  169. void extract_(std::string_view str, double* value) {
  170. *value = std::atof(str.data());
  171. }
  172. void extract_(std::string_view str, char** value) {
  173. *value = (char*)str.data();
  174. }
  175. void extract_(std::string_view str, string_view* value) {
  176. *value = str;
  177. }
  178. //! Specialization (as overload function) to handle void* types
  179. void extract_ (const char* str, void* value) noexcept {
  180. (void)*str; (void)value;
  181. }
  182. private:
  183. std::string_view buffer_;
  184. std::array<jpair_t, N> pairs_;
  185. bool valid_;
  186. };
  187. #endif /* JSON_H_ */