01. 64bit only
02. has my own memory allocator.
03. C++14~
04. experimental!
05. Array has my_own_vector<_Value>
06. Object has my_own_vector<Pair<_Value, _Value>> (not a std::map!)
07. in Object, key can be dupplicated, are not sorted, just in order of input.
08. scanning - modified? simdjson, parsing - parallel
09. it is not read-only!
10. _Value <- json_Value, (in destructor, no remove data(Array or Object!), no copy, only move or clone!
11. Value <- wrap _Value, (in destructor, remove data(Array or Object!)
C++17 ๊ธฐ๋ฐ์ ๊ณ ์ฑ๋ฅ ๋ฉํฐ์ค๋ ๋ JSON ํ์ ๋ฐ ์ง๋ ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- ๊ฐ์
- ์ํคํ ์ฒ ๊ตฌ์กฐ
- ํต์ฌ ํด๋์ค
- ํ์ ๋ฐ ์ง๋ ฌํ
- ์ ํธ๋ฆฌํฐ
- ํ์ ์์คํ
- ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
- ์ฌ์ฉ ์์
- ๋ด๋ถ ๊ตฌํ ์์ธ
claujson์ simdjson์ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋ C++ JSON ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์ฃผ์ ํน์ง:
- ๋ฉํฐ์ค๋ ๋ ํ์ฑ: JSON์ ์ฌ๋ฌ ์ฒญํฌ๋ก ๋ถํ ํ์ฌ ๋ณ๋ ฌ ํ์ฑ ํ ๋ณํฉ
- Arena ๊ธฐ๋ฐ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ: ๋ณ๋ ๋ฉ๋ชจ๋ฆฌ ํ์ ์ฌ์ฉํ์ฌ ํ ๋น/ํด์ ์ค๋ฒํค๋ ์ต์ํ
- ์ด๋ ์ ์ฉ(Move-only) ์ค๊ณ:
_Value,Value๋ฑ์ ํต์ฌ ํ์ ์ ๋ณต์ฌ ๋ถ๊ฐ, ์ด๋๋ง ๊ฐ๋ฅ - Short String ์ต์ ํ: 11๋ฐ์ดํธ ์ดํ์ ๋ฌธ์์ด์ ํ ํ ๋น ์์ด ์ธ๋ผ์ธ ์ ์ฅ
- ๋ณ๋ ฌ ์ง๋ ฌํ: JSON ํธ๋ฆฌ๋ฅผ ๋ถํ ํ์ฌ ๋ฉํฐ์ค๋ ๋๋ก ๋์ ์ง๋ ฌํ
claujson
โโโ claujson_internal.h # ๊ธฐ๋ฐ ํ์
, Arena, my_vector, Log ๋ฑ
โโโ claujson_string.h # String ํด๋์ค (SSO ํฌํจ)
โโโ claujson.h # _Value, Value, Document, StructuredPtr, parser, writer
โโโ claujson_array.h/.cpp # Array ํด๋์ค
โโโ claujson_object.h/.cpp # Object ํด๋์ค
โโโ claujson_partialjson.h/.cpp # PartialJson (ํ์ฑ ๋ด๋ถ์ฉ)
โโโ claujson.cpp # ํ์ฑ/์ง๋ ฌํ ํต์ฌ ๊ตฌํ, diff/patch
_Value
โโโ Array* (_array_ptr)
โโโ Object* (_obj_ptr)
โโโ PartialJson* (_pj_ptr)
โโโ String* (_str_val)
StructuredPtr
โโโ Array* / Object* / PartialJson* (union)
Document
โโโ _Value (๋ฃจํธ ๊ฐ)
โโโ Arena* (๋ฉ๋ชจ๋ฆฌ ํ)
JSON์ ๋จ์ผ ๊ฐ์ ๋ํ๋ด๋ ํต์ฌ ํด๋์ค์ ๋๋ค. ์ ์, ์ค์, ๋ถ๋ฆฌ์ธ, ๋ฌธ์์ด, null, ๋ฐฐ์ด, ๊ฐ์ฒด๋ฅผ ๋ชจ๋ ํํํฉ๋๋ค.
ํค๋: claujson.h
- ๋ณต์ฌ ๋ถ๊ฐ:
_Value(const _Value&) = delete - ์ด๋ ๊ฐ๋ฅ:
_Value(_Value&&) noexcept - ๋ด๋ถ์ ์ผ๋ก union์ ํตํด ํ์ ๋ณ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ์ ์ฅ
union {
int64_t _int_val;
uint64_t _uint_val;
double _float_val;
Array* _array_ptr;
Object* _obj_ptr;
PartialJson* _pj_ptr;
String* _str_val;
bool _bool_val;
};
_ValueType _type;| ์์ฑ์ | ์ค๋ช |
|---|---|
_Value() |
๊ธฐ๋ณธ ์์ฑ์ (NONE ํ์ ) |
_Value(int x) |
์ ์ ๊ฐ |
_Value(unsigned int x) |
๋ถํธ ์๋ ์ ์ |
_Value(int64_t x) |
64๋นํธ ์ ์ |
_Value(uint64_t x) |
64๋นํธ ๋ถํธ ์๋ ์ ์ |
_Value(double x) |
๋ถ๋์์์ |
_Value(bool x) |
๋ถ๋ฆฌ์ธ |
_Value(std::nullptr_t x) |
null ๊ฐ |
_Value(Arena* pool, StringView x) |
๋ฌธ์์ด (UTF-8 ๊ฒ์ฆ ํฌํจ) |
_Value(Arena* pool, const char* x) |
C ๋ฌธ์์ด |
_Value(Array* x) |
๋ฐฐ์ด ํฌ์ธํฐ๋ก๋ถํฐ |
_Value(Object* x) |
๊ฐ์ฒด ํฌ์ธํฐ๋ก๋ถํฐ |
| ๋ฉ์๋ | ๋ฐํ | ์ค๋ช |
|---|---|---|
is_valid() |
bool |
์ ํจํ ๊ฐ์ธ์ง ํ์ธ |
is_null() |
bool |
null ํ์ ์ธ์ง ํ์ธ |
is_primitive() |
bool |
๊ธฐ๋ณธ ํ์ ์ธ์ง ํ์ธ |
is_structured() |
bool |
๋ฐฐ์ด ๋๋ ๊ฐ์ฒด์ธ์ง ํ์ธ |
is_array() |
bool |
๋ฐฐ์ด์ธ์ง ํ์ธ |
is_object() |
bool |
๊ฐ์ฒด์ธ์ง ํ์ธ |
is_int() |
bool |
64๋นํธ ์ ์์ธ์ง ํ์ธ |
is_uint() |
bool |
๋ถํธ ์๋ 64๋นํธ ์ ์์ธ์ง ํ์ธ |
is_float() |
bool |
๋ถ๋์์์ ์ธ์ง ํ์ธ |
is_number() |
bool |
์ซ์ ํ์ ์ธ์ง ํ์ธ (int, uint, float) |
is_bool() |
bool |
๋ถ๋ฆฌ์ธ์ธ์ง ํ์ธ |
is_str() |
bool |
๋ฌธ์์ด์ธ์ง ํ์ธ |
is_virtual() |
bool |
๊ฐ์ ๋ ธ๋์ธ์ง ํ์ธ (๋ด๋ถ ํ์ฑ์ฉ) |
is_partial_json() |
bool |
๋ถ๋ถ JSON์ธ์ง ํ์ธ (๋ด๋ถ์ฉ) |
| ๋ฉ์๋ | ๋ฐํ | ์ค๋ช |
|---|---|---|
int_val() |
int64_t |
์ ์ ๊ฐ ๋ฐํ |
uint_val() |
uint64_t |
๋ถํธ ์๋ ์ ์ ๊ฐ ๋ฐํ |
float_val() |
double |
๋ถ๋์์์ ๊ฐ ๋ฐํ |
bool_val() |
bool |
๋ถ๋ฆฌ์ธ ๊ฐ ๋ฐํ |
str_val() |
String& |
๋ฌธ์์ด ๊ฐ์ฒด ์ฐธ์กฐ ๋ฐํ |
get_integer() |
int64_t |
์ ์ ๊ฐ ๋ฐํ (int_val() ๋ณ์นญ) |
get_unsigned_integer() |
uint64_t |
๋ถํธ ์๋ ์ ์ ๋ฐํ |
get_floating() |
double |
๋ถ๋์์์ ๋ฐํ |
get_boolean() |
bool |
๋ถ๋ฆฌ์ธ ๋ฐํ |
get_string() |
String& |
๋ฌธ์์ด ๋ฐํ |
get_number<T>() |
T |
์ซ์๋ฅผ ์ง์ ํ์ ์ผ๋ก ๋ณํ ๋ฐํ |
| ๋ฉ์๋ | ๋ฐํ | ์ค๋ช |
|---|---|---|
as_array() |
Array* |
Array ํฌ์ธํฐ ๋ฐํ (๋ฐฐ์ด์ด ์๋๋ฉด nullptr) |
as_object() |
Object* |
Object ํฌ์ธํฐ ๋ฐํ (๊ฐ์ฒด๊ฐ ์๋๋ฉด nullptr) |
as_partial_json() |
PartialJson* |
PartialJson ํฌ์ธํฐ ๋ฐํ |
as_structured() |
StructuredPtr |
๊ตฌ์กฐ์ฒด ํฌ์ธํฐ ๋ํผ ๋ฐํ |
as_structured_ptr() |
StructuredPtr |
๊ตฌ์กฐ์ฒด ํฌ์ธํฐ ๋ํผ ๋ฐํ |
| ์ฐ์ฐ์ | ์ค๋ช |
|---|---|
operator[](uint64_t idx) |
์ธ๋ฑ์ค๋ก ์์ ๊ฐ ์ ๊ทผ |
operator[](const _Value& key) |
ํค๋ก ์์ ๊ฐ ์ ๊ทผ (๊ฐ์ฒด) |
operator bool() |
์ ํจ์ฑ ํ์ธ |
operator== / operator!= |
๋น๊ต |
operator< |
์ ๋ ฌ์ฉ ๋น๊ต |
operator=(_Value&&) |
์ด๋ ๋์ |
| ๋ฉ์๋ | ์ค๋ช |
|---|---|
set_int(long long x) |
์ ์ ๊ฐ ์ค์ |
set_uint(unsigned long long x) |
๋ถํธ ์๋ ์ ์ ์ค์ |
set_float(double x) |
๋ถ๋์์์ ์ค์ |
set_str(Arena*, const char*, uint64_t) |
๋ฌธ์์ด ์ค์ (UTF-8 ๊ฒ์ฆ, ์ด์ค์ผ์ดํ ์ฒ๋ฆฌ) |
set_bool(bool x) |
๋ถ๋ฆฌ์ธ ์ค์ |
set_null() |
null ์ค์ |
set_none() |
NONE ํ์ ์ผ๋ก ์ด๊ธฐํ |
_Value& json_pointerB(const my_vector<_Value>& routeVec);
const _Value& json_pointerB(const my_vector<_Value>& routeVec) const;๊ฒฝ๋ก(route)๋ฅผ ๋ฐ๋ผ ์ค์ฒฉ๋ ๊ฐ์ ์ ๊ทผํฉ๋๋ค. ๋ฐฐ์ด์ ์ธ๋ฑ์ค(์ ์), ๊ฐ์ฒด๋ ํค(๋ฌธ์์ด)๋ฅผ ์ฌ์ฉํฉ๋๋ค.
_Value clone(Arena* pool) const;๊ฐ์ ๊น์ ๋ณต์ฌ(deep copy)ํฉ๋๋ค. pool์ด ์ ๊ณต๋๋ฉด Arena์ ํ ๋นํฉ๋๋ค.
JSON ๋ฐฐ์ด์ ๋ํ๋ด๋ ํด๋์ค์ ๋๋ค.
ํค๋: claujson_array.h
| ๋ฉ์๋ | ์ค๋ช |
|---|---|
static _Value Make(Arena* pool) |
์ผ๋ฐ ๋ฐฐ์ด ์์ฑ |
static _Value MakeVirtual(Arena* pool) |
๊ฐ์ ๋ฐฐ์ด ์์ฑ (๋ด๋ถ ํ์ฑ์ฉ) |
| ๋ฉ์๋ | ๋ฐํ | ์ค๋ช |
|---|---|---|
size() |
uint64_t |
์์ ์ ๋ฐํ |
empty() |
bool |
๋น์ด์๋์ง ํ์ธ |
get_data_size() |
uint64_t |
์์ ์ ๋ฐํ |
get_value_list(idx) |
_Value& |
์ธ๋ฑ์ค๋ก ๊ฐ ์ ๊ทผ |
operator[](idx) |
_Value& |
์ธ๋ฑ์ค๋ก ๊ฐ ์ ๊ทผ |
add_element(Value val) |
bool |
์์ ์ถ๊ฐ |
assign_element(idx, Value val) |
bool |
์ธ๋ฑ์ค ์์น์ ๊ฐ ๋์ |
insert(idx, Value val) |
bool |
์ธ๋ฑ์ค ์์น์ ์ฝ์ |
erase(idx, bool real) |
void |
์ธ๋ฑ์ค ์์น ์์ ์ญ์ |
erase(const _Value&, bool real) |
void |
๊ฐ์ผ๋ก ๊ฒ์ ํ ์ญ์ |
find(const _Value&, start) |
uint64_t |
๊ฐ ๊ฒ์, ์์ผ๋ฉด npos |
clear() |
void |
์ ์ฒด ์ด๊ธฐํ |
clear(idx) |
void |
์ธ๋ฑ์ค ์์น ์์ ์ด๊ธฐํ |
reserve_data_list(len) |
void |
์ฉ๋ ์์ฝ |
clone(Arena*) |
_Value |
๊น์ ๋ณต์ฌ |
is_virtual() |
bool |
๊ฐ์ ๋ ธ๋ ์ฌ๋ถ |
get_parent() |
StructuredPtr |
๋ถ๋ชจ ๋ ธ๋ ๋ฐํ |
set_parent(StructuredPtr) |
void |
๋ถ๋ชจ ๋ ธ๋ ์ค์ |
_ValueIterator begin(); // _Value*
_ValueIterator end();
_ConstValueIterator begin() const;
_ConstValueIterator end() const;JSON ๊ฐ์ฒด(ํค-๊ฐ ์์ ์ปฌ๋ ์ )๋ฅผ ๋ํ๋ด๋ ํด๋์ค์ ๋๋ค.
ํค๋: claujson_object.h
| ๋ฉ์๋ | ์ค๋ช |
|---|---|
static _Value Make(Arena* pool) |
์ผ๋ฐ ๊ฐ์ฒด ์์ฑ |
static _Value MakeVirtual(Arena* pool) |
๊ฐ์ ๊ฐ์ฒด ์์ฑ (๋ด๋ถ ํ์ฑ์ฉ) |
| ๋ฉ์๋ | ๋ฐํ | ์ค๋ช |
|---|---|---|
size() |
uint64_t |
ํค-๊ฐ ์์ ์ ๋ฐํ |
empty() |
bool |
๋น์ด์๋์ง ํ์ธ |
get_data_size() |
uint64_t |
ํค-๊ฐ ์์ ์ ๋ฐํ |
get_value_list(idx) |
_Value& |
์ธ๋ฑ์ค๋ก ๊ฐ ์ ๊ทผ |
get_key_list(idx) |
_Value& |
์ธ๋ฑ์ค๋ก ํค ์ ๊ทผ (private) |
get_const_key_list(idx) |
const _Value& |
์ธ๋ฑ์ค๋ก ํค ์ฝ๊ธฐ |
operator[](const _Value& key) |
_Value& |
ํค๋ก ๊ฐ ์ ๊ทผ |
operator[](uint64_t idx) |
_Value& |
์ธ๋ฑ์ค๋ก ๊ฐ ์ ๊ทผ |
find(const _Value& key) |
uint64_t |
ํค ๊ฒ์, ์์ผ๋ฉด npos |
add_element(Value key, Value val) |
bool |
ํค-๊ฐ ์ ์ถ๊ฐ |
assign_value_element(idx, Value val) |
bool |
์ธ๋ฑ์ค ์์น์ ๊ฐ ๋์ |
change_key(const _Value&, Value) |
bool |
ํค ๋ณ๊ฒฝ |
change_key(uint64_t idx, Value) |
bool |
์ธ๋ฑ์ค๋ก ํค ๋ณ๊ฒฝ |
erase(const _Value& key, bool real) |
void |
ํค๋ก ์ญ์ |
erase(uint64_t idx, bool real) |
void |
์ธ๋ฑ์ค๋ก ์ญ์ |
chk_key_dup(uint64_t*) |
bool |
ํค ์ค๋ณต ํ์ธ |
clear() |
void |
์ ์ฒด ์ด๊ธฐํ |
reserve_data_list(len) |
void |
์ฉ๋ ์์ฝ |
clone(Arena*) |
_Value |
๊น์ ๋ณต์ฌ |
// Pair<_Value, _Value>* (ํค-๊ฐ ์ ํฌ์ธํฐ)
_ValueIterator begin();
_ValueIterator end();
_ConstValueIterator begin() const;
_ConstValueIterator end() const;๋ฉํฐ์ค๋ ๋ ํ์ฑ ๊ณผ์ ์์ ๋ถํ ๋ JSON ์กฐ๊ฐ์ ์์๋ก ๋ณด๊ดํ๋ ๋ด๋ถ ํด๋์ค์ ๋๋ค.
ํค๋: claujson_partialjson.h
์ฃผ์: ์ด ํด๋์ค๋
LoadData/LoadData2๋ด๋ถ์์๋ง ์ฌ์ฉ๋๋ฉฐ, ์ผ๋ฐ ์ฌ์ฉ์๋ ์ง์ ๋ค๋ฃจ์ง ์์ต๋๋ค.
- ๋ฐฐ์ด(
arr_vec) ๋๋ ๊ฐ์ฒด(obj_data) ์ค ํ๋๋ก ์๋ virtualJson: ๊ฐ์ ๋ฃจํธ ๋ ธ๋(๋ถํ ๊ฒฝ๊ณ์์ ๋ฐ์)๋ฅผ ๋ณด๊ด- ๋ถ๋ชจ๊ฐ
nullptr์ธ ์ต์์ ๋ถ๋ถ JSON
| ๋ฉ์๋ | ์ค๋ช |
|---|---|
add_array_element(Value val) |
๋ฐฐ์ด ์์ ์ถ๊ฐ |
add_object_element(Value key, Value val) |
๊ฐ์ฒด ์์ ์ถ๊ฐ |
get_data_size() |
๋ณด๊ด ์ค์ธ ์์ ์ |
get_value_list(idx) |
์ธ๋ฑ์ค๋ก ๊ฐ ์ ๊ทผ |
get_key_list(idx) |
์ธ๋ฑ์ค๋ก ํค ์ ๊ทผ |
MergeWith(Array*, int) |
Array์ ๋ณํฉ |
MergeWith(PartialJson*, int) |
PartialJson๊ณผ ๋ณํฉ |
Array*, Object*, PartialJson*๋ฅผ ํ๋์ ํ์
์ผ๋ก ๋ค๋ฃจ๋ ํฌ์ธํฐ ๋ํผ์
๋๋ค.
ํค๋: claujson.h
StructuredPtr() // nullptr
StructuredPtr(Array* arr) // type = 1
StructuredPtr(Object* obj) // type = 2
StructuredPtr(PartialJson* pj) // type = 3
StructuredPtr(_Value& x) // _Value๋ก๋ถํฐ ์๋ ํ๋ณ
StructuredPtr(const _Value& x)bool is_array() const;
bool is_object() const;
bool is_partial_json() const;
bool is_nullptr() const;
bool is_user_type() const; // array || object
bool is_virtual() const;
explicit operator bool() const;| ๋ฉ์๋ | ์ค๋ช |
|---|---|
size() / empty() |
ํฌ๊ธฐ ํ์ธ |
get_data_size() |
์์ ์ |
get_value_list(idx) |
๊ฐ ์ ๊ทผ |
get_key_list(idx) |
ํค ์ ๊ทผ (๊ฐ์ฒด/PartialJson) |
get_const_key_list(idx) |
ํค ์ฝ๊ธฐ ์ ์ฉ ์ ๊ทผ |
add_array_element(Value) |
๋ฐฐ์ด์ ์์ ์ถ๊ฐ |
add_object_element(Value, Value) |
๊ฐ์ฒด์ ํค-๊ฐ ์ถ๊ฐ |
operator[](const _Value&) |
ํค๋ก ๊ฐ ์ ๊ทผ |
operator[](uint64_t) |
์ธ๋ฑ์ค๋ก ๊ฐ ์ ๊ทผ |
find_by_key(const _Value&) |
ํค ๊ฒ์ |
find_by_value(const _Value&, start) |
๊ฐ ๊ฒ์ |
insert(idx, Value) |
๋ฐฐ์ด์ ์ฝ์ |
erase(idx, bool) |
์ธ๋ฑ์ค๋ก ์ญ์ |
erase(const _Value&, bool) |
ํค๋ก ์ญ์ |
assign_value(idx, Value) |
์ธ๋ฑ์ค ์์น์ ๊ฐ ๋์ |
change_key(const _Value&, Value&&) |
ํค ๋ณ๊ฒฝ |
change_key(uint64_t, Value&&) |
์ธ๋ฑ์ค๋ก ํค ๋ณ๊ฒฝ |
chk_key_dup(uint64_t*) |
ํค ์ค๋ณต ํ์ธ |
get_parent() |
๋ถ๋ชจ ๋ ธ๋ ๋ฐํ |
null_parent() |
๋ถ๋ชจ ํฌ์ธํฐ null๋ก ์ค์ |
MergeWith(StructuredPtr, int) |
๋ค๋ฅธ ๊ตฌ์กฐ์ฒด์ ๋ณํฉ |
reserve_data_list(sz) |
์ฉ๋ ์์ฝ |
clear() |
์ ์ฒด ์ด๊ธฐํ |
clear(idx) |
ํน์ ์ธ๋ฑ์ค ์ด๊ธฐํ |
Delete() |
ํฌ์ธํฐ delete ๋ฐ nullptr ์ค์ |
get_pool() |
Arena ํฌ์ธํฐ ๋ฐํ |
has_pool() |
Arena ์ฌ์ฉ ์ฌ๋ถ |
ํ์ฑ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ ํ๋ ์ต์์ ์ปจํ ์ด๋์ ๋๋ค.
ํค๋: claujson.h
class Document {
_Value x; // ๋ฃจํธ JSON ๊ฐ
Arena* pool; // ๋ฉ๋ชจ๋ฆฌ ํ
};Document(uint64_t size = Arena::initialSize);
Document(_Value&& x, uint64_t size = Arena::initialSize);
Document(Document&& d) noexcept;| ๋ฉ์๋ | ๋ฐํ | ์ค๋ช |
|---|---|---|
Get() |
_Value& |
๋ฃจํธ ๊ฐ ์ ๊ทผ |
Get() const |
const _Value& |
๋ฃจํธ ๊ฐ ์ฝ๊ธฐ ์ ์ฉ ์ ๊ทผ |
GetAllocator() |
Arena* |
๋ฉ๋ชจ๋ฆฌ ํ ์ ๊ทผ |
SSO(Small String Optimization)๋ฅผ ์ง์ํ๋ ๋ฌธ์์ด ํด๋์ค์ ๋๋ค.
ํค๋: claujson_string.h
- Short String: 11๋ฐ์ดํธ(
CLAUJSON_STRING_BUF_SIZE) ์ดํ๋ ์ธ๋ผ์ธ ๋ฒํผ์ ์ ์ฅ (_ValueType::SHORT_STRING) - Long String: 11๋ฐ์ดํธ ์ด๊ณผ ์ ํ(๋๋ Arena)์ ํ ๋น (
_ValueType::STRING) - ๋ณต์ฌ ๋ถ๊ฐ (
operator=(const String&) = delete) - ์ด๋ ๊ฐ๋ฅ
| ๋ฉ์๋ | ์ค๋ช |
|---|---|
data() |
char* ํฌ์ธํฐ ๋ฐํ |
size() |
๋ฌธ์์ด ๊ธธ์ด ๋ฐํ |
is_valid() |
์ ํจ์ฑ ํ์ธ |
is_str() |
๋ฌธ์์ด ํ์ ์ธ์ง ํ์ธ |
clear() |
๋ฉ๋ชจ๋ฆฌ ํด์ ๋ฐ ์ด๊ธฐํ |
clone(Arena*) |
๋ณต์ฌ๋ณธ ์์ฑ |
get_std_string(bool&) |
std::string์ผ๋ก ๋ณํ |
get_string_view(bool&) |
StringView๋ก ๋ณํ |
find(char, start) |
๋ฌธ์ ๊ฒ์ |
substr(start, len) |
๋ถ๋ถ ๋ฌธ์์ด ์์ฑ |
operator== / operator< |
๋น๊ต |
๋ธ๋ก ๊ธฐ๋ฐ ๋ฉ๋ชจ๋ฆฌ ํ๋ก, ๋น๋ฒํ new/delete๋ฅผ ๋์ฒดํฉ๋๋ค.
ํค๋: claujson_internal.h
- ๋ ์ข
๋ฅ์ ๋ธ๋ก ๊ด๋ฆฌ: ์ผ๋ฐ ํฌ๊ธฐ(
no=0)์ ๋ํ ํฌ๊ธฐ(no=1) - ์ ๋ ฌ(alignment) ์ง์:
std::align์ ์ฌ์ฉํ์ฌ ์ฌ๋ฐ๋ฅธ ์ ๋ ฌ ๋ณด์ฅ link_from(): ์ฌ๋ฌ Arena๋ฅผ ํ๋๋ก ์ฐ๊ฒฐ (๋ณ๋ ฌ ํ์ฑ ํ ๋ณํฉ ์ ์ฌ์ฉ)
template <class T>
T* allocate(uint64_t size, uint64_t align = alignof(T));
template <class T>
void deallocate(T* ptr, uint64_t len); // ํ์ฌ no-op (์ต์ ํ ๋ชฉ์ ์ฝ๋๋ง ์กด์ฌ)
template<typename T, typename... Args>
T* create(Args&&... args); // allocate + placement new
void Clear(); // ๋ธ๋ก ์ฌ์ฌ์ฉ (ํด์ ํ์ง ์์)
void Reset(); // ๋ธ๋ก ๋ฆฌ์
void link_from(Arena* other); // ๋ค๋ฅธ Arena ๋ธ๋ก์ ์ด์ชฝ์ผ๋ก ์ฐ๊ฒฐstatic const uint64_t initialSize = 1024 * 1024; // ๊ธฐ๋ณธ ๋ธ๋ก ํฌ๊ธฐ (1MB)JSON์ ํ์ฑํ๋ ํด๋์ค์ ๋๋ค.
ํค๋: claujson.h
class parser {
_simdjson::dom::parser_for_claujson test_;
std::unique_ptr<ThreadPool> pool;
};parser(int thr_num = 0); // thr_num=0์ด๋ฉด ํ๋์จ์ด ์ค๋ ๋ ์์์ 2๋ฅผ ๋บ ๊ฐ ์ฌ์ฉ// JSON ํ์ผ ํ์ฑ
std::pair<bool, uint64_t> parse(const std::string& fileName, Document& d, uint64_t thr_num);
// JSON ๋ฌธ์์ด ํ์ฑ
std::pair<bool, uint64_t> parse_str(StringView str, Document& d, uint64_t thr_num);
// C++20: UTF-8 ๋ฌธ์์ด ํ์ฑ
std::pair<bool, uint64_t> parse_str(std::u8string_view str, Document& d, uint64_t thr_num);๋ฐํ๊ฐ: {์ฑ๊ณต ์ฌ๋ถ, ์ฒ๋ฆฌ๋ ํ ํฐ ์}
1. simdjson stage1: ๊ตฌ์กฐ ํ ํฐ ์์ธ ์์ฑ
2. is_valid2(): ๋ณ๋ ฌ ๋ฌธ๋ฒ ๊ฒ์ฆ ๋ฐ count_vec ๊ตฌ์ฑ
3. LoadData2::parse(): ๋ณ๋ ฌ JSON ํธ๋ฆฌ ๊ตฌ์ฑ
โโโ ์ฒญํฌ๋ณ __LoadData() ๋ณ๋ ฌ ์คํ (ThreadPool)
โโโ Merge(): ์ฒญํฌ ๊ฒฐ๊ณผ ์์ฐจ ๋ณํฉ
4. ์ต์ข
_Value ๋ฐํ
JSON์ ์ง๋ ฌํํ๋ ํด๋์ค์ ๋๋ค.
ํค๋: claujson.h
class writer {
std::unique_ptr<ThreadPool> pool;
};writer(int thr_num = 0);| ๋ฉ์๋ | ์ค๋ช |
|---|---|
write_to_str(const _Value&, bool pretty) |
JSON ๋ฌธ์์ด๋ก ์ง๋ ฌํ |
write_to_str2(const _Value&, bool pretty) |
JsonView ๋ฐฉ์์ผ๋ก ์ง๋ ฌํ (์คํ์ ) |
write(const string&, const _Value&, bool pretty) |
ํ์ผ๋ก ์ง๋ ฌํ |
write_parallel(Arena*, string&, _Value&, uint64_t, bool) |
ํธ๋ฆฌ ๋ถํ ๋ณ๋ ฌ ์ง๋ ฌํ |
write_parallel2(string&, const _Value&, uint64_t, bool) |
JsonView ๊ธฐ๋ฐ ๋ณ๋ ฌ ์ง๋ ฌํ |
write_parallel3(Arena*, string&, _Value&, uint64_t, bool) |
NodeView ๊ธฐ๋ฐ ๋ณ๋ ฌ ์ง๋ ฌํ (์คํ์ -ํ ์คํธ์ค..) |
| ๋ฐฉ์ | ํด๋์ค | ๋ฉํฐ์ค๋ ๋ | ํน์ง |
|---|---|---|---|
write_to_str |
LoadData2::_write |
No | ์ฌ๊ท์ DFS ์ํ |
write_to_str2 |
JsonView + print |
๊ฐ๋ฅ | ๋ฐฐ์ด ๊ธฐ๋ฐ ์ ํ ์ํ |
write_parallel |
LoadData2::write_ |
Yes | ํธ๋ฆฌ ๋ถํ ํ ์ฒญํฌ๋ณ ์ง๋ ฌํ |
write_parallel2 |
JsonView + print |
Yes | ์ ํ JsonView ๋ฐฐ์ด ๋ถํ |
๋ JSON ๊ฐ์ ์ฐจ์ด๋ฅผ ๊ณ์ฐํ๊ณ ์ ์ฉํฉ๋๋ค.
[[nodiscard]]
_Value diff(Arena* pool, const _Value& x, const _Value& y);
_Value& patch(Arena* pool, _Value& x, const _Value& diff);diff ๊ฒฐ๊ณผ๋ JSON Patch(RFC 6902 ์ ์ฌ) ํ์์ ๋ฐฐ์ด์ ๋๋ค:
[
{ "op": "replace", "path": [...], "value": <new_value> },
{ "op": "remove", "path": [...], "last_key": "key" },
{ "op": "remove", "path": [...], "last_idx": 3 },
{ "op": "add", "path": [...], "key": "key", "value": <value> },
{ "op": "add", "path": [...], "value": <value> }
]/*
// JSON ๋ฌธ์์ด ๋ด ์ด์ค์ผ์ดํ ์ฒ๋ฆฌ (์: \n -> \\n)
std::pair<bool, std::string> convert_to_string_in_json(StringView x);
// JSON ๋ฌธ์์ด๋ก์ ์ ํจํ์ง ํ์ธ
bool is_valid_string_in_json(StringView x);
// ์ซ์ ๋ฌธ์์ด์ _Value๋ก ๋ณํ
bool convert_number(StringView x, claujson::_Value& data);
// ๋ฌธ์์ด์ _Value๋ก ๋ณํ
bool convert_string(StringView x, claujson::_Value& data);
*//*
#if __cpp_lib_char8_t
std::pair<bool, std::string> convert_to_string_in_json(std::u8string_view x);
bool is_valid_string_in_json(std::u8string_view x);
#endif
*/void clean(_Value& x);_Value์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ํฉ๋๋ค. Arena๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์๋ฉธ์๋ง ํธ์ถํ๊ณ , ํ ํ ๋น์ ๊ฒฝ์ฐ deleteํฉ๋๋ค.
์ฐธ๊ณ : ํ์ฌ ๊ตฌํ์์๋ ์ฆ์ ๋ฐํ(
return)ํ์ฌ ์ค์ ํด์ ๋ฅผ ์ํํ์ง ์์ต๋๋ค. Arena์ ์๋ช ์ฃผ๊ธฐ์ ๋ฐ๋ผ ์ผ๊ด ํด์ ๋ฅผ ๊ธฐ๋ํ๋ ์ค๊ณ์ ๋๋ค.
claujson::Log log; // ์ ์ญ ๋ก๊ทธ ๊ฐ์ฒด
claujson::Log::Info info; // ์ ๋ณด ๋ ๋ฒจ ํ๊ทธ
claujson::Log::Warning warn; // ๊ฒฝ๊ณ ๋ ๋ฒจ ํ๊ทธclaujson::log.console(); // ์ฝ์ ์ถ๋ ฅ ํ์ฑํ
claujson::log.info(); // INFO ๋ ๋ฒจ ํ์ฑํ
claujson::log.warn(); // WARN ๋ ๋ฒจ ํ์ฑํ
claujson::log << claujson::info << "ํ์ฑ ์์\n";
claujson::log << claujson::warn << "์ค๋ฅ ๋ฐ์\n";| ์ต์ | ์ค๋ช |
|---|---|
log.console() |
์ฝ์ ์ถ๋ ฅ |
log.file() |
ํ์ผ ์ถ๋ ฅ |
log.console_and_file() |
์ฝ์ + ํ์ผ |
log.no_print() |
์ถ๋ ฅ ๋นํ์ฑํ |
log.file_name(str) |
๋ก๊ทธ ํ์ผ๋ช ์ค์ |
enum class _ValueType : int32_t {
NONE = 0, // ์ด๊ธฐํ๋์ง ์์ ์ํ
ARRAY, // JSON ๋ฐฐ์ด
OBJECT, // JSON ๊ฐ์ฒด
PARTIAL_JSON, // ๋ถ๋ถ JSON (๋ด๋ถ์ฉ)
INT, // 64๋นํธ ๋ถํธ ์๋ ์ ์
UINT, // 64๋นํธ ๋ถํธ ์๋ ์ ์
FLOAT, // IEEE 754 double
BOOL, // ๋ถ๋ฆฌ์ธ
NULL_, // JSON null
STRING, // ๋ฌธ์์ด (ํ/Arena ํ ๋น)
SHORT_STRING, // ๋ฌธ์์ด (11๋ฐ์ดํธ ์ดํ ์ธ๋ผ์ธ ์ ์ฅ)
NOT_VALID, // ์ ํจํ์ง ์์ ๊ฐ (์ ๊ทผ ๋ถ๊ฐ ๋ง์ปค)
ERROR // ์ค๋ฅ ์ํ
};_Value๋ฅผ ์์ ํ๊ฒ ์ ๋ฌํ๊ธฐ ์ํ ๋ํผ์
๋๋ค.
class Value {
_Value x;
public:
Value(_Value&& x) noexcept;
Value(Value&& x) noexcept;
_Value& Get() noexcept;
const _Value& Get() const noexcept;
};
add_element,add_object_element๋ฑ์ ๋ฉ์๋๋Value๋ฅผ ์ธ์๋ก ๋ฐ์ ์์ ๊ถ์ ์ด์ ํฉ๋๋ค.
Arena pool;
// Array ์์ฑ - pool ํ ๋น
_Value arr = Array::Make(&pool);
// Object ์์ฑ - pool ํ ๋น
_Value obj = Object::Make(&pool);
// ๋ฌธ์์ด ์์ฑ - pool ํ ๋น
_Value str(&pool, "hello"sv);ํฌ๊ธฐ < defaultBlockSize(1MB) โ Block[0] (์ผ๋ฐ ๋ธ๋ก)
ํฌ๊ธฐ >= defaultBlockSize โ Block[1] (๋ํ ๋ธ๋ก)
๋ฉ์ธ pool
โโโ link_from(sub_pool_1)
โโโ link_from(sub_pool_2)
โโโ link_from(sub_pool_3)
๊ฐ ์ค๋ ๋๋ ๋
๋ฆฝ์ ์ธ Arena๋ฅผ ์ฌ์ฉํ์ฌ ํ์ฑํ๊ณ , ์๋ฃ ํ ๋ฉ์ธ Arena์ ๋ธ๋ก์ ์ฐ๊ฒฐํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ค๋ ๋ ๊ฐ ๋ฉ๋ชจ๋ฆฌ ๊ฒฝํฉ์ ์ ๊ฑฐํฉ๋๋ค.
#include "claujson.h"
// ๋ก๊ทธ ์ค์ (์ ํ)
claujson::log.console();
claujson::log.warn();
// ํ์ ์์ฑ
claujson::parser p;
claujson::Document doc;
// ํ์ผ ํ์ฑ
auto [ok, token_count] = p.parse("data.json", doc, 4);
if (!ok) {
// ์ค๋ฅ ์ฒ๋ฆฌ
return;
}
claujson::_Value& root = doc.Get();claujson::parser p;
claujson::Document doc;
auto [ok, _] = p.parse_str(R"({"name": "Alice", "age": 30})", doc, 1);
if (ok) {
auto& root = doc.Get();
// root๋ Object
}claujson::_Value& root = doc.Get();
// ๊ฐ์ฒด ์ ๊ทผ
if (root.is_object()) {
claujson::Arena arena;
claujson::_Value key(&arena, "name");
claujson::_Value& name = root[key];
if (name.is_str()) {
bool fail = false;
std::string s = name.str_val().get_std_string(fail);
}
}
// ๋ฐฐ์ด ์ ๊ทผ
if (root.is_array()) {
uint64_t sz = root.as_array()->size();
for (uint64_t i = 0; i < sz; ++i) {
claujson::_Value& elem = root[i];
if (elem.is_int()) {
int64_t v = elem.int_val();
}
}
}claujson::Arena pool;
// ๋ฐฐ์ด ์์ฑ
claujson::_Value arr = claujson::Array::Make(&pool);
arr.as_array()->add_element(claujson::Value(claujson::_Value(42LL)));
arr.as_array()->add_element(claujson::Value(claujson::_Value(true)));
arr.as_array()->add_element(claujson::Value(claujson::_Value(&pool, "hello"sv)));
// ๊ฐ์ฒด ์์ฑ
claujson::_Value obj = claujson::Object::Make(&pool);
obj.as_object()->add_element(
claujson::Value(claujson::_Value(&pool, "key"sv)),
claujson::Value(claujson::_Value(123LL))
);claujson::writer w;
// ๋ฌธ์์ด๋ก ๋ณํ
std::string json_str = w.write_to_str(root, false); // compact
std::string json_pretty = w.write_to_str(root, true); // pretty
// ํ์ผ๋ก ์ ์ฅ
w.write("output.json", root, false);
// ๋ณ๋ ฌ ์ง๋ ฌํ (๋์ฉ๋)
Arena* pool = doc.GetAllocator();
w.write_parallel(pool, "output.json", root, 4, false);claujson::Arena pool;
claujson::_Value d = claujson::diff(&pool, original, modified);
// diff ์ ์ฉ
claujson::_Value& patched = claujson::patch(&pool, original, d);ํฌ์ธํฐ์ 2๋นํธ์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ธ์ฝ๋ฉํ๋ ํด๋์ค์ ๋๋ค (ํฌ์ธํฐ ํ๊น ๊ธฐ๋ฒ).
class Pointer {
void* ptr;
// bit 63 : left_type (is_virtual ์ฌ๋ถ)
// bits 1-0 : right_type (1=Array, 2=Object, 3=PartialJson)
};Array์ Object์ parent ํ๋์ ์ฌ์ฉ๋ฉ๋๋ค.
Arena๋ฅผ ์ง์ํ๋ ์ปค์คํ ๋์ ๋ฐฐ์ด์ ๋๋ค.
template <class T>
using my_vector = Vector2<T>;์ฃผ์ ๊ธฐ๋ฅ:
- Arena ํ ๋น/ํด์ ์ง์
Divide(start_idx): ์ง์ ์ธ๋ฑ์ค๋ถํฐ ๋๊น์ง ๋ถ๋ฆฌํ์ฌ ์ ๋ฒกํฐ ๋ฐํinsert(start, end): ์ด๋ ์๋งจํฑ์ผ๋ก ์์ ์ฝ์
๋ณ๋ ฌ ํ์ฑ ๋ฐ ์ง๋ ฌํ์ ํต์ฌ ๋ก์ง์ ๋ด๋นํฉ๋๋ค.
์ฃผ์ ๋ด๋ถ ๋ฉ์๋:
| ๋ฉ์๋ | ์ค๋ช |
|---|---|
__LoadData(...) |
์ ์ ํจ์. ๋จ์ผ ์ฒญํฌ๋ฅผ ํ์ฑํ์ฌ PartialJson ๊ตฌ์ฑ |
Merge(next, ut, ut_next) |
๋ PartialJson์ ๋ณํฉ |
Merge2(next, ut, ut_next, op) |
Merge์ ๋ณํ (null ut ์ฒ๋ฆฌ ์ถ๊ฐ) |
Divide(pool, pos, result) |
ํธ๋ฆฌ์ ํน์ ์์น์์ ๋ถํ ํ์ฌ PartialJson ์์ฑ |
Divide2(pool, n, j, result, hint) |
n๊ฐ์ ๋ถํ ์ ๊ณ์ฐ ๋ฐ ๋ถํ ์คํ |
Find2(root, n, idx, ...) |
๊ท ๋ฑ ๋ถํ ์ ํ์ (์ฌ๊ท) |
Size(Array*) |
์๋ธํธ๋ฆฌ์ ๋ ธ๋ ์ ๊ณ์ฐ |
Size2(const _Value&) |
JsonView์ฉ ๋ ธ๋ ์ ๊ณ์ฐ |
_write(...) |
์ฌ๊ท DFS ์ง๋ ฌํ |
_write2(...) |
๋ฐ๋ณต ์คํ ๊ธฐ๋ฐ ์ง๋ ฌํ |
simdjson์ ๊ตฌ์กฐ ํ ํฐ ๋ฐฐ์ด์ ๊ธฐ๋ฐ์ผ๋ก JSON ๋ฌธ๋ฒ ์ ํจ์ฑ์ ๊ฒ์ฌํฉ๋๋ค. goto ๊ธฐ๋ฐ ์ํ ๋จธ์ ์ผ๋ก ๊ตฌํ๋์ด ์์ต๋๋ค.
์ํ ๋ชฉ๋ก:
object_begin/object_field/object_continuearray_begin/array_value/array_continuescope_end/document_end
๋์์ ๊ฐ ๋ฐฐ์ด/๊ฐ์ฒด์ ์์ ์๋ฅผ count_vec์ ๊ธฐ๋กํ์ฌ ์ดํ reserve_data_list() ์ต์ ํ์ ํ์ฉํฉ๋๋ค.
write_parallel2 / write_to_str2์์ ์ฌ์ฉํ๋ ์ ํ ๋ทฐ ํํ์
๋๋ค.
struct JsonView {
Pointer value;
// right_type: 0=ARRAY_START, 1=OBJECT_START, 2=KEY, 3=VALUE
// left_type: 1 = END(ARRAY/OBJECT)
};JSON ํธ๋ฆฌ๋ฅผ DFS ์์๋ก ํผ์ณ ๋ฐฐ์ด์ ์ ์ฅํ ๋ค, ์ํ๋ ๊ตฌ๊ฐ์ ์ฌ๋ฌ ์ค๋ ๋์ ๋ถ๋ฐฐํ์ฌ ๋ณ๋ ฌ ์ง๋ ฌํ๋ฅผ ์ํํฉ๋๋ค.
๋ณธ ๋ฌธ์๋ claujson ์์ค ์ฝ๋ ๋ถ์์ ๊ธฐ๋ฐ์ผ๋ก ์์ฑ๋์์ต๋๋ค.