Avro C++
NodeConcepts.hh
00001 /*
00002  * Licensed to the Apache Software Foundation (ASF) under one
00003  * or more contributor license agreements.  See the NOTICE file
00004  * distributed with this work for additional information
00005  * regarding copyright ownership.  The ASF licenses this file
00006  * to you under the Apache License, Version 2.0 (the
00007  * "License"); you may not use this file except in compliance
00008  * with the License.  You may obtain a copy of the License at
00009  *
00010  *     http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 
00019 #ifndef avro_NodeConcepts_hh__
00020 #define avro_NodeConcepts_hh__
00021 
00022 #include "Config.hh"
00023 
00024 #include <vector>
00025 #include <map>
00026 #include "Exception.hh"
00027 
00028 namespace avro {
00029 
00030 
00047 
00048 namespace concepts {
00049 
00050 template <typename Attribute>
00051 struct NoAttribute
00052 {
00053     static const bool hasAttribute = false;
00054 
00055     size_t size() const {
00056         return 0;
00057     }
00058 
00059     void add( const Attribute &attr) {
00060         // There must be an add function for the generic NodeImpl, but the
00061         // Node APIs ensure that it is never called, the throw here is
00062         // just in case
00063         throw Exception("This type does not have attribute");
00064     }
00065 
00066     const Attribute &get(size_t index = 0) const {
00067         // There must be an get function for the generic NodeImpl, but the
00068         // Node APIs ensure that it is never called, the throw here is
00069         // just in case
00070         throw Exception("This type does not have attribute");
00071         // even though this code is unreachable the compiler requires it
00072         static const Attribute empty = Attribute();
00073         return empty;
00074     }
00075 
00076     Attribute &get(size_t index = 0) {
00077         // There must be an get function for the generic NodeImpl, but the
00078         // Node APIs ensure that it is never called, the throw here is
00079         // just in case
00080         throw Exception("This type does not have attribute");
00081     }
00082 
00083 };
00084 
00085 template<typename Attribute>
00086 struct SingleAttribute
00087 {
00088     static const bool hasAttribute = true;
00089 
00090     SingleAttribute() : attr_()
00091     { }
00092 
00093     SingleAttribute(const Attribute& a) : attr_(a) { }
00094     // copy constructing from another single attribute is allowed
00095     SingleAttribute(const SingleAttribute<Attribute> &rhs) : 
00096         attr_(rhs.attr_)
00097     { }
00098 
00099     // copy constructing from a no attribute is allowed
00100     SingleAttribute(const NoAttribute<Attribute> &rhs) : 
00101         attr_()
00102     { }
00103 
00104     size_t size() const {
00105         return 1;
00106     }
00107 
00108     void add(const Attribute &attr) {
00109         attr_ = attr;
00110     }
00111 
00112     const Attribute &get(size_t index = 0) const {
00113         if (index != 0) {
00114             throw Exception("SingleAttribute has only 1 value");
00115         }
00116         return attr_;
00117     }
00118 
00119     Attribute &get(size_t index = 0) {
00120         if (index != 0) {
00121             throw Exception("SingleAttribute has only 1 value");
00122         }
00123         return attr_;
00124     }
00125 
00126 private:
00127     template<typename T> friend struct MultiAttribute;
00128     Attribute attr_;
00129 };
00130 
00131 template<typename Attribute>
00132 struct MultiAttribute
00133 {
00134     static const bool hasAttribute = true;
00135 
00136     MultiAttribute() 
00137     { }
00138 
00139     // copy constructing from another single attribute is allowed, it
00140     // pushes the attribute
00141     MultiAttribute(const SingleAttribute<Attribute> &rhs) 
00142     { 
00143         // since map is the only type that does this we know it's
00144         // final size will be two, so reserve 
00145         attrs_.reserve(2);
00146         attrs_.push_back(rhs.attr_);
00147     }
00148 
00149     MultiAttribute(const MultiAttribute<Attribute> &rhs)  :
00150         attrs_(rhs.attrs_)
00151     { }
00152 
00153     MultiAttribute(const NoAttribute<Attribute> &rhs)
00154     {}
00155 
00156     size_t size() const {
00157         return attrs_.size();
00158     }
00159 
00160     void add(const Attribute &attr) {
00161         attrs_.push_back(attr); 
00162     }
00163 
00164     const Attribute &get(size_t index = 0) const {
00165         return attrs_.at(index);
00166     }
00167 
00168     Attribute &get(size_t index) {
00169         return attrs_.at(index);
00170     }
00171 
00172   private:
00173 
00174     std::vector<Attribute> attrs_;
00175 };
00176 
00177 
00178 template<typename T>
00179 struct NameIndexConcept {
00180 
00181     bool lookup(const std::string &name, size_t &index) const {
00182         throw Exception("Name index does not exist");
00183         return 0;
00184     }
00185 
00186     bool add(const::std::string &name, size_t index) {
00187         throw Exception("Name index does not exist");
00188         return false;
00189     }
00190 };
00191 
00192 template<>
00193 struct NameIndexConcept < MultiAttribute<std::string> > 
00194 {
00195     typedef std::map<std::string, size_t> IndexMap;
00196 
00197     bool lookup(const std::string &name, size_t &index) const {
00198         IndexMap::const_iterator iter = map_.find(name); 
00199         if(iter == map_.end()) {
00200             return false;
00201         }
00202         index = iter->second;
00203         return true;
00204     }
00205 
00206     bool add(const::std::string &name, size_t index) {
00207         bool added = false;
00208         IndexMap::iterator lb = map_.lower_bound(name); 
00209         if(lb == map_.end() || map_.key_comp()(name, lb->first)) {
00210             map_.insert(lb, IndexMap::value_type(name, index));
00211             added = true;
00212         }
00213         return added;
00214     }
00215 
00216   private:
00217 
00218     IndexMap map_;
00219 };
00220 
00221 } // namespace concepts
00222 } // namespace avro
00223 
00224 #endif