include: co/json.h.
co/json
是一个类似 rapidjson 的 json 库,与 rapidjson 相比,它既有一定的性能优势,同时又更简单易用。
最新版本的实现中,将 json 对象构建到一块连续的内存上,大大减少了内存分配操作,json 的 parsing 速度也有了显著提升,实测可以超过 rapidjson 的两倍。由于一个 json 对象就是一块连续的内存,拷贝起来很容易,因此移除了早期版本中使用的引用计数。
#基本概念
#JSON 数据格式
JSON 是一种简单的数据格式,它支持两种数据结构:
- 由一系列 key/value 键值对构成的集合,这类结构称为 object,对应编程语言中的 struct, map 等等。
- 由一系列 value 构成的列表,这类结构称为 array,对应编程语言中的 vector, list 等等。
上述 key 是 string,value 一般也称为 JSON value,可以是 object, array, number, string, bool(false, true), null 中的任意一种。number 是整数或浮点数,大部分实现会将整数与浮点数区分开。
object 由一对大括号括起来,array 由一对中括号括起来,它们看起来像下面这样:
{"a":1, "b":false, "s":"xxx"}
[1, 3.14, true, "xxx"]
由定义 object 与 array 可以嵌套,从而可以表示树等复杂数据结构。
#json::Json
co/json 用 json::Json
类表示 JSON,为了方便,还给出了下面的 typedef 定义:
typedef json::Json Json;
在 co/json 的实现中,Json 类的数据成员仅有一个指针,它指向一块连续的内存。实际应用中,Json 一般是 object 或 array 类型。
#json::Value
co/json 用 json::Value
类表示 JSON value,它可以是 object, array, string, int, double, bool, null 中的任意一种。
json::Value 的结构如下:
class Value {
Json* _root;
uint32 _index;
};
它包含一个 Json 类的指针,以及一个 index,表示它在 Json 内存块中的位置。用户无法直接创建 json::Value 对象,只能由 Json 类中的一些方法创建。
json::Value 几乎支持 Json 类中的所有操作,因此,下面关于 Json 类的文档,一般也适用于 json::Value 类。
#json::Json (Json)
#Json::Json
Json();
Json(Json&& r);
Json(const Json& r);
- 第 1 个版本是默认构造函数,构建一个 null 对象。
- 第 2 个版本是 move 构造函数,参数 r 的内容转移到所构建的 Json 对象中,r 自身失效。
- 第 3 个版本是拷贝构造函数,通过内存拷贝构建一个 Json 对象。
#json::array
Json array();
- 此函数在 namespace json 下,它返回一个空的 array 对象。
#json::object
Json object();
- 此函数在 namespace json 下,它返回一个空的 object 对象。
#Json::operator=
Json& operator=(const Json& r);
Json& operator=(Json&& r) noexcept;
- 第 1 个版本进行内存拷贝,用 r 的内容覆盖原来的内容。
- 第 2 个版本直接转移 r 的内容,r 自身失效。
#———————————
#Json::add_member
void add_member(const char* key, bool x);
void add_member(const char* key, int64 x);
void add_member(const char* key, int x);
void add_member(const char* key, uint32 x);
void add_member(const char* key, uint64 x);
void add_member(const char* key, double x);
void add_member(const char* key, const char* x, size_t n);
void add_member(const char* key, const char* x);
void add_member(const char* key, const std::string& x);
void add_member(const char* key, const fastring& x);
-
向 object 类型的 Json 中添加 key-value 键值对 (null 调用此方法后自动变成 object)。
-
参数 key 是
'\0'
结尾的 C 字符串,参数 x 是所添加的值。 -
第 1 个版本添加 bool 类型的值。
-
第 2-5 个版本添加整数类型的值。
-
第 6 个版本添加 double 类型的值。
-
第 7-10 个版本添加 string 类型的值。
-
温馨提示: co/json 出于性能上的考虑,要求 key 中不能包含双引号,最好不要包含任何转义字符。我从未见有人这样用过,如果有的话,请告诉我,我再考虑支持一下^o^。
-
示例
Json r;
r.add_member("a", 1); // r -> {"a":1}
r.add_member("d", 3.3); // r -> {"a":1, "d":3.3}
r.add_member("s", "xx"); // r -> {"a":1, "d":3.3, "s":"xx"}
#Json::add_null
void add_null(const char* key);
-
向 object 类型的 Json 中添加 null。
-
示例
Json r;
r.add_null("x"); // r -> {"x": null}
#Json::add_array
Value add_array(const char* key, uint32 cap=0);
-
向 object 类型的 Json 中添加 array。
-
参数 cap 指定所添加 array 的初始容量,默认为 0。如果预先知道 array 的大小(size) 为 n,则可以直接将 cap 设为 n,这样可以减少不必要的内存重分配及消耗。
-
此方法向 Json 中添加一个空的 array,并返回表示该 array 的
json::Value
对象,用户可以通过返回值继续往该 array 里面添加元素。 -
示例
Json r;
auto a = r.add_array("xxx", 3); // r -> {"xxx": []}
a.push_back(1, 2, 3); // r -> {"xxx": [1,2,3]}
#Json::add_object
Value add_object(const char* key, uint32 cap=0);
-
向 object 类型的 Json 中添加 object。
-
参数 cap 指定所添加 object 的初始容量,默认为 0。如果预先知道 object 的大小(size) 为 n,则可以直接将 cap 设为 n,这样可以减少不必要的内存重分配及消耗。
-
此方法向 Json 中添加一个空的 object,并返回表示该 object 的
json::Value
对象,用户可以通过返回值继续往该 object 里面添加元素。 -
示例
Json r;
auto o = r.add_object("xxx", 3); // r -> {"xxx": {}}
o.add_member("a", 1); // r -> {"xxx": {"a":1}}
o.add_member("b", 2); // r -> {"xxx": {"a":1, "b":2}}
o.add_member("c", 3); // r -> {"xxx": {"a":1, "b":2, "c":3}}
#Json::push_back
void push_back(bool x);
void push_back(int64 x);
void push_back(int x);
void push_back(uint32 x);
void push_back(uint64 x);
void push_back(double x);
void push_back(const char* x, size_t n);
void push_back(const char* x);
void push_back(const std::string& x);
void push_back(const fastring& x);
template <typename X, typename ...V> void push_back(X x, V... v);
-
向 array 类型的 Json 中添加元素(null 调用此方法后自动变成 array)。
-
第 1 个版本添加 bool 类型的值。
-
第 2-5 个版本添加整数类型的值。
-
第 6 个版本添加 double 类型的值。
-
第 7-10 个版本添加 string 类型的值。
-
第 11 个版本接受任意数量的参数,参数必须是版本 1-10 中的类型。
-
示例
Json r;
r.push_back(1); // r -> [1]
r.push_back(3.3); // r -> [1, 3.3]
r.push_back("xx"); // r -> [1, 3.3, "xx"]
Json s;
s.push_back(1, 3.3, "xx"); // s -> [1, 3.3, "xx"]
#Json::push_null
void push_null();
-
向 array 类型的 Json 中添加 null 对象。
-
示例
Json r;
r.push_null(); // r -> [null]
#Json::push_array
Value push_array(uint32 cap=0);
-
向 array 类型的 Json 中添加 array。
-
参数 cap 指定所添加 array 的初始容量,默认为 0。如果预先知道 array 的大小(size) 为 n,则可以直接将 cap 设为 n,这样可以减少不必要的内存重分配及消耗。
-
此方法向 Json 中添加一个空的 array,并返回表示该 array 的
json::Value
对象,用户可以通过返回值继续往该 array 里面添加元素。 -
示例
Json r;
auto a = r.push_array(3); // r -> [[]]
a.push_back(1, 2, 3.3); // r -> [[1, 2, 3.3]]
#Json::push_object
Value push_object(uint32 cap=0);
-
向 array 类型的 Json 中添加 object。
-
参数 cap 指定所添加 object 的初始容量,默认为 0。如果预先知道 object 的大小(size) 为 n,则可以直接将 cap 设为 n,这样可以减少不必要的内存重分配及消耗。
-
此方法向 Json 中添加一个空的 object,并返回表示该 object 的
json::Value
对象,用户可以通过返回值继续往该 object 里面添加元素。 -
示例
Json r;
auto o = r.push_object(3); // r -> [{}]
o.add_member("a", 1); // r -> [{"a":1}]
o.add_member("b", 2); // r -> [{"a":1, "b":2}]
o.add_member("c", 3); // r -> [{"a":1, "b":2, "c":3}]
#———————————
#Json::str
fastream& str(fastream& fs) const;
fastring str(uint32 cap=256) const;
- 将 Json 对象转换成字符串。
- 第 1 个版本将 JSON 字符串写入 fastream 中,返回值与参数 fs 相同。
- 第 2 个版本直接返回 JSON 字符串,参数 cap 是字符串初始容量,默认为 256,设置为合适的值可以减少内存重分配。
#Json::pretty
fastream& pretty(fastream& fs) const;
fastring pretty(uint32 cap=256) const;
- 将 Json 对象转换成更漂亮的 JSON 字符串,除了结果好看点,其他与
Json::str()
一样。
#Json::dbg
fastream& dbg(fastream& fs) const;
fastring dbg(uint32 cap=256) const;
- 将 Json 对象转换成 debug 字符串,当 string 类型的值长度超过 512 字节时,截断取前 32 字节,其他与
Json::str()
一样。 - 此方法一般用于打印日志。有些应用场景中,Json 对象可能包含较长的 string,如一个图片文件的 base64 编码,这个时候用
Json::dbg()
取代Json::str()
方法,可以避免打印过多无意义的日志。
#Json::parse_from
bool parse_from(const char* s, size_t n);
bool parse_from(const char* s);
bool parse_from(const fastring& s);
bool parse_from(const std::string& s);
- 从 JSON 字符串解析 Json 对象。
- 第 1 个版本中,s 不要求以
'\0'
结尾。 - 解析成功时,返回 true,否则返回 false。
- 解析失败时,Json 内部状态是不确定的,如果用户没有判断返回值,就直接使用 Json 对象,可能导致未定义的行为。
- 一般推荐使用更安全的
json::parse()
函数,它在解析失败时始终返回 null 对象。
#json::parse
Json parse(const char* s, size_t n);
Json parse(const char* s);
Json parse(const fastring& s);
Json parse(const std::string& s);
- 从 JSON 字符串解析 Json 对象。
- 此函数不是 Json 类中的方法,而是定义于
namespace json
下的函数。 - 此函数返回一个 Json 对象,解析失败时,返回 null。
#代码示例
Json r;
auto a = r.add_array("a");
a.push_back(1, 2, 3);
fastring s = r.str(); // s -> {"a":[1,2,3]}
fastring p = r.pretty();
LOG << r.dbg(); // print json debug string
LOG << r; // the same as above, may be more efficient
Json x;
x.parse_from(s);
x.parse_from(p);
s = "{\"a\":[1,false,3.14]}";
Json v = json::parse(s); // v -> {"a":[1,false,3.14]}
#———————————
#Json::is_null
bool is_null() const;
- 判断 Json 对象是否为 null。
#Json::is_bool
bool is_bool() const;
- 判断 Json 对象是否为 bool 类型。
#Json::is_int
bool is_int() const;
- 判断 Json 对象是否为整数类型。
#Json::is_double
bool is_double() const;
- 判断 Json 对象是否为 double 类型。
#Json::is_string
bool is_string() const;
- 判断 Json 对象是否为字符串类型。
#Json::is_array
bool is_array() const;
- 判断 Json 对象是否为 array 类型。
#Json::is_object
bool is_object() const;
- 判断 Json 对象是否为 object 类型。
#———————————
#Json::get_bool
bool get_bool() const;
- 获取 bool 类型的值,若调用此方法的 Json 对象不是 bool 类型,返回值为 false。
#Json::get_int
int get_int() const;
int32 get_int32() const;
int64 get_int64() const;
uint32 get_uint32() const;
uint64 get_uint64() const;
- 获取整数类型的值,若调用这些方法的 Json 对象不是整数类型,返回值为 0。
#Json::get_double
double get_double() const;
- 获取 double 类型的值,若调用此方法的 Json 对象不是 double 类型,返回值是 0.0。
#Json::get_string
const char* get_string() const;
- 获取字符串类型的值,若调用此方法的 Json 对象不是字符串类型,返回值是空字符串。
- 此方法返回
'\0'
结尾的 C 字符串,用户还可以调用string_size()
方法获取字符串的长度。
#代码示例
Json r;
r.add_member("a", 1);
r.add_member("d", 3.3);
r.add_member("s", "xx");
r["a"].get_int(); // return 1
r["d"].get_double(); // return 3.3
r["s"].get_string(); // return "xx"
#———————————
#Json::set_null
void set_null();
- 将 Json 对象设置为 null。
#Json::set_array
void set_array();
- 将 Json 对象设置为一个空的 array。
#Json::set_object
void set_object();
- 将 Json 对象设置为一个空的 object。
#代码示例
Json r;
r.set_array(); // r -> []
r.push_back(1); // r -> [1]
r.set_object(); // r -> {}
r.set_null(); // r -> null
#———————————
#Json::operator[]
Value operator[](int i) const;
Value operator[](uint32 i) const;
Value operator[](const char* key) const
-
重载
operator[]
,获取 Json 对象中的元素,返回一个json::Value
对象。 -
前两个版本适用于 array 类型,参数 i 是元素在 array 中的偏移位置,i 必须在 array 大小范围内。
-
第 3 个版本适用于 object 类型,若 key 对应的元素不存在,返回 null。
-
示例
Json r;
r.add_member("x", 1);
auto a = r.add_array("a");
a.push_back(1, 2, 3); // r -> {"x":1, "a":[1,2,3]}
auto x = r["x"];
x.get_int(); // 1
a = r["a"];
a.array_size(); // 3
a[0].get_int(); // 1
a[1].get_int(); // 2
#Json::has_member
bool has_member(const char* key) const;
-
判断 Json 对象中是否存在 key 对应的元素。
-
调用此方法的 Json 对象必须是 object 或 null。
-
示例
Json r;
r.add_member("a", 1);
r.has_member("a"); // true
r.has_member("x"); // false
#Json::size
uint32 size() const;
-
若 Json 是 object 或 array 类型,此方法返回元素个数。
-
若 Json 是 string 类型,此方法返回字符串长度。
-
所有其他类型,此方法返回 0。
-
示例
Json r;
r.add_member("x", 1);
auto a = r.add_array("a");
a.push_back(1, 2, 3); // r -> {"x":1, "a":[1,2,3]}
r.size(); // 2
r["x"].size(); // 0
r["a"].size(); // 3
#Json::string_size
uint32 string_size() const;
- 返回 string 类型的长度,若调用此方法的 Json 对象不是 string 类型,返回 0。
#Json::array_size
uint32 array_size() const;
- 返回 array 类型的元素个数,若调用此方法的 Json 对象不是 array 类型,返回 0。
#Json::object_size
uint32 object_size() const;
- 返回 object 类型的元素个数,若调用此方法的 Json 对象不是 object 类型,返回 0。
#———————————
#Json::begin
iterator begin() const;
- 返回指向 Json 对象的 beginning iterator。
- 调用此方法的 Json 对象必须是 array, object 或 null。
- 当 Json 对象为空时,此方法返回值等于
Json::end()
。
#Json::end
const iterator::End& end() const;
- 返回一个假的 end iterator。
- 返回值实际上并不是一个 iterator 对象,但 iterator 可以与它比较,若 iterator 与
Json::end()
相等,表示没有更多的元素了。
#Json::iterator
#iterator::operator==
bool operator==(const End&) const;
- 判断 iterator 是否等于
End
,End 是一个假的 end iterator。
#iterator::operator!=
bool operator!=(const End&) const;
- 判断 iterator 是否不等于
End
,End 是一个假的 end iterator。
#iterator::operator++
iterator& operator++();
- 重载前缀
++
操作,不支持后缀++
操作。
#iterator::operator*
Value operator*() const;
- 重载
operator*
,此方法仅适用于 array 类型的 iterator。 - Json 为 array 时,iterator 指向 array 中的元素。此方法返回一个 json::Value 对象,表示 iterator 指向的元素。
#iterator::key
const char* key();
- 此方法仅适用于 object 类型的 iterator。
- Json 为 object 时,iterator 指向 object 中的 key-value 键值对,此方法返回该键值对中的 key。
#iterator::value
Value value();
- 此方法仅适用于 object 类型的 iterator。
- Json 为 object 时,iterator 指向 object 中的 key-value 键值对,此方法返回该键值对中的 value,即一个 json::Value 对象。
#遍历 array 或 object
co/json 支持用 iterator 遍历 array 或 object 类型的 Json 对象。
// {"i":7, "s":"xx", "a":[123, true, "nice"]}
Json r;
r.add_member("i", 7);
r.add_member("s", "xx");
auto a = r.add_array("a");
a.push_back(123, true, "nice");
// object
for (auto it = r.begin(); it != r.end(); ++it) {
LOG << it.key() << ": " << it.value();
}
// array
a = r["a"];
for (auto it = a.begin(); it != a.end(); ++it) {
LOG << (*it);
}
#json::Value
json::Value
的构造函数是私有的,用户不能直接创建 json::Value 对象。
json::Value 一般用作中间临时对象,它支持 Json 类中除 parse_from() 外的所有方法,其用法也完全一样,因此这里就不再赘述了。另外,它还支持一些 Json 类不支持的 operator=
赋值操作,用于对 Json 类中的元素赋值。
#json::Value::operator=
void operator=(bool x);
void operator=(int64 x);
void operator=(int32 x);
void operator=(uint32 x);
void operator=(uint64 x);
void operator=(double x);
void operator=(const char* x);
void operator=(const fastring& x);
void operator=(const std::string& x);
-
赋值操作,将 json::Value 的值设置为参数 x 指定的值,json::Value 的类型也会变成相应的类型。
-
第 1 个版本用 bool 类型的值赋值。
-
第 2-5 个版本用整数类型的值赋值。
-
第 6 个版本用 double 类型的值赋值。
-
第 7-9 个版本用字符串类型赋值。
-
示例
Json r;
r.add_member("x", 1);
auto a = r["x"];
a = 3; // r -> {"x": 3}
a = false; // r -> {"x": false}
a = "nice"; // r -> {"x": "nice"}
r["x"] = 3.3; // r -> {"x": 3.3}
#性能优化建议
有些用户喜欢用下面的方式添加元素:
Json r;
r["a"] = 1;
r["s"] = "hello world";
上面的操作虽然可行,但是效率并不高。operator[]
操作会先查找 key,找到了就更新值,没找到就插入新的元素。一般建议用 add_member() 方法取而代之:
Json r;
r.add_member("a", 1);
r.add_member("s", "hello world");
object 类型内部实际上是以数组的形式存储的,operator[]
会与数组中的 key 一一比较,可能较慢。在特别注重性能的场合,建议将 operator[] 的结果缓存起来,不要对同一个 key 多次调用 operator[] 操作。
Json r;
r.add_member("a", 1);
auto a = r["a"];
if (a.is_int()) LOG << a.get_int();