Avro C++
Generic.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_Generic_hh__
00020 #define avro_Generic_hh__
00021 
00022 #include <vector>
00023 #include <map>
00024 #include <string>
00025 
00026 #include <boost/any.hpp>
00027 #include <boost/utility.hpp>
00028 
00029 #include "Config.hh"
00030 #include "Node.hh"
00031 #include "Types.hh"
00032 #include "Encoder.hh"
00033 #include "Decoder.hh"
00034 #include "ValidSchema.hh"
00035 
00036 namespace avro {
00059 class AVRO_DECL GenericDatum {
00060     Type type_;
00061     boost::any value_;
00062 
00063     GenericDatum(Type t) : type_(t) { }
00064 
00065     template <typename T>
00066     GenericDatum(Type t, const T& v) : type_(t), value_(v) { }
00067 
00068     void init(const NodePtr& schema);
00069 public:
00073     Type type() const;
00074 
00080     template<typename T> const T& value() const;
00081 
00091     template<typename T> T& value();
00092 
00096     bool isUnion() const { return type_ == AVRO_UNION; }
00097 
00102     size_t unionBranch() const;
00103 
00108     void selectBranch(size_t branch);
00109 
00111     GenericDatum() : type_(AVRO_NULL) { }
00112 
00114     GenericDatum(bool v) : type_(AVRO_BOOL), value_(v) { }
00115 
00117     GenericDatum(int32_t v) : type_(AVRO_INT), value_(v) { }
00118 
00120     GenericDatum(int64_t v) : type_(AVRO_LONG), value_(v) { }
00121 
00123     GenericDatum(float v) : type_(AVRO_FLOAT), value_(v) { }
00124 
00126     GenericDatum(double v) : type_(AVRO_DOUBLE), value_(v) { }
00127 
00129     GenericDatum(const std::string& v) : type_(AVRO_STRING), value_(v) { }
00130 
00133     GenericDatum(const std::vector<uint8_t>& v) :
00134         type_(AVRO_BYTES), value_(v) { }
00135 
00142     GenericDatum(const NodePtr& schema);
00143 
00150     GenericDatum(const ValidSchema& schema);
00151 };
00152 
00156 class AVRO_DECL GenericContainer {
00157     NodePtr schema_;
00158     static void assertType(const NodePtr& schema, Type type);
00159 protected:
00163     GenericContainer(Type type, const NodePtr& s) : schema_(s) {
00164         assertType(s, type);
00165     }
00166 
00167 public:
00169     const NodePtr& schema() const {
00170         return schema_;
00171     }
00172 };
00173 
00177 class AVRO_DECL GenericUnion : public GenericContainer {
00178     size_t curBranch_;
00179     GenericDatum datum_;
00180 
00181 public:
00187     GenericUnion(const NodePtr& schema) :
00188         GenericContainer(AVRO_UNION, schema), curBranch_(schema->leaves()) {
00189     }
00190 
00194     size_t currentBranch() const { return curBranch_; }
00195 
00200     void selectBranch(size_t branch) {
00201         if (curBranch_ != branch) {
00202             datum_ = GenericDatum(schema()->leafAt(branch));
00203             curBranch_ = branch;
00204         }
00205     }
00206 
00210     Type type() const {
00211         return datum_.type();
00212     }
00213 
00217     template<typename T>
00218     const T& value() const {
00219         return datum_.value<T>();
00220     }
00221 
00225     template<typename T>
00226     T& value() {
00227         return datum_.value<T>();
00228     }
00229 
00230 };
00231 
00235 class AVRO_DECL GenericRecord : public GenericContainer {
00236     std::vector<GenericDatum> fields_;
00237 public:
00242     GenericRecord(const NodePtr& schema);
00243 
00247     size_t fieldCount() const {
00248         return fields_.size();
00249     }
00250 
00254     size_t fieldIndex(const std::string& name) const { 
00255         size_t index = 0;
00256         if (!schema()->nameIndex(name, index)) {
00257             throw Exception("Invalid field name: " + name);
00258         }
00259         return index;
00260     }
00261 
00266     bool hasField(const std::string& name) const {
00267         size_t index = 0;
00268         return schema()->nameIndex(name, index);
00269     }
00270 
00274     const GenericDatum& field(const std::string& name) const {
00275         return fieldAt(fieldIndex(name));
00276     }
00277 
00282     GenericDatum& field(const std::string& name) {
00283         return fieldAt(fieldIndex(name));
00284     }
00285 
00289     const GenericDatum& fieldAt(size_t pos) const {
00290         return fields_[pos];
00291     }
00292 
00297     GenericDatum& fieldAt(size_t pos) {
00298         return fields_[pos];
00299     }
00300 
00304     void setField(const std::string& name, const GenericDatum& v) {
00305         // assertSameType(v, schema()->leafAt(pos)); 
00306         return setFieldAt(fieldIndex(name), v);
00307     }
00308 
00312     void setFieldAt(size_t pos, const GenericDatum& v) {
00313         // assertSameType(v, schema()->leafAt(pos));    
00314         fields_[pos] = v;
00315     }
00316 };
00317 
00321 class AVRO_DECL GenericArray : public GenericContainer {
00322 public:
00326     typedef std::vector<GenericDatum> Value;
00327 
00332     GenericArray(const NodePtr& schema) : GenericContainer(AVRO_ARRAY, schema) {
00333     }
00334 
00338     const Value& value() const {
00339         return value_;
00340     }
00341 
00345     Value& value() {
00346         return value_;
00347     }
00348 private:
00349     Value value_;
00350 };
00351 
00355 class AVRO_DECL GenericMap : public GenericContainer {
00356 public:
00360     typedef std::vector<std::pair<std::string, GenericDatum> > Value;
00361 
00366     GenericMap(const NodePtr& schema) : GenericContainer(AVRO_MAP, schema) {
00367     }
00368 
00372     const Value& value() const {
00373         return value_;
00374     }
00375 
00379     Value& value() {
00380         return value_;
00381     }
00382 private:
00383     Value value_;
00384 };
00385 
00389 class AVRO_DECL GenericEnum : public GenericContainer {
00390     size_t value_;
00391 public:
00396     GenericEnum(const NodePtr& schema) :
00397         GenericContainer(AVRO_ENUM, schema), value_(0) {
00398     }
00399 
00404     const std::string& symbol(size_t n) {
00405         if (n < schema()->names()) {
00406             return schema()->nameAt(n);
00407         }
00408         throw Exception("Not as many symbols");
00409     }
00410 
00415     size_t index(const std::string& symbol) const {
00416         size_t result;
00417         if (schema()->nameIndex(symbol, result)) {
00418             return result;
00419         }
00420         throw Exception("No such symbol");
00421     }
00422 
00426     size_t set(const std::string& symbol) {
00427         return value_ = index(symbol);
00428     }
00429 
00433     void set(size_t n) {
00434         if (n < schema()->names()) {
00435             value_ = n;
00436             return;
00437         }
00438         throw Exception("Not as many symbols");
00439     }
00440 
00444     size_t value() const {
00445         return value_;
00446     }
00447 
00451     const std::string& symbol() const {
00452         return schema()->nameAt(value_);
00453     }
00454 };
00455 
00459 class AVRO_DECL GenericFixed : public GenericContainer {
00460     std::vector<uint8_t> value_;
00461 public:
00466     GenericFixed(const NodePtr& schema) : GenericContainer(AVRO_FIXED, schema) {
00467         value_.resize(schema->fixedSize());
00468     }
00469 
00473     const std::vector<uint8_t>& value() const {
00474         return value_;
00475     }
00476 
00480     std::vector<uint8_t>& value() {
00481         return value_;
00482     }
00483 };
00484 
00485 
00489 class AVRO_DECL GenericReader : boost::noncopyable {
00490     const ValidSchema schema_;
00491     const bool isResolving_;
00492     const DecoderPtr decoder_;
00493 
00494     static void read(GenericDatum& datum, Decoder& d, bool isResolving);
00495 public:
00499     GenericReader(const ValidSchema& s, const DecoderPtr& decoder);
00500 
00506     GenericReader(const ValidSchema& writerSchema,
00507         const ValidSchema& readerSchema, const DecoderPtr& decoder);
00508 
00512     void read(GenericDatum& datum) const;
00513 
00517     static void read(Decoder& d, GenericDatum& g);
00518 
00522     static void read(Decoder& d, GenericDatum& g, const ValidSchema& s);
00523 };
00524 
00525 
00529 class AVRO_DECL GenericWriter : boost::noncopyable {
00530     const ValidSchema schema_;
00531     const EncoderPtr encoder_;
00532 
00533     static void write(const GenericDatum& datum, Encoder& e);
00534 public:
00538     GenericWriter(const ValidSchema& s, const EncoderPtr& encoder);
00539 
00543     void write(const GenericDatum& datum) const;
00544 
00548     static void write(Encoder& e, const GenericDatum& g);
00549 
00554     static void write(Encoder& e, const GenericDatum& g, const ValidSchema&) {
00555         write(e, g);
00556     }
00557 };
00558 
00559 inline Type AVRO_DECL GenericDatum::type() const {
00560     return (type_ == AVRO_UNION) ?
00561         boost::any_cast<GenericUnion>(&value_)->type() : type_;
00562 }
00563 
00564 template<typename T>
00565 const T& GenericDatum::value() const {
00566     return (type_ == AVRO_UNION) ?
00567         boost::any_cast<GenericUnion>(&value_)->value<T>() :
00568         *boost::any_cast<T>(&value_);
00569 }
00570 
00571 template<typename T>
00572 T& GenericDatum::value() {
00573     return (type_ == AVRO_UNION) ?
00574         boost::any_cast<GenericUnion>(&value_)->value<T>() :
00575         *boost::any_cast<T>(&value_);
00576 }
00577 
00578 inline size_t GenericDatum::unionBranch() const {
00579     return boost::any_cast<GenericUnion>(&value_)->currentBranch();
00580 }
00581 
00582 inline void GenericDatum::selectBranch(size_t branch) {
00583     boost::any_cast<GenericUnion>(&value_)->selectBranch(branch);
00584 }
00585 
00586 template <typename T> struct codec_traits;
00587 
00593 template <> struct codec_traits<std::pair<ValidSchema, GenericDatum> > {
00595     static void encode(Encoder& e,
00596         const std::pair<ValidSchema, GenericDatum>& p) {
00597         GenericWriter::write(e, p.second, p.first);
00598     }
00599 
00601     static void decode(Decoder& d, std::pair<ValidSchema, GenericDatum>& p) {
00602         GenericReader::read(d, p.second, p.first);
00603     }
00604 };
00605 
00609 template <> struct codec_traits<GenericDatum> {
00611     static void encode(Encoder& e, const GenericDatum& g) {
00612         GenericWriter::write(e, g);
00613     }
00614 
00616     static void decode(Decoder& d, GenericDatum& g) {
00617         GenericReader::read(d, g);
00618     }
00619 };
00620     
00621 }   // namespace avro
00622 #endif
00623