blob: e95de2ba299433a8ef1c234b0d1203547e489cf8 [file] [log] [blame]
/*
* 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