3

动态数据类型 folly::dynamic

 3 years ago
source link: https://zhiqiang.org/coding/folly-dynamic.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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, size, resize等都是支持的。

字典的遍历则和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)等也都是支持的。

如果要判断 key 存在,可以用:obj.find(key) != obj.items().end()。还有个方法是auto pos = obj.get_ptr(key),然后判断pos != nullptr,可以通过pos->getString()来获取到值。

1.5. 计算

这个类的强大之处在于,它和 Python 一样,支持dynamic对象之间以及和普通类型之间的计算:

dynamic b1 = s < "xyz";
dynamic s1 = s + "abc";
dynamic i1 = i - 1;
dynamic is = s + i; // 抛出异常。

当运算不满足类型要求时,计算将抛出异常。这也和 Python 一致。

1.6. JSON 导入和导出

folly::dynamic的强大之处在于它支持 JSON 的导入和导出:

folly::dynamic arr = folly::dynamic::array(1, "123", true);
std::string json = toJson(arr);
folly::dynamic imported = parseJson(json); // will equal arsss1

1.7. 注意事项

  1. obj = obj[key]会导致obj == nullptr。这涉及到 C++的内存管理。可以用:folly::dynamic tmp = obj[key]; obj = key;来代替。

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的基类。这个基类提供一个功能,如果实现了一些运算符,那么基类将自动扩展相关的运算符。比如如果定义了==符号,那么!=就被自动扩展。这样可以少写很多代码,又能最大程度地覆盖到所有运算符。

初始化的内容很多,原因是除了基本类型,还需要支持objectarray。里面还是有很多弯弯绕绕的东西,比如下面的初始化:

ObjectMaker() : val_(dynamic::object) {}  // dynamic val_;

ObjectMaker dynamic::object() {
  return ObjectMaker();
}

咋一看,还以为出现循环调用,但其实第一行的val_(dynamic::object)调用的是下面这个:

inline dynamic::dynamic(ObjectMaker (*)()) : type_(OBJECT) {
  new (getAddress<ObjectImpl>()) ObjectImpl();
}

未完待续。。。

Q. E. D.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK