eis/inc/x2struct/xreader.h

364 lines
9.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) 2019 YY Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __X_READER_H
#define __X_READER_H
#include "xstdint.h"
#include <string>
#include <map>
#include <vector>
#include <list>
#include <set>
#include <stdexcept>
//#include <iostream>
#ifdef XTOSTRUCT_SUPPORT_CHAR_ARRAY
#include <string.h>
#endif
#include "util.h"
#include "traits.h"
namespace x2struct {
/*
DOC need implement
bool has(const std::string)
const std::string& type()
*/
template<typename DOC>
class XReader {
protected:
typedef DOC doc_type;
typedef XReader<DOC> xdoc_type;
public:
// only c++0x support reference initialize, so use pointer
XReader(const doc_type *parent, const char* key):_parent(parent), _key(key), _index(-1), _set_has(false){}
XReader(const doc_type *parent, size_t index):_parent(parent), _key(0), _index(int(index)), _set_has(false){}
~XReader(){}
public:
template <typename TYPE>
bool convert(const char*key, std::vector<TYPE> &val) {
doc_type tmp;
doc_type *obj = get_obj(key, &tmp);
if (NULL == obj) {
return false;
}
size_t s = obj->size(); // [implement] size_t size(bool to_vec=true)
val.resize(s);
for (size_t i=0; i<s; ++i) {
(*obj)[i].convert(NULL, val[i]); // [implement] doc_type operator[](size_t)
}
return true;
}
template <typename TYPE>
bool convert(const char*key, std::list<TYPE> &val) {
doc_type tmp;
doc_type *obj = get_obj(key, &tmp);
if (NULL == obj) {
return false;
}
size_t s = obj->size();
for (size_t i=0; i<s; ++i) {
TYPE _t;
(*obj)[i].convert(NULL, _t);
val.push_back(_t);
}
return true;
}
template <typename TYPE>
bool convert(const char*key, std::set<TYPE> &val) {
doc_type tmp;
doc_type *obj = get_obj(key, &tmp);
if (NULL == obj) {
return false;
}
size_t s = obj->size();
for (size_t i=0; i<s; ++i) {
TYPE _t;
(*obj)[i].convert(NULL, _t);
val.insert(_t);
}
return true;
}
template <typename TYPE>
bool convert(const char*key, std::map<std::string,TYPE> &val) {
doc_type tmp;
doc_type *obj = get_obj(key, &tmp);
if (NULL == obj) {
return false;
}
for (doc_type d=obj->begin(); d; d=d.next()) { // [implement] doc_type begin(); doc_type next(); operator bool() const;
TYPE _t;
d.convert(NULL, _t);
val[d.key()] = _t;
}
return true;
}
template <typename KEYTYPE, typename TYPE>
bool convert(const char*key, std::map<KEYTYPE, TYPE> &val) {
doc_type tmp;
doc_type *obj = get_obj(key, &tmp);
if (NULL == obj) {
return false;
}
for (doc_type d=obj->begin(); d; d=d.next()) {
TYPE _t;
d.convert(NULL, _t);
KEYTYPE _k;
std::string key = d.key();
if (key[0]!='x') {
_k = Util::tonum<KEYTYPE>(key);
} else { // libconfig/xml不支持数字作为key所以用x开头比如x11
_k = Util::tonum<KEYTYPE>(key.substr(1));
}
val[_k] = _t;
}
return true;
}
#ifdef X_SUPPORT_C0X
// unordered_map
template <typename TYPE>
bool convert(const char*key, std::unordered_map<std::string,TYPE> &val) {
doc_type tmp;
doc_type *obj = get_obj(key, &tmp);
if (NULL == obj) {
return false;
}
for (doc_type d=obj->begin(); d; d=d.next()) { // [implement] doc_type begin(); doc_type next(); operator bool() const;
TYPE _t;
d.convert(NULL, _t);
val[d.key()] = _t;
}
return true;
}
// shared_ptr
template <typename TYPE>
bool convert(const char*key, std::shared_ptr<TYPE>& val) {
if (NULL == val.get()) {
val.reset(new TYPE);
}
return this->convert(key, *val);
}
// class/struct that not defined macro XTOSTRUCT
template <typename TYPE, typename std::enable_if<!x_has_x2struct<TYPE>::value, int>::type = 0>
bool convert(const char*key, TYPE& val, x_for_class(TYPE, int) *unused=0) {
(void)unused;
doc_type tmp;
doc_type *obj = get_obj(key, &tmp);
bool ret = false;
do {
if (NULL == obj) {
break;
}
x_str_to_struct(*obj, val);
ret = true;
} while(false);
return ret;
}
// class/struct that defined macro XTOSTRUCT
template <typename TYPE, typename std::enable_if<x_has_x2struct<TYPE>::value, int>::type = 0>
bool convert(const char*key, TYPE& val) {
#else
// add x_for_class to avoid enum hit this function
template <typename TYPE>
bool convert(const char*key, TYPE& val, x_for_class(TYPE, int) *unused=0) {
(void)unused;
#endif
doc_type tmp;
doc_type *obj = get_obj(key, &tmp);
bool ret = false;
do {
if (NULL == obj) {
break;
}
size_t len = obj->size(false);
if (len <= 1) {
val.__x_to_struct(*obj);
ret = true;
} else if (NULL == val.__x_cond.cond) {
break;
} else {
for (size_t i=0; i<len; ++i) {
doc_type sub = (*obj)[i];
if (val.__x_cond.cond(val.__x_cond.parent, (void*)&sub)) {
val.__x_to_struct(sub);
ret = true;
break;
}
}
}
} while(false);
val.__x_cond.set(0, 0);
return ret;
}
// for enum
template <typename TYPE>
bool convert(const char*key, TYPE& val, x_for_enum(TYPE) *p=0) {
(void)p;
return ((doc_type*)(this))->convert(key, *(int*)&val);
}
#ifdef XTOSTRUCT_SUPPORT_CHAR_ARRAY
bool convert(const char*key, char val[]) {
std::string str;
bool ret = ((doc_type*)this)->convert(key, str);
if (ret) {
strncpy(val, str.data(), str.length());
val[str.length()] = '\0';
}
return ret;
}
#endif
std::string attribute(const char* key) {
std::string val;
(static_cast<doc_type*>(this))->convert(key, val);
return val;
}
const std::string key() const {
if (0 != _key) {
return _key;
} else {
return Util::tostr(_index);
}
}
const char* key_char() const {
if (0 != _key) {
return _key;
} else {
return "";
}
}
std::string hasa(const std::string&key, const std::string&alias, bool *md) {
return Util::alias_parse(key, alias, static_cast<doc_type*>(this)->type(), md);
}
std::string path() {
std::vector<std::string> nodes;
const doc_type* tmp = static_cast<doc_type*>(this);
while (tmp) {
std::string k;
k.reserve(32);
if (0 != tmp->_key) {
if (0!=tmp->_parent && 0!=tmp->_parent->_parent) {
k.append(".");
}
k.append(tmp->_key);
} else {
k.append("[").append(Util::tostr(tmp->_index)).append("]");
}
nodes.push_back(k);
tmp = tmp->_parent;
}
std::string p;
p.reserve(64);
for (int i=(int)nodes.size()-1; i>=0; --i) {
p.append(nodes[i]);
}
return p;
}
void md_exception(const std::string&key) {
/*std::string err;
err.reserve(128);
err.append("miss mandatory node ");
std::string p = path();
if (!p.empty()) {
err.append(p).append(".");
}
err.append(key);
throw std::runtime_error(err);*/
read_exception("miss mandatory node", key);
}
void read_exception(const char* what, const std::string&key) {
std::string err;
err.reserve(128);
if (NULL != what) {
err.append(what);
}
err.append("[");
std::string p = path();
if (!p.empty()) {
err.append(p).append(".");
}
err.append(key);
err.append("]");
throw std::runtime_error(err);
}
bool set_has() const {
return _set_has;
}
void set_has(bool set) {
_set_has = set;
}
/*void set_condition(void *parent, cond_f f) {
if (NULL == parent) {
this->_p_cond = NULL;
} else {
this->_cond.parent = parent;
this->_cond.cond = f;
this->_p_cond = &this->_cond;
}
}*/
protected:
doc_type* get_obj(const char *key, doc_type *tmp) {
doc_type *obj = static_cast<doc_type*>(this);
if (NULL != key) {
obj = obj->child(key, tmp); // [implement] doc_type* child(const char*, doc_type*)
}
return obj;
}
const doc_type* _parent;
const char* _key;
int _index;
bool _set_has;
/*
private:
x_condition _cond;
x_condition *_p_cond;*/
};
}
#endif