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 "Node.hh"
00030 #include "Types.hh"
00031 #include "Encoder.hh"
00032 #include "Decoder.hh"
00033 #include "ValidSchema.hh"
00034 
00035 namespace avro {
00058 class GenericDatum {
00059     Type type_;
00060     boost::any value_;
00061 
00062     GenericDatum(Type t) : type_(t) { }
00063 
00064     template <typename T>
00065     GenericDatum(Type t, const T& v) : type_(t), value_(v) { }
00066 
00067     void init(const NodePtr& schema);
00068 public:
00072     Type type() const;
00073 
00079     template<typename T> const T& value() const;
00080 
00090     template<typename T> T& value();
00091 
00095     bool isUnion() const { return type_ == AVRO_UNION; }
00096 
00101     size_t unionBranch() const;
00102 
00107     void selectBranch(size_t branch);
00108 
00110     GenericDatum() : type_(AVRO_NULL) { }
00111 
00113     GenericDatum(bool v) : type_(AVRO_BOOL), value_(v) { }
00114 
00116     GenericDatum(int32_t v) : type_(AVRO_INT), value_(v) { }
00117 
00119     GenericDatum(int64_t v) : type_(AVRO_LONG), value_(v) { }
00120 
00122     GenericDatum(float v) : type_(AVRO_FLOAT), value_(v) { }
00123 
00125     GenericDatum(double v) : type_(AVRO_DOUBLE), value_(v) { }
00126 
00128     GenericDatum(const std::string& v) : type_(AVRO_STRING), value_(v) { }
00129 
00132     GenericDatum(const std::vector<uint8_t>& v) :
00133         type_(AVRO_BYTES), value_(v) { }
00134 
00141     GenericDatum(const NodePtr& schema);
00142 
00149     GenericDatum(const ValidSchema& schema);
00150 };
00151 
00155 class GenericContainer {
00156     NodePtr schema_;
00157     static void assertType(const NodePtr& schema, Type type);
00158 protected:
00162     GenericContainer(Type type, const NodePtr& s) : schema_(s) {
00163         assertType(s, type);
00164     }
00165 
00169     static void assertSameType(const GenericDatum& v, const NodePtr& n);
00170 
00171 public:
00173     const NodePtr& schema() const {
00174         return schema_;
00175     }
00176 };
00177 
00181 class GenericUnion : public GenericContainer {
00182     size_t curBranch_;
00183     GenericDatum datum_;
00184 
00185 public:
00191     GenericUnion(const NodePtr& schema) :
00192         GenericContainer(AVRO_UNION, schema), curBranch_(schema->leaves()) {
00193     }
00194 
00198     size_t currentBranch() const { return curBranch_; }
00199 
00204     void selectBranch(size_t branch) {
00205         if (curBranch_ != branch) {
00206             datum_ = GenericDatum(schema()->leafAt(branch));
00207             curBranch_ = branch;
00208         }
00209     }
00210 
00214     Type type() const {
00215         return datum_.type();
00216     }
00217 
00221     template<typename T>
00222     const T& value() const {
00223         return datum_.value<T>();
00224     }
00225 
00229     template<typename T>
00230     T& value() {
00231         return datum_.value<T>();
00232     }
00233 
00234 };
00235 
00239 class GenericRecord : public GenericContainer {
00240     std::vector<GenericDatum> fields_;
00241 public:
00246     GenericRecord(const NodePtr& schema);
00247 
00251     size_t fieldCount() const {
00252         return fields_.size();
00253     }
00254 
00258     const GenericDatum& fieldAt(size_t pos) const {
00259         return fields_[pos];
00260     }
00261 
00266     GenericDatum& fieldAt(size_t pos) {
00267         return fields_[pos];
00268     }
00269 
00273     void setFieldAt(size_t pos, const GenericDatum& v) {
00274         assertSameType(v, schema()->leafAt(pos));    
00275         fields_[pos] = v;
00276     }
00277 };
00278 
00282 class GenericArray : public GenericContainer {
00283 public:
00287     typedef std::vector<GenericDatum> Value;
00288 
00293     GenericArray(const NodePtr& schema) : GenericContainer(AVRO_ARRAY, schema) {
00294     }
00295 
00299     const Value& value() const {
00300         return value_;
00301     }
00302 
00306     Value& value() {
00307         return value_;
00308     }
00309 private:
00310     Value value_;
00311 };
00312 
00316 class GenericMap : public GenericContainer {
00317 public:
00321     typedef std::vector<std::pair<std::string, GenericDatum> > Value;
00322 
00327     GenericMap(const NodePtr& schema) : GenericContainer(AVRO_MAP, schema) {
00328     }
00329 
00333     const Value& value() const {
00334         return value_;
00335     }
00336 
00340     Value& value() {
00341         return value_;
00342     }
00343 private:
00344     Value value_;
00345 };
00346 
00350 class GenericEnum : public GenericContainer {
00351     size_t value_;
00352 public:
00357     GenericEnum(const NodePtr& schema) :
00358         GenericContainer(AVRO_ENUM, schema), value_(0) {
00359     }
00360 
00365     const std::string& symbol(size_t n) {
00366         if (n < schema()->names()) {
00367             return schema()->nameAt(n);
00368         }
00369         throw Exception("Not as many symbols");
00370     }
00371 
00376     size_t index(const std::string& symbol) const {
00377         size_t result;
00378         if (schema()->nameIndex(symbol, result)) {
00379             return result;
00380         }
00381         throw Exception("No such symbol");
00382     }
00383 
00387     size_t set(const std::string& symbol) {
00388         return value_ = index(symbol);
00389     }
00390 
00394     void set(size_t n) {
00395         if (n < schema()->names()) {
00396             value_ = n;
00397             return;
00398         }
00399         throw Exception("Not as many symbols");
00400     }
00401 
00405     size_t value() const {
00406         return value_;
00407     }
00408 
00412     const std::string& symbol() const {
00413         return schema()->nameAt(value_);
00414     }
00415 };
00416 
00420 class GenericFixed : public GenericContainer {
00421     std::vector<uint8_t> value_;
00422 public:
00427     GenericFixed(const NodePtr& schema) : GenericContainer(AVRO_FIXED, schema) {
00428         value_.resize(schema->fixedSize());
00429     }
00430 
00434     const std::vector<uint8_t>& value() const {
00435         return value_;
00436     }
00437 
00441     std::vector<uint8_t>& value() {
00442         return value_;
00443     }
00444 };
00445 
00446 
00450 class GenericReader : boost::noncopyable {
00451     const ValidSchema schema_;
00452     const bool isResolving_;
00453     const DecoderPtr decoder_;
00454 
00455     static void read(GenericDatum& datum, Decoder& d, bool isResolving);
00456 public:
00460     GenericReader(const ValidSchema& s, const DecoderPtr& decoder);
00461 
00467     GenericReader(const ValidSchema& writerSchema,
00468         const ValidSchema& readerSchema, const DecoderPtr& decoder);
00469 
00473     void read(GenericDatum& datum) const;
00474 
00478     static void read(Decoder& d, GenericDatum& g);
00479 
00483     static void read(Decoder& d, GenericDatum& g, const ValidSchema& s);
00484 };
00485 
00486 
00490 class GenericWriter : boost::noncopyable {
00491     const ValidSchema schema_;
00492     const EncoderPtr encoder_;
00493 
00494     static void write(const GenericDatum& datum, Encoder& e);
00495 public:
00499     GenericWriter(const ValidSchema& s, const EncoderPtr& encoder);
00500 
00504     void write(const GenericDatum& datum) const;
00505 
00509     static void write(Encoder& e, const GenericDatum& g);
00510 
00515     static void write(Encoder& e, const GenericDatum& g, const ValidSchema&) {
00516         write(e, g);
00517     }
00518 };
00519 
00520 inline Type GenericDatum::type() const {
00521     return (type_ == AVRO_UNION) ?
00522         boost::any_cast<GenericUnion>(&value_)->type() : type_;
00523 }
00524 
00525 template<typename T>
00526 const T& GenericDatum::value() const {
00527     return (type_ == AVRO_UNION) ?
00528         boost::any_cast<GenericUnion>(&value_)->value<T>() :
00529         *boost::any_cast<T>(&value_);
00530 }
00531 
00532 template<typename T>
00533 T& GenericDatum::value() {
00534     return (type_ == AVRO_UNION) ?
00535         boost::any_cast<GenericUnion>(&value_)->value<T>() :
00536         *boost::any_cast<T>(&value_);
00537 }
00538 
00539 inline size_t GenericDatum::unionBranch() const {
00540     return boost::any_cast<GenericUnion>(&value_)->currentBranch();
00541 }
00542 
00543 inline void GenericDatum::selectBranch(size_t branch) {
00544     boost::any_cast<GenericUnion>(&value_)->selectBranch(branch);
00545 }
00546 
00547 template <typename T> struct codec_traits;
00548 
00554 template <> struct codec_traits<std::pair<ValidSchema, GenericDatum> > {
00556     static void encode(Encoder& e,
00557         const std::pair<ValidSchema, GenericDatum>& p) {
00558         GenericWriter::write(e, p.second, p.first);
00559     }
00560 
00562     static void decode(Decoder& d, std::pair<ValidSchema, GenericDatum>& p) {
00563         GenericReader::read(d, p.second, p.first);
00564     }
00565 };
00566 
00570 template <> struct codec_traits<GenericDatum> {
00572     static void encode(Encoder& e, const GenericDatum& g) {
00573         GenericWriter::write(e, g);
00574     }
00575 
00577     static void decode(Decoder& d, GenericDatum& g) {
00578         GenericReader::read(d, g);
00579     }
00580 };
00581     
00582 }   // namespace avro
00583 #endif
00584