IWAField.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /*
00003  * This file is part of the libetonyek project.
00004  *
00005  * This Source Code Form is subject to the terms of the Mozilla Public
00006  * License, v. 2.0. If a copy of the MPL was not distributed with this
00007  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
00008  */
00009 
00010 #ifndef IWAFIELD_H_INCLUDED
00011 #define IWAFIELD_H_INCLUDED
00012 
00013 #include <deque>
00014 #include <stdexcept>
00015 
00016 #include <boost/container/deque.hpp>
00017 #include <boost/optional.hpp>
00018 #include <boost/shared_ptr.hpp>
00019 
00020 #include "IWAReader.h"
00021 #include "libetonyek_utils.h"
00022 
00023 namespace libetonyek
00024 {
00025 
00026 class IWAField
00027 {
00028 public:
00029   enum Tag
00030   {
00031     TAG_INT32,
00032     TAG_INT64,
00033     TAG_UINT32,
00034     TAG_UINT64,
00035     TAG_SINT32,
00036     TAG_SINT64,
00037     TAG_BOOL,
00038     TAG_ENUM,
00039     TAG_FIXED64,
00040     TAG_SFIXED64,
00041     TAG_DOUBLE,
00042     TAG_STRING,
00043     TAG_BYTES,
00044     TAG_MESSAGE,
00045     TAG_FIXED32,
00046     TAG_SFIXED32,
00047     TAG_FLOAT
00048   };
00049 
00050 public:
00051   virtual ~IWAField() = 0;
00052 
00053   virtual Tag tag() const = 0;
00054 
00055   // repeated
00056   virtual bool empty() const = 0;
00057   virtual std::size_t size() const = 0;
00058 
00059   // optional
00060   virtual bool is() const = 0;
00061   operator bool() const;
00062   bool operator!() const;
00063 
00064   virtual void parse(const RVNGInputStreamPtr_t &input, unsigned long length, bool allowEmpty) = 0;
00065 };
00066 
00067 typedef boost::shared_ptr<IWAField> IWAFieldPtr_t;
00068 
00069 namespace detail
00070 {
00071 
00072 template<IWAField::Tag TagV, typename ValueT, typename Reader>
00073 class IWAFieldImpl : public IWAField
00074 {
00075   typedef boost::container::deque<ValueT> container_type;
00076 
00077 public:
00078   typedef ValueT value_type;
00079   typedef ValueT &reference_type;
00080   typedef const ValueT &const_reference_type;
00081   typedef typename container_type::const_iterator const_iterator;
00082   typedef typename container_type::const_reverse_iterator const_reverse_iterator;
00083 
00084 public:
00085   // classification
00086 
00087   virtual IWAField::Tag tag() const
00088   {
00089     return TagV;
00090   }
00091 
00092   // optional interface
00093 
00094   virtual bool is() const
00095   {
00096     return !m_values.empty();
00097   }
00098 
00099   const_reference_type get() const
00100   {
00101     if (m_values.empty())
00102       throw std::logic_error("the field is unset");
00103     return m_values[0];
00104   }
00105 
00106   // container interface
00107 
00108   virtual bool empty() const
00109   {
00110     return m_values.empty();
00111   }
00112 
00113   virtual std::size_t size() const
00114   {
00115     return m_values.size();
00116   }
00117 
00118   const_reference_type operator[](const std::size_t index) const
00119   {
00120     if (index >= m_values.size())
00121       throw std::out_of_range("index is out of range");
00122     return m_values[index];
00123   }
00124 
00125   const_iterator begin() const
00126   {
00127     return m_values.begin();
00128   }
00129 
00130   const_iterator end() const
00131   {
00132     return m_values.end();
00133   }
00134 
00135   const_reverse_iterator rbegin() const
00136   {
00137     return m_values.rbegin();
00138   }
00139 
00140   const_reverse_iterator rend() const
00141   {
00142     return m_values.rend();
00143   }
00144 
00145   // conversions
00146 
00147   // TODO: remove this or replace direct use of std::deque by a typedef
00148   const std::deque<value_type> repeated() const
00149   {
00150     const std::deque<value_type> values(m_values.begin(), m_values.end());
00151     return values;
00152   }
00153 
00154   const boost::optional<value_type> optional() const
00155   {
00156     return m_values.empty() ? boost::none : boost::make_optional(m_values.front());
00157   }
00158 
00159   // initialization
00160 
00161   virtual void parse(const RVNGInputStreamPtr_t &input, const unsigned long length, const bool allowEmpty)
00162   {
00163     if (length != 0)
00164     {
00165       const long start = input->tell();
00166       while (!input->isEnd() && (length > static_cast<unsigned long>(input->tell() - start)))
00167       {
00168         const value_type value(Reader::read(input, length));
00169         m_values.push_back(value);
00170       }
00171     }
00172     else if (allowEmpty)
00173     {
00174       m_values.push_back(value_type());
00175     }
00176   }
00177 
00178 private:
00179   container_type m_values;
00180 };
00181 
00182 }
00183 
00184 template<IWAField::Tag TagV, typename ValueT, typename Reader>
00185 const ValueT &get(const detail::IWAFieldImpl<TagV, ValueT, Reader> &field)
00186 {
00187   return field.get();
00188 }
00189 
00190 template<IWAField::Tag TagV, typename ValueT, typename Reader>
00191 const ValueT &get_optional_value_or(const detail::IWAFieldImpl<TagV, ValueT, Reader> &field, const ValueT &value)
00192 {
00193   return bool(field) ? field.get() : value;
00194 }
00195 
00196 template<IWAField::Tag TagV, typename ValueT, typename Reader, typename DefaultValueT>
00197 const ValueT get_optional_value_or(const detail::IWAFieldImpl<TagV, ValueT, Reader> &field, const DefaultValueT &value)
00198 {
00199   return bool(field) ? field.get() : ValueT(value);
00200 }
00201 
00202 typedef detail::IWAFieldImpl<IWAField::TAG_UINT32, uint32_t, IWAReader::UInt32> IWAUInt32Field;
00203 typedef detail::IWAFieldImpl<IWAField::TAG_UINT64, uint64_t, IWAReader::UInt64> IWAUInt64Field;
00204 typedef detail::IWAFieldImpl<IWAField::TAG_SINT32, int32_t, IWAReader::SInt32> IWASInt32Field;
00205 typedef detail::IWAFieldImpl<IWAField::TAG_SINT64, int64_t, IWAReader::SInt64> IWASInt64Field;
00206 typedef detail::IWAFieldImpl<IWAField::TAG_BOOL, bool, IWAReader::Bool> IWABoolField;
00207 
00208 typedef detail::IWAFieldImpl<IWAField::TAG_FIXED64, uint64_t, IWAReader::Fixed64> IWAFixed64Field;
00209 typedef detail::IWAFieldImpl<IWAField::TAG_DOUBLE, double, IWAReader::Double> IWADoubleField;
00210 
00211 typedef detail::IWAFieldImpl<IWAField::TAG_STRING, std::string, IWAReader::String> IWAStringField;
00212 typedef detail::IWAFieldImpl<IWAField::TAG_BYTES, RVNGInputStreamPtr_t, IWAReader::Bytes> IWABytesField;
00213 
00214 typedef detail::IWAFieldImpl<IWAField::TAG_FIXED32, uint32_t, IWAReader::Fixed32> IWAFixed32Field;
00215 typedef detail::IWAFieldImpl<IWAField::TAG_FLOAT, float, IWAReader::Float> IWAFloatField;
00216 
00217 class IWAMessageField : public detail::IWAFieldImpl<IWAField::TAG_MESSAGE, IWAMessage, IWAReader::Message>
00218 {
00219 public:
00220   const IWAUInt32Field &uint32(std::size_t field) const;
00221   const IWAUInt64Field &uint64(std::size_t field) const;
00222   const IWASInt32Field &sint32(std::size_t field) const;
00223   const IWASInt64Field &sint64(std::size_t field) const;
00224   const IWABoolField &bool_(std::size_t field) const;
00225 
00226   const IWAFixed64Field &fixed64(std::size_t field) const;
00227   const IWADoubleField &double_(std::size_t field) const;
00228 
00229   const IWAStringField &string(std::size_t field) const;
00230   const IWABytesField &bytes(std::size_t field) const;
00231   const IWAMessageField &message(std::size_t field) const;
00232 
00233   const IWAFixed32Field &fixed32(std::size_t field) const;
00234   const IWAFloatField &float_(std::size_t field) const;
00235 };
00236 
00237 }
00238 
00239 #endif
00240 
00241 /* vim:set shiftwidth=2 softtabstop=2 expandtab: */