/* * 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 #include #include #include #include #include //#include #ifdef XTOSTRUCT_SUPPORT_CHAR_ARRAY #include #endif #include "util.h" #include "traits.h" namespace x2struct { /* DOC need implement bool has(const std::string) const std::string& type() */ template class XReader { protected: typedef DOC doc_type; typedef XReader 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 bool convert(const char*key, std::vector &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 bool convert(const char*key, std::list &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 bool convert(const char*key, std::set &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 bool convert(const char*key, std::map &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 bool convert(const char*key, std::map &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(key); } else { // libconfig/xml不支持数字作为key,所以用x开头,比如x11 _k = Util::tonum(key.substr(1)); } val[_k] = _t; } return true; } #ifdef X_SUPPORT_C0X // unordered_map template bool convert(const char*key, std::unordered_map &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 bool convert(const char*key, std::shared_ptr& val) { if (NULL == val.get()) { val.reset(new TYPE); } return this->convert(key, *val); } // class/struct that not defined macro XTOSTRUCT template ::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 ::value, int>::type = 0> bool convert(const char*key, TYPE& val) { #else // add x_for_class to avoid enum hit this function template 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 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(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(this)->type(), md); } std::string path() { std::vector nodes; const doc_type* tmp = static_cast(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(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