| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 |
| * |
| * https://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 avro_NodeConcepts_hh__ |
| #define avro_NodeConcepts_hh__ |
| |
| #include "Config.hh" |
| |
| #include <vector> |
| #include <map> |
| #include "Exception.hh" |
| |
| namespace avro { |
| |
| |
| /// |
| /// The concept classes are used to simplify NodeImpl. Since different types |
| /// of avro types carry different attributes, such as names, or field names for |
| /// record members. Using the concept class of NoAttribute vs Attribute, the |
| /// NodeImpl object can enable/disable the attribute, but the code is the same |
| /// in either case. |
| /// |
| /// Furthermore, attributes may have different types, for example, most |
| /// attributes are strings, but fixed types have a size attribute, which is |
| /// integer. |
| /// |
| /// Since compound types are composed of other types, the leaf attribute |
| /// concepts extend a NodeImpl to include leaf nodes, and attributes for leaf |
| /// nodes, which are used to build parse trees. |
| /// |
| /// |
| |
| namespace concepts { |
| |
| template <typename Attribute> |
| struct NoAttribute |
| { |
| static const bool hasAttribute = false; |
| |
| size_t size() const { |
| return 0; |
| } |
| |
| void add( const Attribute &attr) { |
| // There must be an add function for the generic NodeImpl, but the |
| // Node APIs ensure that it is never called, the throw here is |
| // just in case |
| throw Exception("This type does not have attribute"); |
| } |
| |
| const Attribute &get(size_t index = 0) const { |
| // There must be an get function for the generic NodeImpl, but the |
| // Node APIs ensure that it is never called, the throw here is |
| // just in case |
| throw Exception("This type does not have attribute"); |
| // even though this code is unreachable the compiler requires it |
| static const Attribute empty = Attribute(); |
| return empty; |
| } |
| |
| Attribute &get(size_t index = 0) { |
| // There must be an get function for the generic NodeImpl, but the |
| // Node APIs ensure that it is never called, the throw here is |
| // just in case |
| throw Exception("This type does not have attribute"); |
| } |
| |
| }; |
| |
| template<typename Attribute> |
| struct SingleAttribute |
| { |
| static const bool hasAttribute = true; |
| |
| SingleAttribute() : attr_() |
| { } |
| |
| SingleAttribute(const Attribute& a) : attr_(a) { } |
| // copy constructing from another single attribute is allowed |
| SingleAttribute(const SingleAttribute<Attribute> &rhs) : |
| attr_(rhs.attr_) |
| { } |
| |
| // copy constructing from a no attribute is allowed |
| SingleAttribute(const NoAttribute<Attribute> &rhs) : |
| attr_() |
| { } |
| |
| size_t size() const { |
| return 1; |
| } |
| |
| void add(const Attribute &attr) { |
| attr_ = attr; |
| } |
| |
| const Attribute &get(size_t index = 0) const { |
| if (index != 0) { |
| throw Exception("SingleAttribute has only 1 value"); |
| } |
| return attr_; |
| } |
| |
| Attribute &get(size_t index = 0) { |
| if (index != 0) { |
| throw Exception("SingleAttribute has only 1 value"); |
| } |
| return attr_; |
| } |
| |
| private: |
| template<typename T> friend struct MultiAttribute; |
| Attribute attr_; |
| }; |
| |
| template<typename Attribute> |
| struct MultiAttribute |
| { |
| static const bool hasAttribute = true; |
| |
| MultiAttribute() |
| { } |
| |
| // copy constructing from another single attribute is allowed, it |
| // pushes the attribute |
| MultiAttribute(const SingleAttribute<Attribute> &rhs) |
| { |
| // since map is the only type that does this we know it's |
| // final size will be two, so reserve |
| attrs_.reserve(2); |
| attrs_.push_back(rhs.attr_); |
| } |
| |
| MultiAttribute(const MultiAttribute<Attribute> &rhs) : |
| attrs_(rhs.attrs_) |
| { } |
| |
| MultiAttribute(const NoAttribute<Attribute> &rhs) |
| {} |
| |
| size_t size() const { |
| return attrs_.size(); |
| } |
| |
| void add(const Attribute &attr) { |
| attrs_.push_back(attr); |
| } |
| |
| const Attribute &get(size_t index = 0) const { |
| return attrs_.at(index); |
| } |
| |
| Attribute &get(size_t index) { |
| return attrs_.at(index); |
| } |
| |
| private: |
| |
| std::vector<Attribute> attrs_; |
| }; |
| |
| |
| template<typename T> |
| struct NameIndexConcept { |
| |
| bool lookup(const std::string &name, size_t &index) const { |
| throw Exception("Name index does not exist"); |
| return 0; |
| } |
| |
| bool add(const::std::string &name, size_t index) { |
| throw Exception("Name index does not exist"); |
| return false; |
| } |
| }; |
| |
| template<> |
| struct NameIndexConcept < MultiAttribute<std::string> > |
| { |
| typedef std::map<std::string, size_t> IndexMap; |
| |
| bool lookup(const std::string &name, size_t &index) const { |
| IndexMap::const_iterator iter = map_.find(name); |
| if(iter == map_.end()) { |
| return false; |
| } |
| index = iter->second; |
| return true; |
| } |
| |
| bool add(const::std::string &name, size_t index) { |
| bool added = false; |
| IndexMap::iterator lb = map_.lower_bound(name); |
| if(lb == map_.end() || map_.key_comp()(name, lb->first)) { |
| map_.insert(lb, IndexMap::value_type(name, index)); |
| added = true; |
| } |
| return added; |
| } |
| |
| private: |
| |
| IndexMap map_; |
| }; |
| |
| } // namespace concepts |
| } // namespace avro |
| |
| #endif |