动态数据类型 folly::dynamic
folly::dynamic
提供类似于C++
的动态类型。和std::any
可以容纳任意类型不一样,folly::dynamic
只支持保存以下几种类型:
enum Type {
NULLT, // nullptr_t
ARRAY, // std::vector<folly::dynamic>
BOOL, // bool
DOUBLE, // double
INT64, // int64_t
OBJECT, // 类似于 std::unordered_map<folly::dynamic, folly::dynamic>
STRING, // std::string
};
因为类型少,基本所有数据都是inline
保存的,这使得它的速度非常快。
1. 使用方法
在https://my.oschina.net/fileoptions/blog/883002基础上整理。
1.1. 初始化
folly::dynamic n = nullptr;
folly::dynamic arr = folly::dynamic::array(n, i, s, true);
folly::dynamic b = true;
folly::dynamic f = 1.2;
folly::dynamic i = 1;
folly::dynamic o = folly::dynamic::object(b, f)(f, arr);
folly::dynamic s = "abc";
1.2. 判断和获取类型
bool isString() const;
bool isObject() const;
bool isBool() const;
bool isNull() const;
bool isArray() const;
bool isDouble() const;
bool isInt() const;
bool isNumber() const; // Returns: isInt() || isDouble().
Type type() const; // return Type
1.3. 获取值
getType
系列函数可以从对象中取出原始数值,若类型不一致将抛出异常:
const std::string& getString() const&;
double getDouble() const&;
int64_t getInt() const&;
bool getBool() const&;
std::string& getString() &;
double& getDouble() &;
int64_t& getInt() &;
bool& getBool() &;
std::string&& getString() &&;
double getDouble() &&;
int64_t getInt() &&;
bool getBool() &&;
asType
系列函数会将试图转换成指定类型,若无法转换,将抛出异常:
std::string asString() const;
double asDouble() const;
int64_t asInt() const;
bool asBool() const;
1.4. 数组和字典遍历
数组的遍历和std::vector
一致,支持iterator
,因此下面都是合法的:
for (auto item : arr) {
// ...
}
通过下标随机访问,比如arr[10]
也是可以的。std::vector
的 API 如push_back
都是支持的。
字典的遍历则和Python
类似,需要通过items()
,keys()
和values()
来确定遍历的具体内容:
for (auto pair : obj.items()) {
// Key is pair.first, value is pair.second
processKey(pair.first);
processValue(pair.second);
}
// 单独遍历key
for (auto key : obj.keys()) {
processKey(key);
}
// 单独遍历value
for (auto value : obj.values()) {
processValue(value);
}
然后也支持obj[key]
访问,std::unordered_map
的 API
如obj.at(key)
,obj.find(key)
等也都是支持的。
1.5. 计算
这个类的强大之处在于,它和 Python 一样,支持dynamic
对象之间以及和普通类型之间的计算:
dynamic b1 = s < "xyz";
dynamic s1 = s + "abc";
dynamic i1 = i - 1;
dynamic is = s + i; // 抛出异常。
当运算不满足类型要求时,计算将抛出异常。这也和 Python 一致。
2. 代码分析
总地来说,folly::dynamic
的实现不算特别难懂。
2.1. 内存结构
内存结构很简单,除了类型,就是共享数据区。
struct dynamic {
Type type_; // enum
union Data {
std::nullptr_t nul;
std::vector<dynamic> array;
bool boolean;
double doubl;
int64_t integer;
std::string string;
aligned_storage_for_t<F14NodeMap<int, int>> objectBuffer;
} u_;
};
唯一可以说的是最后一个aligned_storage_for_t<F14NodeMap<int, int>>
objectBuffer;
,这个目标是保存字典数据。F14NodeMap
是 folly
提供的一个更高效的std::unordered_map
。这里用了F14NodeMap<int,
int>
,而不是F14NodeMap<dynamic, dynamic>
,因为后者还未能定义(?)。
2.2. 基类和初始化
boost::operators<dynamic>
是dynamic
的基类。这个基类提供一个功能,如果实现了一些运算符,那么基类将自动扩展相关的运算符。比如如果定义了==
符号,那么!=
就被自动扩展。这样可以少写很多代码,又能最大程度地覆盖到所有运算符。
初始化的内容很多,原因是除了基本类型,还需要支持object
和array
。里面还是有很多弯弯绕绕的东西,比如下面的初始化:
ObjectMaker() : val_(dynamic::object) {} // dynamic val_;
ObjectMaker dynamic::object() {
return ObjectMaker();
}
咋一看,还以为出现循环调用,但其实第一行的val_(dynamic::object)
调用的是下面这个:
inline dynamic::dynamic(ObjectMaker (*)()) : type_(OBJECT) {
new (getAddress<ObjectImpl>()) ObjectImpl();
}
未完待续。。。
作者暂无likerid, 赞赏暂由本网站代持,当作者有likerid后会全部转账给作者(我们会尽力而为)。Tips: Until now, everytime you want to store your article, we will help you store it in Filecoin network. In the future, you can store it in Filecoin network using your own filecoin.
Support author:
Author's Filecoin address:
Or you can use Likecoin to support author: