blob: f6ec13428a25a6827f22b7eeb689976930463340 [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
*
* 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 avro_Generic_hh__
#define avro_Generic_hh__
#include <vector>
#include <map>
#include <string>
#include <boost/any.hpp>
#include <boost/utility.hpp>
#include "Node.hh"
#include "Types.hh"
#include "Encoder.hh"
#include "Decoder.hh"
#include "ValidSchema.hh"
namespace avro {
class GenericDatum {
Type type_;
boost::any value_;
GenericDatum(Type t) : type_(t) { }
template <typename T>
GenericDatum(Type t, const T& v) : type_(t), value_(v) { }
public:
Type type() const {
return type_;
}
template<typename T>
const T& value() const {
return *boost::any_cast<T>(&value_);
}
template<typename T>
T& value() {
return *boost::any_cast<T>(&value_);
}
/// Makes a new AVRO_NULL datum.
GenericDatum() : type_(AVRO_NULL) { }
/// Makes a new AVRO_BOOL datum whose value is of type bool.
GenericDatum(bool v) : type_(AVRO_BOOL), value_(v) { }
/// Makes a new AVRO_INT datum whose value is of type int32_t.
GenericDatum(int32_t v) : type_(AVRO_INT), value_(v) { }
/// Makes a new AVRO_LONG datum whose value is of type int64_t.
GenericDatum(int64_t v) : type_(AVRO_LONG), value_(v) { }
/// Makes a new AVRO_FLOAT datum whose value is of type float.
GenericDatum(float v) : type_(AVRO_FLOAT), value_(v) { }
/// Makes a new AVRO_DOUBLE datum whose value is of type double.
GenericDatum(double v) : type_(AVRO_DOUBLE), value_(v) { }
/// Makes a new AVRO_STRING datum whose value is of type std::string.
GenericDatum(const std::string& v) : type_(AVRO_STRING), value_(v) { }
/// Makes a new AVRO_BYTES datum whose value is of type
/// std::vector<uint8_t>.
GenericDatum(const std::vector<uint8_t>& v) :
type_(AVRO_BYTES), value_(v) { }
GenericDatum(const NodePtr& schema);
};
class GenericContainer {
const NodePtr schema_;
protected:
GenericContainer(const NodePtr& s) : schema_(s) { }
static void assertSameType(const GenericDatum& v, const NodePtr& n);
static void assertType(const NodePtr& schema, Type type,
const char* message);
public:
/// Returns the schema for this object
const NodePtr& schema() const {
return schema_;
}
};
class GenericRecord : public GenericContainer {
std::vector<GenericDatum> fields_;
public:
GenericRecord(const NodePtr& schema);
size_t fieldCount() const {
return fields_.size();
}
const GenericDatum& fieldAt(size_t pos) const {
return fields_[pos];
}
GenericDatum& fieldAt(size_t pos) {
return fields_[pos];
}
void setFieldAt(size_t pos, const GenericDatum& v) {
assertSameType(v, schema()->leafAt(pos));
fields_[pos] = v;
}
};
class GenericArray : public GenericContainer {
public:
typedef std::vector<GenericDatum> Value;
GenericArray(const NodePtr& schema) : GenericContainer(schema) {
if (schema->type() != AVRO_ARRAY) {
throw Exception("Schema is not an array");
}
}
const Value& value() const {
return value_;
}
Value& value() {
return value_;
}
private:
Value value_;
};
class GenericMap : public GenericContainer {
public:
typedef std::vector<std::pair<std::string, GenericDatum> > Value;
GenericMap(const NodePtr& schema) : GenericContainer(schema) {
assertType(schema, AVRO_MAP, "Schema is not a map");
}
const Value& value() const {
return value_;
}
Value& value() {
return value_;
}
private:
Value value_;
};
class GenericEnum : public GenericContainer {
size_t value_;
public:
GenericEnum(const NodePtr& schema) : GenericContainer(schema), value_(0) {
}
const std::string& symbol(size_t n) {
if (n < schema()->names()) {
return schema()->nameAt(n);
}
throw Exception("Not as many symbols");
}
size_t index(const std::string& symbol) const {
size_t result;
if (schema()->nameIndex(symbol, result)) {
return result;
}
throw Exception("No such symbol");
}
size_t set(const std::string& symbol) {
return value_ = index(symbol);
}
void set(size_t n) {
if (n < schema()->names()) {
value_ = n;
return;
}
throw Exception("Not as many symbols");
}
size_t value() const {
return value_;
}
const std::string& symbol() const {
return schema()->nameAt(value_);
}
};
class GenericFixed : public GenericContainer {
std::vector<uint8_t> value_;
public:
GenericFixed(const NodePtr& schema) : GenericContainer(schema) {
value_.resize(schema->fixedSize());
}
const std::vector<uint8_t>& value() const {
return value_;
}
std::vector<uint8_t>& value() {
return value_;
}
};
class GenericReader : boost::noncopyable {
const ValidSchema schema_;
const bool isResolving_;
const DecoderPtr decoder_;
static void read(GenericDatum& datum, const NodePtr& n, Decoder& d,
bool isResolving);
public:
GenericReader(const ValidSchema& s, const DecoderPtr& decoder);
GenericReader(const ValidSchema& writerSchema,
const ValidSchema& readerSchema, const DecoderPtr& decoder);
void read(GenericDatum& datum) const;
/**
* Reads a generic datum from the stream, using the given schema.
*/
static void read(Decoder& d, GenericDatum& g, const ValidSchema& s);
};
class GenericWriter : boost::noncopyable {
const ValidSchema schema_;
const EncoderPtr encoder_;
static void write(const GenericDatum& datum, const NodePtr& n, Encoder& e);
public:
GenericWriter(const ValidSchema& s, const EncoderPtr& encoder);
void write(const GenericDatum& datum) const;
/**
* Writes a generic datum on to the stream, using the given schema.
*/
static void write(Encoder& e, const GenericDatum& g, const ValidSchema& s);
};
template <typename T> struct codec_traits;
template <> struct codec_traits<std::pair<ValidSchema, GenericDatum> > {
static void encode(Encoder& e,
const std::pair<ValidSchema, GenericDatum>& p) {
GenericWriter::write(e, p.second, p.first);
}
static void decode(Decoder& d, std::pair<ValidSchema, GenericDatum>& p) {
GenericReader::read(d, p.second, p.first);
}
};
} // namespace avro
#endif