Avro C++
GenericDatum.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_GenericDatum_hh__
00020 #define avro_GenericDatum_hh__
00021 
00022 #include <stdint.h>
00023 #include <vector>
00024 #include <map>
00025 #include <string>
00026 
00027 #include <boost/any.hpp>
00028 
00029 #include "Node.hh"
00030 #include "ValidSchema.hh"
00031 
00032 namespace avro {
00055 class AVRO_DECL GenericDatum {
00056     Type type_;
00057     boost::any value_;
00058 
00059     GenericDatum(Type t) : type_(t) { }
00060 
00061     template <typename T>
00062     GenericDatum(Type t, const T& v) : type_(t), value_(v) { }
00063 
00064     void init(const NodePtr& schema);
00065 public:
00069     Type type() const {
00070         return type_;
00071     }
00072 
00078     template<typename T> const T& value() const {
00079         return *boost::any_cast<T>(&value_);
00080     }
00081 
00091     template<typename T> T& value() {
00092         return *boost::any_cast<T>(&value_);
00093     }
00094 
00098     bool isUnion() const { return type_ == AVRO_UNION; }
00099 
00104     size_t unionBranch() const;
00105 
00110     void selectBranch(size_t branch);
00111 
00113     GenericDatum() : type_(AVRO_NULL) { }
00114 
00116     GenericDatum(bool v) : type_(AVRO_BOOL), value_(v) { }
00117 
00119     GenericDatum(int32_t v) : type_(AVRO_INT), value_(v) { }
00120 
00122     GenericDatum(int64_t v) : type_(AVRO_LONG), value_(v) { }
00123 
00125     GenericDatum(float v) : type_(AVRO_FLOAT), value_(v) { }
00126 
00128     GenericDatum(double v) : type_(AVRO_DOUBLE), value_(v) { }
00129 
00131     GenericDatum(const std::string& v) : type_(AVRO_STRING), value_(v) { }
00132 
00135     GenericDatum(const std::vector<uint8_t>& v) :
00136         type_(AVRO_BYTES), value_(v) { }
00137 
00144     GenericDatum(const NodePtr& schema);
00145 
00152     template<typename T>
00153     GenericDatum(const NodePtr& schema, const T& v) :
00154         type_(schema->type()) {
00155         init(schema);
00156         value<T>() = v;
00157     }
00158 
00165     GenericDatum(const ValidSchema& schema);
00166 };
00167 
00171 class AVRO_DECL GenericContainer {
00172     NodePtr schema_;
00173     static void assertType(const NodePtr& schema, Type type);
00174 protected:
00178     GenericContainer(Type type, const NodePtr& s) : schema_(s) {
00179         assertType(s, type);
00180     }
00181 
00182 public:
00184     const NodePtr& schema() const {
00185         return schema_;
00186     }
00187 };
00188 
00192 class AVRO_DECL GenericUnion : public GenericContainer {
00193     size_t curBranch_;
00194     GenericDatum datum_;
00195 
00196 public:
00202     GenericUnion(const NodePtr& schema) :
00203         GenericContainer(AVRO_UNION, schema), curBranch_(schema->leaves()) {
00204     }
00205 
00209     size_t currentBranch() const { return curBranch_; }
00210 
00215     void selectBranch(size_t branch) {
00216         if (curBranch_ != branch) {
00217             datum_ = GenericDatum(schema()->leafAt(branch));
00218             curBranch_ = branch;
00219         }
00220     }
00221 
00226     GenericDatum& datum() {
00227         return datum_;
00228     }
00229 
00234     const GenericDatum& datum() const {
00235         return datum_;
00236     }
00237 };
00238 
00242 class AVRO_DECL GenericRecord : public GenericContainer {
00243     std::vector<GenericDatum> fields_;
00244 public:
00249     GenericRecord(const NodePtr& schema);
00250 
00254     size_t fieldCount() const {
00255         return fields_.size();
00256     }
00257 
00261     size_t fieldIndex(const std::string& name) const { 
00262         size_t index = 0;
00263         if (!schema()->nameIndex(name, index)) {
00264             throw Exception("Invalid field name: " + name);
00265         }
00266         return index;
00267     }
00268 
00273     bool hasField(const std::string& name) const {
00274         size_t index = 0;
00275         return schema()->nameIndex(name, index);
00276     }
00277 
00281     const GenericDatum& field(const std::string& name) const {
00282         return fieldAt(fieldIndex(name));
00283     }
00284 
00289     GenericDatum& field(const std::string& name) {
00290         return fieldAt(fieldIndex(name));
00291     }
00292 
00296     const GenericDatum& fieldAt(size_t pos) const {
00297         return fields_[pos];
00298     }
00299 
00304     GenericDatum& fieldAt(size_t pos) {
00305         return fields_[pos];
00306     }
00307 
00311     void setFieldAt(size_t pos, const GenericDatum& v) {
00312         // assertSameType(v, schema()->leafAt(pos));    
00313         fields_[pos] = v;
00314     }
00315 };
00316 
00320 class AVRO_DECL GenericArray : public GenericContainer {
00321 public:
00325     typedef std::vector<GenericDatum> Value;
00326 
00331     GenericArray(const NodePtr& schema) : GenericContainer(AVRO_ARRAY, schema) {
00332     }
00333 
00337     const Value& value() const {
00338         return value_;
00339     }
00340 
00344     Value& value() {
00345         return value_;
00346     }
00347 private:
00348     Value value_;
00349 };
00350 
00354 class AVRO_DECL GenericMap : public GenericContainer {
00355 public:
00359     typedef std::vector<std::pair<std::string, GenericDatum> > Value;
00360 
00365     GenericMap(const NodePtr& schema) : GenericContainer(AVRO_MAP, schema) {
00366     }
00367 
00371     const Value& value() const {
00372         return value_;
00373     }
00374 
00378     Value& value() {
00379         return value_;
00380     }
00381 private:
00382     Value value_;
00383 };
00384 
00388 class AVRO_DECL GenericEnum : public GenericContainer {
00389     size_t value_;
00390 
00391     static size_t index(const NodePtr& schema, const std::string& symbol) {
00392         size_t result;
00393         if (schema->nameIndex(symbol, result)) {
00394             return result;
00395         }
00396         throw Exception("No such symbol");
00397     }
00398 
00399 public:
00404     GenericEnum(const NodePtr& schema) :
00405         GenericContainer(AVRO_ENUM, schema), value_(0) {
00406     }
00407 
00408     GenericEnum(const NodePtr& schema, const std::string& symbol) :
00409         GenericContainer(AVRO_ENUM, schema), value_(index(schema, symbol)) {
00410     }
00411 
00416     const std::string& symbol(size_t n) {
00417         if (n < schema()->names()) {
00418             return schema()->nameAt(n);
00419         }
00420         throw Exception("Not as many symbols");
00421     }
00422 
00427     size_t index(const std::string& symbol) const {
00428         return index(schema(), symbol);
00429     }
00430 
00434     size_t set(const std::string& symbol) {
00435         return value_ = index(symbol);
00436     }
00437 
00441     void set(size_t n) {
00442         if (n < schema()->names()) {
00443             value_ = n;
00444             return;
00445         }
00446         throw Exception("Not as many symbols");
00447     }
00448 
00452     size_t value() const {
00453         return value_;
00454     }
00455 
00459     const std::string& symbol() const {
00460         return schema()->nameAt(value_);
00461     }
00462 };
00463 
00467 class AVRO_DECL GenericFixed : public GenericContainer {
00468     std::vector<uint8_t> value_;
00469 public:
00474     GenericFixed(const NodePtr& schema) : GenericContainer(AVRO_FIXED, schema) {
00475         value_.resize(schema->fixedSize());
00476     }
00477 
00478     GenericFixed(const NodePtr& schema, const std::vector<uint8_t>& v) :
00479         GenericContainer(AVRO_FIXED, schema), value_(v) { }
00480 
00484     const std::vector<uint8_t>& value() const {
00485         return value_;
00486     }
00487 
00491     std::vector<uint8_t>& value() {
00492         return value_;
00493     }
00494 };
00495 
00496 inline size_t GenericDatum::unionBranch() const {
00497     return boost::any_cast<GenericUnion>(&value_)->currentBranch();
00498 }
00499 
00500 inline void GenericDatum::selectBranch(size_t branch) {
00501     boost::any_cast<GenericUnion>(&value_)->selectBranch(branch);
00502 }
00503 
00504 }   // namespace avro
00505 #endif // avro_GenericDatum_hh__