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     const GenericDatum& fieldAt(size_t pos) const {
00255         return fields_[pos];
00256     }
00257 
00262     GenericDatum& fieldAt(size_t pos) {
00263         return fields_[pos];
00264     }
00265 
00269     void setFieldAt(size_t pos, const GenericDatum& v) {
00270         // assertSameType(v, schema()->leafAt(pos));    
00271         fields_[pos] = v;
00272     }
00273 };
00274 
00278 class AVRO_DECL GenericArray : public GenericContainer {
00279 public:
00283     typedef std::vector<GenericDatum> Value;
00284 
00289     GenericArray(const NodePtr& schema) : GenericContainer(AVRO_ARRAY, schema) {
00290     }
00291 
00295     const Value& value() const {
00296         return value_;
00297     }
00298 
00302     Value& value() {
00303         return value_;
00304     }
00305 private:
00306     Value value_;
00307 };
00308 
00312 class AVRO_DECL GenericMap : public GenericContainer {
00313 public:
00317     typedef std::vector<std::pair<std::string, GenericDatum> > Value;
00318 
00323     GenericMap(const NodePtr& schema) : GenericContainer(AVRO_MAP, schema) {
00324     }
00325 
00329     const Value& value() const {
00330         return value_;
00331     }
00332 
00336     Value& value() {
00337         return value_;
00338     }
00339 private:
00340     Value value_;
00341 };
00342 
00346 class AVRO_DECL GenericEnum : public GenericContainer {
00347     size_t value_;
00348 public:
00353     GenericEnum(const NodePtr& schema) :
00354         GenericContainer(AVRO_ENUM, schema), value_(0) {
00355     }
00356 
00361     const std::string& symbol(size_t n) {
00362         if (n < schema()->names()) {
00363             return schema()->nameAt(n);
00364         }
00365         throw Exception("Not as many symbols");
00366     }
00367 
00372     size_t index(const std::string& symbol) const {
00373         size_t result;
00374         if (schema()->nameIndex(symbol, result)) {
00375             return result;
00376         }
00377         throw Exception("No such symbol");
00378     }
00379 
00383     size_t set(const std::string& symbol) {
00384         return value_ = index(symbol);
00385     }
00386 
00390     void set(size_t n) {
00391         if (n < schema()->names()) {
00392             value_ = n;
00393             return;
00394         }
00395         throw Exception("Not as many symbols");
00396     }
00397 
00401     size_t value() const {
00402         return value_;
00403     }
00404 
00408     const std::string& symbol() const {
00409         return schema()->nameAt(value_);
00410     }
00411 };
00412 
00416 class AVRO_DECL GenericFixed : public GenericContainer {
00417     std::vector<uint8_t> value_;
00418 public:
00423     GenericFixed(const NodePtr& schema) : GenericContainer(AVRO_FIXED, schema) {
00424         value_.resize(schema->fixedSize());
00425     }
00426 
00430     const std::vector<uint8_t>& value() const {
00431         return value_;
00432     }
00433 
00437     std::vector<uint8_t>& value() {
00438         return value_;
00439     }
00440 };
00441 
00442 
00446 class AVRO_DECL GenericReader : boost::noncopyable {
00447     const ValidSchema schema_;
00448     const bool isResolving_;
00449     const DecoderPtr decoder_;
00450 
00451     static void read(GenericDatum& datum, Decoder& d, bool isResolving);
00452 public:
00456     GenericReader(const ValidSchema& s, const DecoderPtr& decoder);
00457 
00463     GenericReader(const ValidSchema& writerSchema,
00464         const ValidSchema& readerSchema, const DecoderPtr& decoder);
00465 
00469     void read(GenericDatum& datum) const;
00470 
00474     static void read(Decoder& d, GenericDatum& g);
00475 
00479     static void read(Decoder& d, GenericDatum& g, const ValidSchema& s);
00480 };
00481 
00482 
00486 class AVRO_DECL GenericWriter : boost::noncopyable {
00487     const ValidSchema schema_;
00488     const EncoderPtr encoder_;
00489 
00490     static void write(const GenericDatum& datum, Encoder& e);
00491 public:
00495     GenericWriter(const ValidSchema& s, const EncoderPtr& encoder);
00496 
00500     void write(const GenericDatum& datum) const;
00501 
00505     static void write(Encoder& e, const GenericDatum& g);
00506 
00511     static void write(Encoder& e, const GenericDatum& g, const ValidSchema&) {
00512         write(e, g);
00513     }
00514 };
00515 
00516 inline Type AVRO_DECL GenericDatum::type() const {
00517     return (type_ == AVRO_UNION) ?
00518         boost::any_cast<GenericUnion>(&value_)->type() : type_;
00519 }
00520 
00521 template<typename T>
00522 const T& GenericDatum::value() const {
00523     return (type_ == AVRO_UNION) ?
00524         boost::any_cast<GenericUnion>(&value_)->value<T>() :
00525         *boost::any_cast<T>(&value_);
00526 }
00527 
00528 template<typename T>
00529 T& GenericDatum::value() {
00530     return (type_ == AVRO_UNION) ?
00531         boost::any_cast<GenericUnion>(&value_)->value<T>() :
00532         *boost::any_cast<T>(&value_);
00533 }
00534 
00535 inline size_t GenericDatum::unionBranch() const {
00536     return boost::any_cast<GenericUnion>(&value_)->currentBranch();
00537 }
00538 
00539 inline void GenericDatum::selectBranch(size_t branch) {
00540     boost::any_cast<GenericUnion>(&value_)->selectBranch(branch);
00541 }
00542 
00543 template <typename T> struct codec_traits;
00544 
00550 template <> struct codec_traits<std::pair<ValidSchema, GenericDatum> > {
00552     static void encode(Encoder& e,
00553         const std::pair<ValidSchema, GenericDatum>& p) {
00554         GenericWriter::write(e, p.second, p.first);
00555     }
00556 
00558     static void decode(Decoder& d, std::pair<ValidSchema, GenericDatum>& p) {
00559         GenericReader::read(d, p.second, p.first);
00560     }
00561 };
00562 
00566 template <> struct codec_traits<GenericDatum> {
00568     static void encode(Encoder& e, const GenericDatum& g) {
00569         GenericWriter::write(e, g);
00570     }
00571 
00573     static void decode(Decoder& d, GenericDatum& g) {
00574         GenericReader::read(d, g);
00575     }
00576 };
00577     
00578 }   // namespace avro
00579 #endif
00580