The OutputStream Interface in C++
On this page:
Initializing an OutputStream
in C++
The OutputStream
class provides a number of overloaded constructors:
namespace Ice { class OutputStream { public: OutputStream(); OutputStream(const std::shared_ptr<Communicator>& communicator); OutputStream(const std::shared_ptr<Communicator>& communicator, const EncodingVersion& version); OutputStream(const std::shared_ptr<Communicator>& communicator, const EncodingVersion& version, const std::pair<const Byte*, const Byte*>& buf); }; }
namespace Ice { class OutputStream { public: OutputStream(); OutputStream(const CommunicatorPtr& communicator); OutputStream(const CommunicatorPtr& communicator, const EncodingVersion& version); OutputStream(const CommunicatorPtr& communicator, const EncodingVersion& version, const std::pair<const Byte*, const Byte*>& buf); }; }
The constructors optionally accept the following arguments:
- A communicator instance
- An encoding version
- A pair of bytes denoting the beginning and end of a memory block to be used as the stream's initial marshaling buffer. This is useful to avoid memory allocations when the size of the encoded data is predictable. The stream will automatically allocate a larger buffer if the encoded data exceeds the size of the given memory block.
We recommend supplying a communicator instance. The stream inspects the communicator's settings to configure several of its own default settings, but you can optionally configure these settings manually using functions that we'll describe later.
If you omit an encoding version, the stream uses the default encoding version of the communicator (if provided) or the most recent encoding version.
Instances of OutputStream
can be allocated statically or dynamically.
If a communicator instance is not available at the time you construct the stream, you can optionally supply it later using one of the overloaded initialize
functions:
class OutputStream { public: void initialize(const std::shared_ptr<Communicator>& communicator); void initialize(const std::shared_ptr<Communicator>& communicator, const EncodingVersion& version); ... };
class OutputStream { public: void initialize(const CommunicatorPtr& communicator); void initialize(const CommunicatorPtr& communicator, const EncodingVersion& version); ... };
Invoking initialize
causes the stream to re-initialize its settings based on the configuration of the given communicator.
Use the following function to manually configure the stream:
class OutputStream { public: void setFormat(FormatType); ... };
For instances of Slice classes, the format determines how the slices of an instance are encoded. If the stream is initialized with a communicator, this setting defaults to the value of Ice.Default.SlicedFormat
, otherwise the setting defaults to the compact format.
Inserting into an OutputStream
in C++
OutputStream
provides a number of overloaded write
member functions that allow you to insert any parameter into the stream simply by calling write
.
For example, you can insert a double value followed by a string into a stream as follows:
Ice::OutputStream out(communicator); Ice::Double d = 3.14; out.write(d); string s = "Hello"; out.write(s);
Likewise, you can insert a sequence of built-in type, or a complex, with the same syntax:
Ice::OutputStream out(communicator); IntSeq s = ...; out.write(s); ComplexType c = ...; out.write(c);
With the C++11 mapping, you can also write a list of parameters in one call with writeAll.
For example, the previous sample can be rewritten as:
Ice::OutputStream out(communicator); IntSeq s = ...; ComplexType c = ...; out.writeAll(s, c);
Here are the functions for inserting data into an stream:
class OutputStream : ... { public: void write(bool); void write(Byte); void write(short); void write(int); void write(long long int); void write(float); void write(double); void write(const std::string&, bool = true); void write(const char*, size_t, bool = true); void write(const char*, bool = true); void write(const std::string*, const std::string*, bool = true); void write(const std::wstring&); void write(const std::wstring*, const std::wstring*); template<typename T> void write(const std::vector<T>& v); template<typename T> void write(const T* begin, const T* end); void writeBlob(const std::vector<Byte>&); void writeBlob(const Byte* v, size_type sz); void writeEnum(int v, int maxValue); bool writeOptional(int tag, OptionalFormat fmt); template<typename T> void write(int tag, const Optional<T>& v); template<typename T> void write(const T& v); // Insert a proxy of the base type void writeProxy(const std::shared_ptr<ObjectPrx>&); // Insert a proxy of a user-defined interface type template</* T is-a ObjectPrx */> void write(const std::shared_ptr<T>& v); // Insert an instance of a Slice class template</* T is-a Value */> void write(const std::shared_ptr<T>& v); void startValue(const std::shared_ptr<SlicedData>& sd); void endValue(); void startException(const std::shared_ptr<SlicedData>& sd); void endException(); // Write all parameters in one call template<typename T> void writeAll(const T& v); template<typename T, typename... Te> void writeAll(const T& v, const Te&... ve); // Write all optional parameters in one call template<typename T> void writeAll(std::initializer_list<int> tags, const Optional<T>& v); template<typename T, typename... Te> void writeAll(std::initializer_list<int> tags, const Optional<T>& v, const Optional<Te>&... ve); void writeSize(int sz); size_type startSize(); void endSize(size_type pos); void rewriteSize(int v, iterator dest); void write(int v, iterator dest); void rewrite(int v, size_type pos); void writeException(const UserException& e); void startSlice(const std::string& typeId, int compactId, bool last); void endSlice(); void startEncapsulation(const EncodingVersion& v, FormatType fmt); void startEncapsulation(); void endEncapsulation(); void writeEmptyEncapsulation(const EncodingVersion& v); void writeEncapsulation(const Byte* v, int sz); EncodingVersion getEncoding() const; void writePendingValues(); void finished(std::vector<Byte>& v); std::pair<const Byte*, const Byte*> finished(); void resize(size_type sz); size_type pos(); void pos(size_type n); };
class OutputStream : ... { public: void write(bool); void write(Byte); void write(short); void write(int); void write(long long int); void write(float); void write(double); void write(const std::string&, bool = true); void write(const char*, size_t, bool = true); void write(const char*, bool = true); void write(const std::string*, const std::string*, bool = true); void write(const std::wstring&); void write(const std::wstring*, const std::wstring*); template<typename T> void write(const std::vector<T>& v); template<typename T> void write(const T* begin, const T* end); void writeBlob(const std::vector<Byte>&); void writeBlob(const Byte* v, size_type sz); void writeEnum(int v, int maxValue); bool writeOptional(int tag, OptionalFormat fmt); template<typename T> void write(int tag, const IceUtil::Optional<T>& v); template<typename T> void write(const T& v); // Insert a proxy of the base interface type void write(const ObjectPrx&); // Insert a proxy of a user-defined interface type template<typename T> void write(const ProxyHandle<T>& v); // Insert an instance of the base class type void write(const ObjectPtr& v); // Insert an instance of a user-defined class type template<typename T> void write(const Handle<T>& v); void startValue(const SlicedDataPtr& sd); void endValue(); void startException(const SlicedDataPtr& sd); void endException(); void writeSize(int sz); size_type startSize(); void endSize(size_type pos); void rewriteSize(int v, iterator dest); void write(int v, iterator dest); void rewrite(int v, size_type pos); void writeException(const UserException& e); void startSlice(const std::string& typeId, int compactId, bool last); void endSlice(); void startEncapsulation(const EncodingVersion& v, FormatType fmt); void startEncapsulation(); void endEncapsulation(); void writeEmptyEncapsulation(const EncodingVersion& v); void writeEncapsulation(const Byte* v, int sz); EncodingVersion getEncoding() const; void writePendingValues(); void finished(std::vector<Byte>& v); std::pair<const Byte*, const Byte*> finished(); void resize(size_type sz); size_type pos(); void pos(size_type n); };
Some of the OutputStream
functions need more explanation:
void write(const std::string& v, bool convert = true)
void write(const char* v, size_t vlen, bool convert = true)
void write(const char* v, bool convert = true)
void write(const std::string* beg, const std::string* end, bool convert = true)
The boolean argument determines whether the strings marshaled by these functions are processed by the narrow string converter, if one has been provided. The default behavior is to convert the strings.
template<typename T>
void write(const T* begin, const T* end)
Marshals the given range as a sequence of typeT
.
void writeBlob(const std::vector<Byte>&)
void writeBlob(const Byte* v, size_type sz)
Copies the specified blob of bytes to the stream without modification.
void writeEnum(int val, int maxValue)
Writes the integer value of an enumerator. ThemaxValue
argument represents the highest enumerator value in the enumeration. Consider the following definitions:Sliceenum Color { red, green, blue } enum Fruit { Apple, Pear=3, Orange }
The maximum value for
Color
is 2, and the maximum value forFruit
is 4.
In general, you should simply usewrite
for your enum values.write
with an enum parameter callswriteEnum
with themaxValue
provided by the code generated byslice2cpp
.
bool writeOptional(int tag, OptionalFormat fmt)
Prepares the stream to write an optional value with the given tag and format. Returns true if the value should be written, or false otherwise. A return value of false indicates that the encoding version in use by the stream does not support optional values. If this function returns true, the data associated with that optional value must be written next. Optional values must be written in order by tag from least to greatest. TheOptionalFormat
enumeration is defined as follows:enum class OptionalFormat : unsigned char { F1 = 0, // Fixed 1-byte encoding F2 = 1, // Fixed 2 bytes encoding F4 = 2, // Fixed 4 bytes encoding F8 = 3, // Fixed 8 bytes encoding Size = 4, // "Size encoding" on 1 to 5 bytes, e.g. enum, class identifier VSize = 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 FSize = 6, // Fixed size on 4 bytes followed by data, e.g. variable-size struct, container. Class = 7 };
enum OptionalFormat { OptionalFormatF1 = 0, // see C++11 OptionalFormatF2 = 1, OptionalFormatF4 = 2, OptionalFormatF8 = 3, OptionalFormatSize = 4, OptionalFormatVSize = 5, OptionalFormatFSize = 6, OptionalFormatClass = 7 };
Refer to the encoding discussion for more information on the meaning of these values.
template<typename T>
void write(int tag, const Ice::Optional<T>& v) (C++11)
template<typename T>
void write(int tag, const IceUtil::Optional<T>& v) (C++98)
If the given optional value is set, this function writes the optional with its value.
void writeSize(int sz)
The Ice encoding has a compact representation to indicate size. This function converts the given non-negative integer into the proper encoded representation.
size_type startSize()
void endSize(size_type pos)
The encoding for optional values uses a 32-bit integer to hold the size of variable-length types. CallingstartSize
writes a placeholder value for the size and returns the starting position of the size value; after writing the data, callendSize
to patch the placeholder with the actual size at the given position.
void rewriteSize(int v, iterator dest)
Replaces a size value at the given destination in the stream. This function does not change the stream's current position.
void write(int v, iterator dest)
void rewrite(int v, size_type pos)
Overwrite a 32-bit integer value at the given destination or position in the stream. These functions do not change the stream's current position.
Inserts a proxy into the stream.void writeProxy(const std::shared_ptr<ObjectPrx>&) (C++11)
template</* T is-a ObjectPrx */> void write(const std::shared_ptr<T>& v) (C++11)
void write(const ObjectPrx&) (C++98)
template<typename T> void write(const ProxyHandle<T>& v) (C++98)
template</* T is-a Value */> void write(const std::shared_ptr<T>& v) (C++11)
void write(const ObjectPtr& v) (C++98)
template<typename T> void write(const Handle<T>& v) (C++98)
Inserts an instance of a Slice class. The Ice encoding for class instances may cause the insertion of this instance to be delayed, in which case the stream retains a reference to the given instance and the stream does not insert its state it untilwritePendingValues
is invoked on the stream.
void writeException(const Ice::UserException& ex)
Inserts a user exception. It is equivalent to callingwrite
with a user exception.
void startValue(const std::shared_ptr<SlicedData>& sd) (C++11)
void startValue(const SlicedDataPtr& sd) (C++98)
void endValue()
When marshaling the slices of a class instance, the application must first callstartValue
, then marshal the slices, and finally callendValue
. The caller can pass aSlicedData
object containing the preserved slices of unknown more-derived types, or 0 if there are no preserved slices.
void startException(const std::shared_ptr<SlicedData>& sd) (C++11)
void startException(const SlicedDataPtr& sd)
(C++98)void endException()
When marshaling the slices of an exception, the application must first callstartException
, then marshal the slices, and finally callendException
. The caller can pass aSlicedData
object containing the preserved slices of unknown more-derived types, or 0 if there are no preserved slices.
void startSlice(const std::string& typeId, int compactId, bool last
)
void endSlice()
Starts and ends a slice of class or exception member data. The call tostartSlice
must include the type ID for the current slice, the corresponding compact ID for the type (if any), and a boolean indicating whether this is the last slice of the class instance or exception. The compact ID is only relevant for class instances; pass a negative value to indicate the encoding should use the string type ID.
void startEncapsulation(const EncodingVersion& v, FormatType fmt
)
void startEncapsulation()void endEncapsulation()
Starts and ends an encapsulation, respectively. The first overloading ofstartEncapsulation
allows you to specify the encoding version as well as the format to use for any class instances and exceptions marshaled within this encapsulation.
void writeEmptyEncapsulation(const EncodingVersion& v)
Writes an encapsulation having the given encoding version with no encoded data.
void writeEncapsulation(const Byte* v, int sz)
Copies the bytes representing an encapsulation from the given address into the stream.
EncodingVersion getEncoding()
Returns the encoding version currently being used by the stream.
void writePendingValues()
Encodes the state of class instances whose insertion was delayed during a previous call towrite
. With encoding version 1.0, this function must only be called exactly once when non-optional data members or parameters use class types. This function is no-op with encoding version 1.1.
void finished(std::vector<Byte>& data)
std::pair<const Byte*, const Byte*> finished()
Indicates that marshaling is complete. This member function must only be called once. In the first overloading, the given byte sequence is filled with a copy of the encoded data. The second overloading avoids a copy by returning a pair of pointers to the stream's internal memory; these pointers are valid for the lifetime of theOutputStream
object.
void resize(size_type sz)
Allocates space forsz
more bytes in the buffer. The stream implementation internally uses this function prior to copying more data into the buffer.
size_type pos()
void pos(size_type n)
Returns or changes the stream's current position, respectively.