// ********************************************************************** // // Copyright (c) 2003-present ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** #ifndef ICE_STREAM_HELPERS_H #define ICE_STREAM_HELPERS_H #include #ifndef ICE_CPP11_MAPPING # include # include #endif namespace Ice { /// \cond STREAM /** * The stream helper category allows streams to select the desired StreamHelper for a given streamable object. */ typedef int StreamHelperCategory; /** For types with no specialized trait. */ const StreamHelperCategory StreamHelperCategoryUnknown = 0; /** For built-in types. */ const StreamHelperCategory StreamHelperCategoryBuiltin = 1; /** For struct types. */ const StreamHelperCategory StreamHelperCategoryStruct = 2; /** For struct types with cpp:class metadata. */ const StreamHelperCategory StreamHelperCategoryStructClass = 3; /** For enum types. */ const StreamHelperCategory StreamHelperCategoryEnum = 4; /** For sequence types. */ const StreamHelperCategory StreamHelperCategorySequence = 5; /** For dictionary types. */ const StreamHelperCategory StreamHelperCategoryDictionary = 6; /** For proxy types. */ const StreamHelperCategory StreamHelperCategoryProxy = 7; /** For class types. */ const StreamHelperCategory StreamHelperCategoryClass = 8; /** For exception types. */ const StreamHelperCategory StreamHelperCategoryUserException = 9; /** * The optional format. * * Optional data members and parameters are encoded with a specific * optional format. This optional format describes how the data is encoded * and how it can be skipped by the unmarshaling code if the optional ID * isn't known to the receiver. */ #ifdef ICE_CPP11_MAPPING enum class OptionalFormat : unsigned char { /** Fixed 1-byte encoding. */ F1 = 0, /** Fixed 2-byte encoding. */ F2 = 1, /** Fixed 4-byte encoding. */ F4 = 2, /** Fixed 8-byte encoding. */ F8 = 3, /** "Size encoding" using 1 to 5 bytes, e.g., enum, class identifier. */ Size = 4, /** * "Size encoding" using 1 to 5 bytes followed by data, e.g., string, fixed size * struct, or containers whose size can be computed prior to marshaling. */ VSize = 5, /** Fixed size using 4 bytes followed by data, e.g., variable-size struct, container. */ FSize = 6, /** Class instance. */ Class = 7 }; #else enum OptionalFormat { /** Fixed 1-byte encoding. */ OptionalFormatF1 = 0, /** Fixed 2-byte encoding. */ OptionalFormatF2 = 1, /** Fixed 4-byte encoding. */ OptionalFormatF4 = 2, /** Fixed 8-byte encoding. */ OptionalFormatF8 = 3, /** "Size encoding" using 1 to 5 bytes, e.g., enum, class identifier. */ OptionalFormatSize = 4, /** * "Size encoding" using 1 to 5 bytes followed by data, e.g., string, fixed size * struct, or containers whose size can be computed prior to marshaling. */ OptionalFormatVSize = 5, /** Fixed size using 4 bytes followed by data, e.g., variable-size struct, container. */ OptionalFormatFSize = 6, /** Class instance. */ OptionalFormatClass = 7 }; #endif /** * Determines whether the provided type is a container. For now, the implementation only checks * if there is a T::iterator typedef using SFINAE. * \headerfile Ice/Ice.h */ template struct IsContainer { template static char test(typename C::iterator*); template static long test(...); static const bool value = sizeof(test(0)) == sizeof(char); }; /** * Determines whether the provided type is a map. For now, the implementation only checks if there * is a T::mapped_type typedef using SFINAE. * \headerfile Ice/Ice.h */ template struct IsMap { template static char test(typename C::mapped_type*); template static long test(...); static const bool value = IsContainer::value && sizeof(test(0)) == sizeof(char); }; #ifdef ICE_CPP11_MAPPING /** * Base traits template. Types with no specialized trait use this trait. * \headerfile Ice/Ice.h */ template struct StreamableTraits { static const StreamHelperCategory helper = StreamHelperCategoryUnknown; // // When extracting a sequence from a stream, we can ensure the // stream has at least StreamableTraits::minWireSize * size bytes // For containers, the minWireSize is 1 (just 1 byte for an empty container). // //static const int minWireSize = 1; // // Is this type encoded on a fixed number of bytes? // Used only for marshaling/unmarshaling optional data members and parameters. // //static const bool fixedLength = false; }; /** * Specialization for sequence and dictionary types. * \headerfile Ice/Ice.h */ template struct StreamableTraits::value || IsContainer::value>::type> { static const StreamHelperCategory helper = IsMap::value ? StreamHelperCategoryDictionary : StreamHelperCategorySequence; static const int minWireSize = 1; static const bool fixedLength = false; }; /** * Specialization for exceptions. * \headerfile Ice/Ice.h */ template struct StreamableTraits::value>::type> { static const StreamHelperCategory helper = StreamHelperCategoryUserException; // // There is no sequence/dictionary of UserException (so no need for minWireSize) // and no optional UserException (so no need for fixedLength) // }; /** * Specialization for arrays (std::pair). * \headerfile Ice/Ice.h */ template struct StreamableTraits> { static const StreamHelperCategory helper = StreamHelperCategorySequence; static const int minWireSize = 1; static const bool fixedLength = false; }; #else /** * Base traits template. Types with no specialized trait use this trait, including sequence and * dictionary types. * \headerfile Ice/Ice.h */ template struct StreamableTraits { static const StreamHelperCategory helper = IsMap::value ? StreamHelperCategoryDictionary : (IsContainer::value ? StreamHelperCategorySequence : StreamHelperCategoryUnknown); /** * When extracting a sequence from a stream, we can ensure the * stream has at least StreamableTraits::minWireSize * size bytes. * For containers, the minWireSize is 1 (just 1 byte for an empty container). */ static const int minWireSize = 1; /** * Is this type encoded on a fixed number of bytes? * Used only for marshaling/unmarshaling optional data members and parameters. */ static const bool fixedLength = false; }; /** * Specialization for exceptions. * \headerfile Ice/Ice.h */ template<> struct StreamableTraits { static const StreamHelperCategory helper = StreamHelperCategoryUserException; // // There is no sequence/dictionary of UserException (so no need for minWireSize) // and no optional UserException (so no need for fixedLength) // }; /** * Specialization for array / range mapped sequences. The type can be a std::pair or a * std::pair, std::pair >. * \headerfile Ice/Ice.h */ template struct StreamableTraits< ::std::pair > { static const StreamHelperCategory helper = StreamHelperCategorySequence; static const int minWireSize = 1; static const bool fixedLength = false; }; #endif /** * Specialization for built-in type (this is needed for sequence * marshaling to figure out the minWireSize of each type). * \headerfile Ice/Ice.h */ template<> struct StreamableTraits { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 1; static const bool fixedLength = true; }; /** * Specialization for built-in type (this is needed for sequence * marshaling to figure out the minWireSize of each type). * \headerfile Ice/Ice.h */ template<> struct StreamableTraits { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 1; static const bool fixedLength = true; }; /** * Specialization for built-in type (this is needed for sequence * marshaling to figure out the minWireSize of each type). * \headerfile Ice/Ice.h */ template<> struct StreamableTraits { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 2; static const bool fixedLength = true; }; /** * Specialization for built-in type (this is needed for sequence * marshaling to figure out the minWireSize of each type). * \headerfile Ice/Ice.h */ template<> struct StreamableTraits { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 4; static const bool fixedLength = true; }; /** * Specialization for built-in type (this is needed for sequence * marshaling to figure out the minWireSize of each type). * \headerfile Ice/Ice.h */ template<> struct StreamableTraits { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 8; static const bool fixedLength = true; }; /** * Specialization for built-in type (this is needed for sequence * marshaling to figure out the minWireSize of each type). * \headerfile Ice/Ice.h */ template<> struct StreamableTraits { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 4; static const bool fixedLength = true; }; /** * Specialization for built-in type (this is needed for sequence * marshaling to figure out the minWireSize of each type). * \headerfile Ice/Ice.h */ template<> struct StreamableTraits { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 8; static const bool fixedLength = true; }; /** * Specialization for built-in type (this is needed for sequence * marshaling to figure out the minWireSize of each type). * \headerfile Ice/Ice.h */ template<> struct StreamableTraits< ::std::string> { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 1; static const bool fixedLength = false; }; /** * Specialization for built-in type (this is needed for sequence * marshaling to figure out the minWireSize of each type). * \headerfile Ice/Ice.h */ template<> struct StreamableTraits< ::std::wstring> { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 1; static const bool fixedLength = false; }; /** * vector is a special type in C++: the streams handle it like a built-in type. * \headerfile Ice/Ice.h */ template<> struct StreamableTraits< ::std::vector > { static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; static const int minWireSize = 1; static const bool fixedLength = false; }; /** * Specialization for proxy types. * \headerfile Ice/Ice.h */ #ifdef ICE_CPP11_MAPPING template struct StreamableTraits<::std::shared_ptr, typename ::std::enable_if<::std::is_base_of<::Ice::ObjectPrx, T>::value>::type> { static const StreamHelperCategory helper = StreamHelperCategoryProxy; static const int minWireSize = 2; static const bool fixedLength = false; }; #else template struct StreamableTraits< ::IceInternal::ProxyHandle > { static const StreamHelperCategory helper = StreamHelperCategoryProxy; static const int minWireSize = 2; static const bool fixedLength = false; }; #endif /** * Specialization for class types. * \headerfile Ice/Ice.h */ #ifdef ICE_CPP11_MAPPING template struct StreamableTraits<::std::shared_ptr, typename ::std::enable_if<::std::is_base_of<::Ice::Value, T>::value>::type> { static const StreamHelperCategory helper = StreamHelperCategoryClass; static const int minWireSize = 1; static const bool fixedLength = false; }; #else template struct StreamableTraits< ::IceInternal::Handle > { static const StreamHelperCategory helper = StreamHelperCategoryClass; static const int minWireSize = 1; static const bool fixedLength = false; }; #endif // // StreamHelper templates used by streams to read and write data. // /** Base StreamHelper template; it must be specialized for each type. */ template struct StreamHelper; /** * Helper for built-ins, delegates read/write to the stream. * \headerfile Ice/Ice.h */ template struct StreamHelper { template static inline void write(S* stream, const T& v) { stream->write(v); } template static inline void read(S* stream, T& v) { stream->read(v); } }; // // "helpers" for the StreamHelper below // slice2cpp generates specializations as needed // /** * General writer. slice2cpp generates specializations as needed. * \headerfile Ice/Ice.h */ template struct StreamWriter { #ifdef ICE_CPP11_MAPPING static inline void write(S* stream, const T& v) { stream->writeAll(v.ice_tuple()); } #else static inline void write(S*, const T&) { // Default is to write nothing for C++98 } #endif }; /** * General reader. slice2cpp generates specializations as needed. * \headerfile Ice/Ice.h */ template struct StreamReader { static inline void read(S*, T&) { // Default is to read nothing } }; /** * Helper for structs. * \headerfile Ice/Ice.h */ template struct StreamHelper { template static inline void write(S* stream, const T& v) { StreamWriter::write(stream, v); } template static inline void read(S* stream, T& v) { StreamReader::read(stream, v); } }; /** * Helper for class structs. * \headerfile Ice/Ice.h */ template struct StreamHelper { template static inline void write(S* stream, const T& v) { StreamWriter::write(stream, v); } template static inline void read(S* stream, T& v) { v = new typename T::element_type; StreamReader::read(stream, v); } }; /** * Helper for enums. * \headerfile Ice/Ice.h */ template struct StreamHelper { template static inline void write(S* stream, const T& v) { if(static_cast(v) < StreamableTraits::minValue || static_cast(v) > StreamableTraits::maxValue) { IceInternal::Ex::throwMarshalException(__FILE__, __LINE__, "enumerator out of range"); } stream->writeEnum(static_cast(v), StreamableTraits::maxValue); } template static inline void read(S* stream, T& v) { Int value = stream->readEnum(StreamableTraits::maxValue); if(value < StreamableTraits::minValue || value > StreamableTraits::maxValue) { IceInternal::Ex::throwMarshalException(__FILE__, __LINE__, "enumerator out of range"); } v = static_cast(value); } }; /** * Helper for sequences. * \headerfile Ice/Ice.h */ template struct StreamHelper { template static inline void write(S* stream, const T& v) { stream->writeSize(static_cast(v.size())); for(typename T::const_iterator p = v.begin(); p != v.end(); ++p) { stream->write(*p); } } template static inline void read(S* stream, T& v) { Int sz = stream->readAndCheckSeqSize(StreamableTraits::minWireSize); T(sz).swap(v); for(typename T::iterator p = v.begin(); p != v.end(); ++p) { stream->read(*p); } } }; /** * Helper for array custom sequence parameters. * \headerfile Ice/Ice.h */ template struct StreamHelper, StreamHelperCategorySequence> { template static inline void write(S* stream, const std::pair& v) { stream->write(v.first, v.second); } template static inline void read(S* stream, std::pair& v) { stream->read(v); } }; #ifndef ICE_CPP11_MAPPING /** * Helper for range custom sequence parameters. * \headerfile Ice/Ice.h */ template struct StreamHelper, StreamHelperCategorySequence> { template static inline void write(S* stream, const std::pair& v) { stream->writeSize(static_cast(IceUtilInternal::distance(v.first, v.second))); for(T p = v.first; p != v.second; ++p) { stream->write(*p); } } template static inline void read(S* stream, std::pair& v) { stream->read(v); } }; /** * Specialization for sequence. * \headerfile Ice/Ice.h */ template<> struct StreamHelper::const_iterator, ::std::vector::const_iterator>, StreamHelperCategorySequence> { template static inline void write(S* stream, const std::pair< ::std::vector::const_iterator, ::std::vector::const_iterator>& v) { stream->writeSize(static_cast(IceUtilInternal::distance(v.first, v.second))); for(::std::vector::const_iterator p = v.first; p != v.second; ++p) { stream->write(static_cast(*p)); } } }; /** * Helper for zero-copy array sequence parameters. * \headerfile Ice/Ice.h */ template struct StreamHelper, std::pair >, StreamHelperCategorySequence> { template static inline void read(S* stream, std::pair, std::pair >& v) { stream->read(v.second, v.first); } // no write: only used for unmarshaling }; #endif /** * Helper for dictionaries. * \headerfile Ice/Ice.h */ template struct StreamHelper { template static inline void write(S* stream, const T& v) { stream->writeSize(static_cast(v.size())); for(typename T::const_iterator p = v.begin(); p != v.end(); ++p) { stream->write(p->first); stream->write(p->second); } } template static inline void read(S* stream, T& v) { Int sz = stream->readSize(); v.clear(); while(sz--) { typename T::value_type p; stream->read(const_cast(p.first)); typename T::iterator i = v.insert(v.end(), p); stream->read(i->second); } } }; /** * Helper for user exceptions. * \headerfile Ice/Ice.h */ template struct StreamHelper { template static inline void write(S* stream, const T& v) { stream->writeException(v); } // no read: only used for marshaling }; /** * Helper for proxies. * \headerfile Ice/Ice.h */ template struct StreamHelper { template static inline void write(S* stream, const T& v) { stream->write(v); } template static inline void read(S* stream, T& v) { stream->read(v); } }; /** * Helper for classes. * \headerfile Ice/Ice.h */ template struct StreamHelper { template static inline void write(S* stream, const T& v) { stream->write(v); } template static inline void read(S* stream, T& v) { stream->read(v); } }; // // Helpers to read/write optional attributes or members. // // // Extract / compute the optionalFormat // This is used _only_ for the base StreamOptionalHelper below // /!\ Do not use in StreamOptionalHelper specializations, and do // not provide specialization not handled by the base StreamOptionalHelper // /** * Extract / compute the optionalFormat. * \headerfile Ice/Ice.h */ template struct GetOptionalFormat; /** * Specialization for 1-byte built-in fixed-length types. * \headerfile Ice/Ice.h */ template<> struct GetOptionalFormat { static const OptionalFormat value = ICE_SCOPED_ENUM(OptionalFormat, F1); }; /** * Specialization for 2-byte built-in fixed-length types. * \headerfile Ice/Ice.h */ template<> struct GetOptionalFormat { static const OptionalFormat value = ICE_SCOPED_ENUM(OptionalFormat, F2); }; /** * Specialization for 4-byte built-in fixed-length types. * \headerfile Ice/Ice.h */ template<> struct GetOptionalFormat { static const OptionalFormat value = ICE_SCOPED_ENUM(OptionalFormat, F4); }; /** * Specialization for 8-byte built-in fixed-length types. * \headerfile Ice/Ice.h */ template<> struct GetOptionalFormat { static const OptionalFormat value = ICE_SCOPED_ENUM(OptionalFormat, F8); }; /** * Specialization for built-in variable-length types. * \headerfile Ice/Ice.h */ template<> struct GetOptionalFormat { static const OptionalFormat value = ICE_SCOPED_ENUM(OptionalFormat, VSize); }; /** * Specialization for class types. * \headerfile Ice/Ice.h */ template<> struct GetOptionalFormat { static const OptionalFormat value = ICE_SCOPED_ENUM(OptionalFormat, Class); }; /** * Specialization for enum types. * \headerfile Ice/Ice.h */ template struct GetOptionalFormat { static const OptionalFormat value = ICE_SCOPED_ENUM(OptionalFormat, Size); }; /** * Base helper for optional values: simply read/write the data. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper { typedef StreamableTraits Traits; // If this optionalFormat fails to compile, you must either define your specialization // for GetOptionalFormat (in which case the optional data will be marshaled/unmarshaled // with straight calls to write/read on the stream), or define your own // StreamOptionalHelper specialization (which gives you more control over marshaling) // static const OptionalFormat optionalFormat = GetOptionalFormat::value; template static inline void write(S* stream, const T& v) { stream->write(v); } template static inline void read(S* stream, T& v) { stream->read(v); } }; /** * Helper to write fixed-size structs. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper { static const OptionalFormat optionalFormat = ICE_SCOPED_ENUM(OptionalFormat, VSize); template static inline void write(S* stream, const T& v) { stream->writeSize(StreamableTraits::minWireSize); stream->write(v); } template static inline void read(S* stream, T& v) { stream->skipSize(); stream->read(v); } }; /** * Helper to write variable-size structs. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper { static const OptionalFormat optionalFormat = ICE_SCOPED_ENUM(OptionalFormat, FSize); template static inline void write(S* stream, const T& v) { typename S::size_type pos = stream->startSize(); stream->write(v); stream->endSize(pos); } template static inline void read(S* stream, T& v) { stream->skip(4); stream->read(v); } }; /** * Class structs are encoded like structs. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper : StreamOptionalHelper { }; /** * Optional proxies are encoded like variable size structs, using the FSize encoding. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper : StreamOptionalHelper { }; /** * Helper to read/write optional sequences or dictionaries. * \headerfile Ice/Ice.h */ template struct StreamOptionalContainerHelper; /** * Encode containers of variable-size elements with the FSize optional * type, since we can't easily figure out the size of the container * before encoding. This is the same encoding as variable size structs * so we just re-use its implementation. * \headerfile Ice/Ice.h */ template struct StreamOptionalContainerHelper { static const OptionalFormat optionalFormat = ICE_SCOPED_ENUM(OptionalFormat, FSize); template static inline void write(S* stream, const T& v, Int) { StreamOptionalHelper::write(stream, v); } template static inline void read(S* stream, T& v) { StreamOptionalHelper::read(stream, v); } }; /** * Encode containers of fixed-size elements with the VSize optional * type since we can figure out the size of the container before * encoding. * \headerfile Ice/Ice.h */ template struct StreamOptionalContainerHelper { static const OptionalFormat optionalFormat = ICE_SCOPED_ENUM(OptionalFormat, VSize); template static inline void write(S* stream, const T& v, Int n) { // // The container size is the number of elements * the size of // an element and the size-encoded number of elements (1 or // 5 depending on the number of elements). // stream->writeSize(sz * n + (n < 255 ? 1 : 5)); stream->write(v); } template static inline void read(S* stream, T& v) { stream->skipSize(); stream->read(v); } }; /** * Optimization: containers of 1 byte elements are encoded with the * VSize optional type. There's no need to encode an additional size * for those, the number of elements of the container can be used to * skip the optional. * \headerfile Ice/Ice.h */ template struct StreamOptionalContainerHelper { static const OptionalFormat optionalFormat = ICE_SCOPED_ENUM(OptionalFormat, VSize); template static inline void write(S* stream, const T& v, Int) { stream->write(v); } template static inline void read(S* stream, T& v) { stream->read(v); } }; /** * Helper to write sequences, delegates to the optional container * helper template partial specializations. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper { typedef typename T::value_type E; static const int size = StreamableTraits::minWireSize; static const bool fixedLength = StreamableTraits::fixedLength; // The optional type of a sequence depends on whether or not elements are fixed // or variable size elements and their size. static const OptionalFormat optionalFormat = StreamOptionalContainerHelper::optionalFormat; template static inline void write(S* stream, const T& v) { StreamOptionalContainerHelper::write(stream, v, static_cast(v.size())); } template static inline void read(S* stream, T& v) { StreamOptionalContainerHelper::read(stream, v); } }; /** * Helper to write sequences, delegates to the optional container * helper template partial specializations. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper, StreamHelperCategorySequence, false> { typedef std::pair P; static const int size = StreamableTraits::minWireSize; static const bool fixedLength = StreamableTraits::fixedLength; // The optional type of a sequence depends on whether or not elements are fixed // or variable size elements and their size. static const OptionalFormat optionalFormat = StreamOptionalContainerHelper::optionalFormat; template static inline void write(S* stream, const P& v) { Int n = static_cast(v.second - v.first); StreamOptionalContainerHelper::write(stream, v, n); } template static inline void read(S* stream, P& v) { StreamOptionalContainerHelper::read(stream, v); } }; #ifndef ICE_CPP11_MAPPING /** * Helper to write sequences, delegates to the optional container * helper template partial specializations. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper, StreamHelperCategorySequence, false> { typedef std::pair P; static const int size = StreamableTraits::minWireSize; static const bool fixedLength = StreamableTraits::fixedLength; // The optional type of a sequence depends on whether or not elements are fixed // or variable size elements and their size. static const OptionalFormat optionalFormat = StreamOptionalContainerHelper::optionalFormat; template static inline void write(S* stream, const P& v) { Int n = static_cast(v.second - v.first); StreamOptionalContainerHelper::write(stream, v, n); } template static inline void read(S* stream, P& v) { StreamOptionalContainerHelper::read(stream, v); } }; /** * Helper to write sequences, delegates to the optional container * helper template partial specializations. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper, std::pair >, StreamHelperCategorySequence, false> { typedef std::pair, std::pair > P; static const int size = StreamableTraits::minWireSize; static const bool fixedLength = StreamableTraits::fixedLength; // The optional type of a sequence depends on whether or not elements are fixed // or variable size elements and their size. static const OptionalFormat optionalFormat = StreamOptionalContainerHelper::optionalFormat; template static inline void read(S* stream, P& v) { StreamOptionalContainerHelper::read(stream, v); } // no write: only used for unmarshaling }; #endif /** * Helper to write dictionaries, delegates to the optional container * helper template partial specializations. * \headerfile Ice/Ice.h */ template struct StreamOptionalHelper { typedef typename T::key_type K; typedef typename T::mapped_type V; static const int size = StreamableTraits::minWireSize + StreamableTraits::minWireSize; static const bool fixedLength = StreamableTraits::fixedLength && StreamableTraits::fixedLength; // The optional type of a dictionary depends on whether or not elements are fixed // or variable size elements. static const OptionalFormat optionalFormat = StreamOptionalContainerHelper::optionalFormat; template static inline void write(S* stream, const T& v) { StreamOptionalContainerHelper::write(stream, v, static_cast(v.size())); } template static inline void read(S* stream, T& v) { StreamOptionalContainerHelper::read(stream, v); } }; /// \endcond } #endif