Skip to content

Commit 5b48bdf

Browse files
committed
Обновлена используемая версия simstr.
1 parent 39b5187 commit 5b48bdf

6 files changed

Lines changed: 62 additions & 50 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ include(FetchContent)
55

66
project(
77
simjson
8-
VERSION 1.2.2
8+
VERSION 1.2.3
99
DESCRIPTION "Very simple json library"
1010
HOMEPAGE_URL "https://github.com/orefkov/simjson"
1111
LANGUAGES CXX
@@ -67,7 +67,7 @@ function(add_simstr)
6767
simstr
6868
GIT_REPOSITORY https://github.com/orefkov/simstr.git
6969
GIT_SHALLOW TRUE
70-
GIT_TAG 458007e
70+
GIT_TAG tags/rel1.2.6
7171
FIND_PACKAGE_ARGS NAMES simstr
7272
)
7373
FetchContent_MakeAvailable(simstr)

include/simjson/json.h

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -582,32 +582,36 @@ class JsonValueTempl : public Json {
582582
return at(std::forward<T>(key));
583583
}
584584
/*!
585-
* @ru @brief Обращение к свойству константного объекта по набору ключей.
586-
* @details Функция последовательно переходит от значения к значению по заданным ключам.
587-
* Как только указанный ключ не будет найден, перебор останавливается.
588-
* Например: config("a", "b", "c") для объекта {"a": {"b": {"c": 10}}} вернёт ссылку на 10.
585+
* @ru @brief Обращение к свойству константного объекта по набору ключей/индексов.
586+
* @details Функция последовательно переходит от значения к значению по заданным ключам/индексам.
587+
* Как только указанный ключ/индекс не будет найден, перебор останавливается.
588+
* Например: config("a", "b", 1, "c") для объекта {"a": {"b":[{"c": 2}, {"c": 10}]}} вернёт ссылку на 10.
589589
* @tparam T - типа ключа.
590-
* @param key - ключ.
590+
* @param key - ключ / индекс.
591591
* @param ...args - остальные ключи.
592-
* @return const json_value& - ссылка на значение ключа.
592+
* @return const json_value& - ссылка на найденное значение.
593593
* Если значение не объект, или указанного ключа нет, не создаёт новую пару, а возвращает ссылку на UNDEFINED.
594-
* @en @brief Access to a property of a constant object by a set of keys.
595-
* @details The function moves sequentially from value to value based on the given keys.
596-
* As soon as the specified key is not found, the search stops.
597-
* For example: config("a", "b", "c") for object {"a": {"b": {"c": 10}}} will return a reference to 10.
594+
* @en @brief Access to a property of a constant object by a set of keys/indexes.
595+
* @details The function moves sequentially from value to value based on the given keys/indexes.
596+
* As soon as the specified key/index is not found, the search stops.
597+
* For example: config("a", "b", 1, "c") for object {"a": {"b": [{"c": 2}, {"c": 10}]}} will return a reference to 10.
598598
* @tparam T - key type.
599-
* @param key - key.
599+
* @param key - key / index.
600600
* @param ...args - other keys.
601601
* @return const json_value& - reference to the key value.
602602
* If the value is not an object, or the specified key does not exist, does not create a new pair, but returns a reference to UNDEFINED.
603603
*/
604-
template<jt::JsonKeyType<K> T, typename...Args>
604+
template<typename T, typename...Args> requires (jt::JsonKeyType<T, K> || std::convertible_to<T, size_t>)
605605
const json_value& operator()(T&& key, Args&&...args) const {
606606
const json_value& res = at(std::forward<T>(key));
607607
if constexpr (sizeof...(Args) == 0) {
608608
return res;
609609
} else {
610-
return res.is_undefined() ? res : res(std::forward<Args>(args)...);
610+
if constexpr (jt::JsonKeyType<std::tuple_element_t<0, std::tuple<Args...>>, K>) {
611+
return res.is_object() ? res(std::forward<Args>(args)...) : UNDEFINED;
612+
} else {
613+
return res.is_array() ? res(std::forward<Args>(args)...) : UNDEFINED;
614+
}
611615
}
612616
}
613617
/*!

readme.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33

44
Designed to work with JSON when using the [simstr](https://github.com/orefkov/simstr) library.
55

6-
Version 1.2.2.
6+
Version 1.2.3.
77

88
<span class="obfuscator"><a href="readme_ru.md">On Russian | По-русски</a></span>
99

1010
This library contains a simple implementation of a simple JsonValue object for working with JSON using string objects
1111
of the *simstr* library, since other libraries mainly work with `std::string` or raw `const char*`.
1212
The task was not to somehow compete in performance or optimality with other libraries, I mainly use it
13-
for working with small config files - read, modify, write.
13+
for working with small config files - read, modify, write. However, it also copes quite well with large files.
1414

1515
For json objects, `std::unordered_map` is used, in the form of `hashStrMap<K, JsonValueTemp<K>>`,
1616
for arrays - `std::vector<JsonValueTemp<K>>`, strings are stored in `sstring<K>`.
@@ -50,7 +50,7 @@ downloads automatically).
5050
// Simple json, equal to 1.
5151
JsonValue json = 1; // int64
5252
stringa text = json.store(); // "1"
53-
53+
5454
// Initialization of the object, ""_h - slightly optimizes the key, calculating the hash during compilation
5555
JsonValue obj = {
5656
{"Key1"_h, 1},
@@ -67,7 +67,7 @@ downloads automatically).
6767
// Saving keys, immediately several levels
6868
test["a"_h]["b"_h]["c"_h] = 10;
6969
text = json.store(); // {"a":{"b":{"c":10}}}
70-
70+
7171
// Converts a json object to an array
7272
test[0] = "value";
7373
test[-1] = true; // When using -1 - the value is added to the end of the array
@@ -114,9 +114,9 @@ void read_config_from_file(ssa folder, ssa file_name) {
114114
stringa config;
115115
if (is_file_exist(fullPath)) {
116116
config = get_file_content(fullPath);
117-
117+
118118
auto [readed, error, line, col] = JsonValue::parse(config);
119-
119+
120120
if (error != JsonParseResult::Success) {
121121
std::cerr << "Error in parse config file " << fullPath <<
122122
" at line " << line << ", col " << col << std::endl;

readme_ru.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33

44
Предназначена для работы с JSON при использовании библиотеки [simstr](https://github.com/orefkov/simstr).
55

6-
Версия 1.2.2.
6+
Версия 1.2.3.
77

88
<span class="obfuscator"><a href="readme.md">On English | По-английски</a></span>
99

1010
В этой библиотеке содержится простая реализация простого объекта JsonValue для работы с JSON с использованием строковых объектов
1111
библиотеки *simstr*, так как другие библиотеки работают в основном с `std::string` или сырыми `const char*`.
12-
Задача как-то соревноваться по производительности или оптимальности с другими библиотеками не ставилась, я её применяю в-основном
13-
для работы с небольшими конфиг-файлами - прочитать, изменить, записать.
12+
Задача как-то соревноваться по производительности или оптимальности с другими библиотеками не ставилась, я её применяю в-основном
13+
для работы с небольшими конфиг-файлами - прочитать, изменить, записать, однако и с большими файлами она вполне успешно справляется.
1414

1515
Для json-объектов используется `std::unordered_map`, в лице `hashStrMap<K, JsonValueTemp<K>>`,
1616
для массивов - `std::vector<JsonValueTemp<K>>`, строки хранятся в `sstring<K>`.
@@ -50,7 +50,7 @@
5050
// Простой json, равный 1.
5151
JsonValue json = 1; // int64
5252
stringa text = json.store(); // "1"
53-
53+
5454
// Инициализация объекта, ""_h - несколько оптимизирует ключ, вычисляя хэш при компиляции
5555
JsonValue obj = {
5656
{"Key1"_h, 1},
@@ -67,7 +67,7 @@
6767
// Сохраняем ключи, сразу несколько уровней
6868
test["a"_h]["b"_h]["c"_h] = 10;
6969
text = json.store(); // {"a":{"b":{"c":10}}}
70-
70+
7171
// Преобразует json-объект в массив
7272
test[0] = "value";
7373
test[-1] = true; // При использовании -1 - значение добавляется в конец массива
@@ -114,9 +114,9 @@ void read_config_from_file(ssa folder, ssa file_name) {
114114
stringa config;
115115
if (is_file_exist(fullPath)) {
116116
config = get_file_content(fullPath);
117-
117+
118118
auto [readed, error, line, col] = JsonValue::parse(config);
119-
119+
120120
if (error != JsonParseResult::Success) {
121121
std::cerr << "Error in parse config file " << fullPath <<
122122
" at line " << line << ", col " << col << std::endl;

src/json.cpp

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ inline static bool is_double_int64(double dbl) {
243243
return
244244
!std::isnan(dbl) &&
245245
!std::isinf(dbl) &&
246-
// std::numeric_limits<int64_t>::max() при конвертировании в double меняет 9223372036854775807 на 9223372036854775808
247246
dbl <= (uint64_t(1) << 53) &&
248247
dbl >= -(int64_t)(uint64_t(1) << 53);
249248
}
@@ -254,20 +253,15 @@ SIMJSON_API std::optional<int64_t> JsonValueTempl<K>::to_integer() const {
254253
case Boolean:
255254
return val_.boolean ? 1 : 0;
256255
case Text: {
257-
auto txt = as_text().template trimmed_right<ssType>();
258-
auto [res, err, processed] = txt.template to_int<int64_t>();
256+
auto txt = as_text().trimmed();
257+
auto [res, err, processed] = txt.template to_int<int64_t, true, 0, false>();
259258
if (err == IntConvertResult::Success) {
260259
return res;
261260
}
262261
if (processed > 0 && err == IntConvertResult::BadSymbolAtTail &&
263-
(txt[processed] == '.' || txt[processed] == 'e' || txt[processed] == 'E')) {
262+
(txt[processed] == '.' || (txt[processed] | 0x20) == 'e')) {
264263
// Считаем, что в тексте double
265-
auto dbl = std::nan("");
266-
if constexpr (is_one_of_std_char_v<K>) {
267-
dbl = txt.to_double();
268-
} else {
269-
dbl = lstringa<100>{txt}.to_double();
270-
}
264+
auto dbl = txt.to_double().value_or(std::nan("0"));
271265
if (is_double_int64(dbl)) {
272266
return static_cast<int64_t>(dbl);
273267
}
@@ -301,11 +295,7 @@ SIMJSON_API double JsonValueTempl<K>::to_real() const {
301295
case Json::Boolean:
302296
return val_.boolean ? 1.0 : 0.0;
303297
case Json::Text:
304-
if constexpr (is_one_of_std_char_v<K>) {
305-
return val_.text.to_double();
306-
} else {
307-
return lstringa<100>{val_.text}.to_double();
308-
}
298+
return val_.text.to_double().value_or(std::nan("0"));
309299
case Json::Integer:
310300
return static_cast<double>(val_.integer);
311301
case Json::Real:
@@ -485,7 +475,10 @@ struct json_store {
485475
}
486476
}
487477
}
488-
buffer += e_if(prettify && printed, uni_string(K, "\n") + e_c(indent - indent_count, indent_symb)) + uni_string(K, "}");
478+
if (prettify && printed) {
479+
buffer += uni_string(K, "\n") + e_c(indent - indent_count, indent_symb);
480+
}
481+
buffer += uni_string(K, "}");
489482
break;
490483
case Json::Array:
491484
buffer += uni_string(K, "[");
@@ -494,7 +487,10 @@ struct json_store {
494487
store(it, indent + indent_count);
495488
printed = true;
496489
}
497-
buffer += e_if(prettify && printed, uni_string(K, "\n") + e_c(indent - indent_count, indent_symb)) + uni_string(K, "]");
490+
if (prettify && printed) {
491+
buffer += uni_string(K, "\n") + e_c(indent - indent_count, indent_symb);
492+
}
493+
buffer += uni_string(K, "]");
498494
break;
499495
}
500496
}
@@ -1120,11 +1116,7 @@ JsonValueTempl<K>* StreamedJsonParser<K>::addNumber(JsonValueTempl<K>* current)
11201116
}
11211117

11221118
if (!asInt || jsonValue.is_undefined()) {
1123-
if constexpr (is_one_of_std_char_v<K>) {
1124-
jsonValue = ssValue.to_double();
1125-
} else {
1126-
jsonValue = lstringa<100>(ssValue).to_double();
1127-
}
1119+
jsonValue = ssValue.to_double().value_or(std::nan("0"));
11281120
}
11291121

11301122
if constexpr (!All) {

tests/test_json.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,22 @@ TEST(SimJson, JsonStdInitMap) {
501501
EXPECT_EQ(json2.store(false, true), "{\"four\":4,\"one\":1,\"three\":3,\"two\":2}");
502502
}
503503

504+
TEST(SimJson, ManyKeys) {
505+
JsonValueU json = {
506+
{u"a"_h, {
507+
{u"b"_h, {
508+
{{u"c"_h, 1}},
509+
{{u"c"_h, 10}}
510+
}}
511+
}},
512+
};
513+
EXPECT_EQ(json.store(), uR"=({"a":{"b":[{"c":1},{"c":10}]}})=");
514+
515+
const auto v = json(u"a"_h, u"b"_h, 1, u"c"_h);
516+
ASSERT_TRUE(v.is_integer());
517+
EXPECT_EQ(v.as_integer(), 10);
518+
}
519+
504520
#if 0
505521
TEST(SimJson, JsonParseBig) {
506522
stringa content1 = get_file_content("citm_catalog.json");

0 commit comments

Comments
 (0)