diff options
author | Bernard Normier <bernard@zeroc.com> | 2012-09-25 22:35:10 +0000 |
---|---|---|
committer | Bernard Normier <bernard@zeroc.com> | 2012-09-25 22:35:10 +0000 |
commit | 4a55d7d891bad0b123ebdb7e253740f4d1b4b2eb (patch) | |
tree | f4a631d7a152edfb86a70a3841e2b136fbaf904f /cpp/include/Ice/StreamHelpers.h | |
parent | Ruby port; Python & C++ fixes (diff) | |
download | ice-4a55d7d891bad0b123ebdb7e253740f4d1b4b2eb.tar.bz2 ice-4a55d7d891bad0b123ebdb7e253740f4d1b4b2eb.tar.xz ice-4a55d7d891bad0b123ebdb7e253740f4d1b4b2eb.zip |
Renamings (ICE-4868):
- StreamTrait is now StreamableTraits
- StreamTraitType is now StreamHelperCategory
- OptionalType is now OptionalFormat
- Ice/StreamTraits.h is now Ice/StreamHelpers.h
Updated C++, Python and Ruby
Updated .depend and .depend.mak in C++, Python, Ruby and PHP
Diffstat (limited to 'cpp/include/Ice/StreamHelpers.h')
-rw-r--r-- | cpp/include/Ice/StreamHelpers.h | 867 |
1 files changed, 867 insertions, 0 deletions
diff --git a/cpp/include/Ice/StreamHelpers.h b/cpp/include/Ice/StreamHelpers.h new file mode 100644 index 00000000000..e075276de3d --- /dev/null +++ b/cpp/include/Ice/StreamHelpers.h @@ -0,0 +1,867 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2012 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_TRAITS_H +#define ICE_STREAM_TRAITS_H + +#include <IceUtil/ScopedArray.h> +#include <IceUtil/Iterator.h> + +#include <Ice/ObjectF.h> + +namespace Ice +{ + +// The stream helper category +// Allows streams to select the desired StreamHelper for a given streamable object; +// see StreamableTraits below. +// + +typedef int StreamHelperCategory; + +const StreamHelperCategory StreamHelperCategoryUnknown = 0; +const StreamHelperCategory StreamHelperCategoryBuiltin = 1; +const StreamHelperCategory StreamHelperCategoryStruct = 2; +const StreamHelperCategory StreamHelperCategoryStructClass = 3; // struct with cpp:class metadata +const StreamHelperCategory StreamHelperCategoryEnum = 4; +const StreamHelperCategory StreamHelperCategorySequence = 5; +const StreamHelperCategory StreamHelperCategoryDictionary = 6; +const StreamHelperCategory StreamHelperCategoryProxy = 7; +const StreamHelperCategory StreamHelperCategoryClass = 8; +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 +// isn't known to the receiver. +// +enum OptionalFormat +{ + OptionalFormatF1 = 0, // Fixed 1-byte encoding + OptionalFormatF2 = 1, // Fixed 2 bytes encoding + OptionalFormatF4 = 2, // Fixed 4 bytes encoding + OptionalFormatF8 = 3, // Fixed 8 bytes encoding + OptionalFormatSize = 4, // "Size encoding" on 1 to 5 bytes, e.g. enum, class identifier + OptionalFormatVSize = 5, // "Size encoding" on 1 to 5 bytes followed by data, e.g. string, fixed size struct, + // or containers whose size can be computed prior to marshaling + OptionalFormatFSize = 6, // Fixed size on 4 bytes followed by data, e.g. variable-size struct, container. + OptionalFormatEndMarker = 7 +}; + + +// +// Is the provided type a container? +// For now, the implementation only checks if there is a T::iterator typedef +// using SFINAE +// +template<typename T> +struct IsContainer +{ + template<typename C> + static char test(typename C::iterator*); + + template<typename C> + static long test(...); + + static const bool value = sizeof(test<T>(0)) == sizeof(char); +}; + +// +// Is the provided type a map? +// For now, the implementation only checks if there is a T::mapped_type typedef +// using SFINAE +// +template<typename T> +struct IsMap +{ + template<typename C> + static char test(typename C::mapped_type*); + + template<typename C> + static long test(...); + + static const bool value = IsContainer<T>::value && sizeof(test<T>(0)) == sizeof(char); +}; + +// +// Base traits template. +// Types with no specialized trait use this trait. +// +template<typename T, typename Enabler = void> +struct StreamableTraits +{ + static const StreamHelperCategory helper = IsMap<T>::value ? StreamHelperCategoryDictionary : + (IsContainer<T>::value ? StreamHelperCategorySequence : StreamHelperCategoryUnknown); + + // + // When extracting a sequence<T> from a stream, we can ensure the + // stream has at least StreamableTraits<T>::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; +}; + +// +// StreamableTraits specialization for array / range mapped sequences +// The type can be a std::pair<T, T> or a +// std::pair<IceUtil::ScopedArray<T>, std::pair<const T*, const T*> > +// +template<typename T, typename U> +struct StreamableTraits< ::std::pair<T, U> > +{ + static const StreamHelperCategory helper = StreamHelperCategorySequence; + static const int minWireSize = 1; + static const bool fixedLength = false; +}; + +// +// StreamableTraits specialization for user exceptions. +// +template<> +struct StreamableTraits<UserException> +{ + 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) + // +}; + + +// +// StreamableTraits specialization for builtins (these are needed for sequence +// marshaling to figure out the minWireSize of each built-in). +// +template<> +struct StreamableTraits<bool> +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 1; + static const bool fixedLength = true; +}; + +template<> +struct StreamableTraits<Byte> +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 1; + static const bool fixedLength = true; +}; + +template<> +struct StreamableTraits<Short> +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 2; + static const bool fixedLength = true; +}; + +template<> +struct StreamableTraits<Int> +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 4; + static const bool fixedLength = true; +}; + +template<> +struct StreamableTraits<Long> +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 8; + static const bool fixedLength = true; +}; + +template<> +struct StreamableTraits<Float> +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 4; + static const bool fixedLength = true; +}; + +template<> +struct StreamableTraits<Double> +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 8; + static const bool fixedLength = true; +}; + +template<> +struct StreamableTraits< ::std::string> +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 1; + static const bool fixedLength = false; +}; + +template<> +struct StreamableTraits< ::std::wstring> +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 1; + static const bool fixedLength = false; +}; + +// +// vector<bool> is a special type in C++: the streams are responsible +// to handle it like a built-in type. +// +template<> +struct StreamableTraits< ::std::vector<bool> > +{ + static const StreamHelperCategory helper = StreamHelperCategoryBuiltin; + static const int minWireSize = 1; + static const bool fixedLength = false; +}; + + +template<typename T> +struct StreamableTraits< ::IceInternal::ProxyHandle<T> > +{ + static const StreamHelperCategory helper = StreamHelperCategoryProxy; + static const int minWireSize = 2; + static const bool fixedLength = false; +}; + +template<typename T> +struct StreamableTraits< ::IceInternal::Handle<T> > +{ + static const StreamHelperCategory helper = StreamHelperCategoryClass; + static const int minWireSize = 1; + static const bool fixedLength = false; +}; + +// +// StreamHelper templates used by streams to read and write data. +// + +// Base StreamHelper template; it must be specialized for each type +template<typename T, StreamHelperCategory st> +struct StreamHelper; + + +// Helper for builtins, delegates read/write to the stream. +template<typename T> +struct StreamHelper<T, StreamHelperCategoryBuiltin> +{ + template<class S> static inline void + write(S* stream, const T& v) + { + stream->write(v); + } + + template<class S> static inline void + read(S* stream, T& v) + { + stream->read(v); + } +}; + +// Helper for structs, uses generated __read/__write methods +template<typename T> +struct StreamHelper<T, StreamHelperCategoryStruct> +{ + template<class S> static inline void + write(S* stream, const T& v) + { + v.__write(stream); + } + + template<class S> static inline void + read(S* stream, T& v) + { + v.__read(stream); + } +}; + +// Helper for class structs, uses generated __read/__write methods +template<typename T> +struct StreamHelper<T, StreamHelperCategoryStructClass> +{ + template<class S> static inline void + write(S* stream, const T& v) + { + v->__write(stream); + } + + template<class S> static inline void + read(S* stream, T& v) + { + v = new typename T::element_type(); + v->__read(stream); + } +}; + +// Helper for enums +template<typename T> +struct StreamHelper<T, StreamHelperCategoryEnum> +{ + template<class S> static inline void + write(S* stream, const T& v) + { + if(static_cast<Int>(v) < 0 || static_cast<Int>(v) >= StreamableTraits<T>::enumLimit) + { + IceInternal::Ex::throwMarshalException(__FILE__, __LINE__, "enumerator out of range"); + } + stream->writeEnum(static_cast<Int>(v), StreamableTraits<T>::enumLimit); + } + + template<class S> static inline void + read(S* stream, T& v) + { + Int value = stream->readEnum(StreamableTraits<T>::enumLimit); + if(value < 0 || value >= StreamableTraits<T>::enumLimit) + { + IceInternal::Ex::throwMarshalException(__FILE__, __LINE__, "enumerator out of range"); + } + v = static_cast<T>(value); + } +}; + +// Helper for sequences +template<typename T> +struct StreamHelper<T, StreamHelperCategorySequence> +{ + template<class S> static inline void + write(S* stream, const T& v) + { + stream->writeSize(static_cast<Int>(v.size())); + for(typename T::const_iterator p = v.begin(); p != v.end(); ++p) + { + stream->write(*p); + } + } + + template<class S> static inline void + read(S* stream, T& v) + { + Int sz = stream->readAndCheckSeqSize(StreamableTraits<typename T::value_type>::minWireSize); + T(sz).swap(v); + for(typename T::iterator p = v.begin(); p != v.end(); ++p) + { + stream->read(*p); + } + } +}; + +// Helper for array and range:array custom sequence parameters +template<typename T> +struct StreamHelper<std::pair<const T*, const T*>, StreamHelperCategorySequence> +{ + template<class S> static inline void + write(S* stream, const std::pair<const T*, const T*>& v) + { + stream->write(v.first, v.second); + } + + template<class S> static inline void + read(S* stream, std::pair<const T*, const T*>& v) + { + stream->read(v); + } +}; + +// Helper for range custom sequence parameters +template<typename T> +struct StreamHelper<std::pair<T, T>, StreamHelperCategorySequence> +{ + template<class S> static inline void + write(S* stream, const std::pair<T, T>& v) + { + stream->writeSize(static_cast<Int>(IceUtilInternal::distance(v.first, v.second))); + for(T p = v.first; p != v.second; ++p) + { + stream->write(*p); + } + } + + template<class S> static inline void + read(S* stream, std::pair<T, T>& v) + { + stream->read(v); + } +}; + +template<> +struct StreamHelper<std::pair< ::std::vector<bool>::const_iterator, + ::std::vector<bool>::const_iterator>, StreamHelperCategorySequence> +{ + template<class S> static inline void + write(S* stream, const std::pair< ::std::vector<bool>::const_iterator, + ::std::vector<bool>::const_iterator>& v) + { + stream->writeSize(static_cast<Int>(IceUtilInternal::distance(v.first, v.second))); + for(::std::vector<bool>::const_iterator p = v.first; p != v.second; ++p) + { + stream->write(static_cast<bool>(*p)); + } + } + + // no read: only used for marshaling +}; + +// Helper for zero-copy array sequence parameters +template<typename T> +struct StreamHelper<std::pair<IceUtil::ScopedArray<T>, std::pair<const T*, const T*> >, StreamHelperCategorySequence> +{ + template<class S> static inline void + read(S* stream, std::pair<IceUtil::ScopedArray<T>, std::pair<const T*, const T*> >& v) + { + v.first.reset(stream->read(v.second)); + } + + // no write: only used for unmarshaling +}; + +// Helper for dictionaries +template<typename T> +struct StreamHelper<T, StreamHelperCategoryDictionary> +{ + template<class S> static inline void + write(S* stream, const T& v) + { + stream->writeSize(static_cast<Int>(v.size())); + for(typename T::const_iterator p = v.begin(); p != v.end(); ++p) + { + stream->write(p->first); + stream->write(p->second); + } + } + + template<class S> 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<typename T::key_type&>(p.first)); + typename T::iterator i = v.insert(v.end(), p); + stream->read(i->second); + } + } +}; + +// Helper for user exceptions +template<typename T> +struct StreamHelper<T, StreamHelperCategoryUserException> +{ + template<class S> static inline void + write(S* stream, const T& v) + { + stream->writeException(v); + } + + // no read: only used for marshaling +}; + +// Helper for proxies +template<typename T> +struct StreamHelper<T, StreamHelperCategoryProxy> +{ + template<class S> static inline void + write(S* stream, const T& v) + { + stream->write(v); + } + + template<class S> static inline void + read(S* stream, T& v) + { + stream->read(v); + } +}; + +// Helper for classes +template<typename T> +struct StreamHelper<T, StreamHelperCategoryClass> +{ + template<class S> static inline void + write(S* stream, const T& v) + { + stream->write(v); + } + + template<class S> 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 +// +template<StreamHelperCategory st, int minWireSize, bool fixedLength> +struct GetOptionalFormat; + +template<> +struct GetOptionalFormat<StreamHelperCategoryBuiltin, 1, true> +{ + static const OptionalFormat value = OptionalFormatF1; +}; + +template<> +struct GetOptionalFormat<StreamHelperCategoryBuiltin, 2, true> +{ + static const OptionalFormat value = OptionalFormatF2; +}; + +template<> +struct GetOptionalFormat<StreamHelperCategoryBuiltin, 4, true> +{ + static const OptionalFormat value = OptionalFormatF4; +}; + +template<> +struct GetOptionalFormat<StreamHelperCategoryBuiltin, 8, true> +{ + static const OptionalFormat value = OptionalFormatF8; +}; + +template<> +struct GetOptionalFormat<StreamHelperCategoryBuiltin, 1, false> +{ + static const OptionalFormat value = OptionalFormatVSize; +}; + +template<> +struct GetOptionalFormat<StreamHelperCategoryClass, 1, false> +{ + static const OptionalFormat value = OptionalFormatSize; +}; + +template<int minWireSize> +struct GetOptionalFormat<StreamHelperCategoryEnum, minWireSize, false> +{ + static const OptionalFormat value = OptionalFormatSize; +}; + + +// Base helper: simply read/write the data +template<typename T, StreamHelperCategory st, bool fixedLength> +struct StreamOptionalHelper +{ + typedef StreamableTraits<T> 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<st, Traits::minWireSize, fixedLength>::value; + + template<class S> static inline void + write(S* stream, const T& v) + { + stream->write(v); + } + + template<class S> static inline void + read(S* stream, T& v) + { + stream->read(v); + } +}; + +// Helper to write fixed size structs +template<typename T> +struct StreamOptionalHelper<T, StreamHelperCategoryStruct, true> +{ + static const OptionalFormat optionalFormat = OptionalFormatVSize; + + template<class S> static inline void + write(S* stream, const T& v) + { + stream->writeSize(StreamableTraits<T>::minWireSize); + stream->write(v); + } + + template<class S> static inline void + read(S* stream, T& v) + { + stream->skipSize(); + stream->read(v); + } +}; + +// Helper to write variable size structs +template<typename T> +struct StreamOptionalHelper<T, StreamHelperCategoryStruct, false> +{ + static const OptionalFormat optionalFormat = OptionalFormatFSize; + + template<class S> static inline void + write(S* stream, const T& v) + { + stream->write(static_cast<Int>(0)); + typename S::size_type p = stream->pos(); + stream->write(v); + stream->rewrite(static_cast<Int>(stream->pos() - p), p - 4); + } + + template<class S> static inline void + read(S* stream, T& v) + { + stream->skip(4); + stream->read(v); + } +}; + +// Class structs are encoded like structs +template<typename T, bool fixedLength> +struct StreamOptionalHelper<T, StreamHelperCategoryStructClass, fixedLength> : StreamOptionalHelper<T, StreamHelperCategoryStruct, fixedLength> +{ +}; + +// Optional proxies are encoded like variable size structs, using the FSize encoding +template<typename T> +struct StreamOptionalHelper<T, StreamHelperCategoryProxy, false> : StreamOptionalHelper<T, StreamHelperCategoryStruct, false> +{ +}; + + +// +// Helpers to read/write optional sequences or dictionaries +// +template<typename T, bool fixedLength, int sz> +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. +// +template<typename T, int sz> +struct StreamOptionalContainerHelper<T, false, sz> +{ + static const OptionalFormat optionalFormat = OptionalFormatFSize; + + template<class S> static inline void + write(S* stream, const T& v, Int) + { + StreamOptionalHelper<T, StreamHelperCategoryStruct, false>::write(stream, v); + } + + template<class S> static inline void + read(S* stream, T& v) + { + StreamOptionalHelper<T, StreamHelperCategoryStruct, false>::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. +// +template<typename T, int sz> +struct StreamOptionalContainerHelper<T, true, sz> +{ + static const OptionalFormat optionalFormat = OptionalFormatVSize; + + template<class S> 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<class S> 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. +// +template<typename T> +struct StreamOptionalContainerHelper<T, true, 1> +{ + static const OptionalFormat optionalFormat = OptionalFormatVSize; + + template<class S> static inline void + write(S* stream, const T& v, Int) + { + stream->write(v); + } + + template<class S> static inline void + read(S* stream, T& v) + { + stream->read(v); + } +}; + + +// +// Helper to write sequences, delegates to the optional container +// helper template partial specializations. +// +template<typename T> +struct StreamOptionalHelper<T, StreamHelperCategorySequence, false> +{ + typedef typename T::value_type E; + static const int size = StreamableTraits<E>::minWireSize; + static const bool fixedLength = StreamableTraits<E>::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<T, fixedLength, size>::optionalFormat; + + template<class S> static inline void + write(S* stream, const T& v) + { + StreamOptionalContainerHelper<T, fixedLength, size>::write(stream, v, static_cast<Int>(v.size())); + } + + template<class S> static inline void + read(S* stream, T& v) + { + StreamOptionalContainerHelper<T, fixedLength, size>::read(stream, v); + } +}; + +template<typename T> +struct StreamOptionalHelper<std::pair<const T*, const T*>, StreamHelperCategorySequence, false> +{ + typedef std::pair<const T*, const T*> P; + static const int size = StreamableTraits<T>::minWireSize; + static const bool fixedLength = StreamableTraits<T>::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<P, fixedLength, size>::optionalFormat; + + template<class S> static inline void + write(S* stream, const P& v) + { + Int n = static_cast<Int>(v.second - v.first); + StreamOptionalContainerHelper<P, fixedLength, size>::write(stream, v, n); + } + + template<class S> static inline void + read(S* stream, P& v) + { + StreamOptionalContainerHelper<P, fixedLength, size>::read(stream, v); + } +}; + +template<typename T> +struct StreamOptionalHelper<std::pair<T, T>, StreamHelperCategorySequence, false> +{ + typedef std::pair<T, T> P; + static const int size = StreamableTraits<typename T::value_type>::minWireSize; + static const bool fixedLength = StreamableTraits<typename T::value_type>::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<P, fixedLength, size>::optionalFormat; + + template<class S> static inline void + write(S* stream, const P& v) + { + Int n = static_cast<Int>(v.second - v.first); + StreamOptionalContainerHelper<P, fixedLength, size>::write(stream, v, n); + } + + template<class S> static inline void + read(S* stream, P& v) + { + StreamOptionalContainerHelper<P, fixedLength, size>::read(stream, v); + } +}; + +template<typename T> +struct StreamOptionalHelper<std::pair<IceUtil::ScopedArray<T>, std::pair<const T*, const T*> >, + StreamHelperCategorySequence, false> +{ + typedef std::pair<IceUtil::ScopedArray<T>, std::pair<const T*, const T*> > P; + static const int size = StreamableTraits<T>::minWireSize; + static const bool fixedLength = StreamableTraits<T>::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<P, fixedLength, size>::optionalFormat; + + template<class S> static inline void + read(S* stream, P& v) + { + StreamOptionalContainerHelper<P, fixedLength, size>::read(stream, v); + } + + // no write: only used for unmarshaling +}; + +// +// Helper to write dictionaries, delegates to the optional container +// helper template partial specializations. +// +template<typename T> +struct StreamOptionalHelper<T, StreamHelperCategoryDictionary, false> +{ + typedef typename T::key_type K; + typedef typename T::mapped_type V; + + static const int size = StreamableTraits<K>::minWireSize + StreamableTraits<V>::minWireSize; + static const bool fixedLength = StreamableTraits<K>::fixedLength && StreamableTraits<V>::fixedLength; + + // The optional type of a dictionary depends on whether or not elements are fixed + // or variable size elements. + static const OptionalFormat optionalFormat = StreamOptionalContainerHelper<T, fixedLength, size>::optionalFormat; + + template<class S> static inline void + write(S* stream, const T& v) + { + StreamOptionalContainerHelper<T, fixedLength, size>::write(stream, v, static_cast<Int>(v.size())); + } + + template<class S> static inline void + read(S* stream, T& v) + { + StreamOptionalContainerHelper<T, fixedLength, size>::read(stream, v); + } +}; + +} + +#endif |