There are two templated stream operators, operator<<
and operator>>
that can be used to externalise and internalise data of all types. They use a syntax that is familiar to users of C++ iostreams, or Java streams.
An object can be externalised to a stream, using a write stream:
writeStream << object;
and later, assuming the operation starts from the appropriate place on the stream, the data can be internalised again, using a read stream:
readStream >> object;
The implementation of the operators depends on the type of object on which they are called.
For a class that defines and implements the ExternalizeL()
and InternalizeL()
functions, the Store framework:
The Store framework provides the necessary implementation for the operators to externalise and internalise the following:
For non-class types, for example enumerators, a specialized implementation of the operators must be defined and implemented for that specific non-class type. The definition of the operators must conform to the templated definitions.
For example, for a class TSimple
that contains an enumeration of type TXxx
as a data member:
enum TXxx {EX1,EX2,EX3};
class TSimple { public : void ExternalizeL(RWriteStream& aStream) const; void InternalizeL(RReadStream& aStream); public : TXxx iTheEnum; ... TUint iUintValue; ... };
The iTheEnum
data member is externalised using operator<<
and internalised using operator>>
:
void TSimple::ExternalizeL(RWriteStream& aStream) const { aStream << iTheEnum; ... }
void TSimple::InternalizeL(RReadStream& aStream) { aStream >> iTheEnum; ... }
As TXxx
is a non-class type, the operators are implemented:
RWriteStream& operator<<(RWriteStream& aStream, const TXxx& anXxx) { aStream.WriteInt8L(anXxx); return aStream; }
RReadStream& operator>>(RReadStream& aStream, TXxx& anXxx) { anXxx = TXxx(aStream.ReadInt8L()); return aStream; }
The enumerator value is written to the stream using RWriteStream::WriteInt8L()
. Implicit here is the assumption that the enumeration can be represented by just 8 bits.
The operators may be used on class types that do not define and implement InternalizeL()
and ExternalizeL()
functions. This is done by defining and implementing some extra global functions.
In practice, it is much simpler to define and implement InternlizeL()
and ExternalizeL()
for a class, and all new classes should include these functions. However, there may be rare situations, for example, when porting classes, where it may be undesirable to define them.
To support the use of the operators for such a class, for example, for the class TNonStore
defined as:
class TNonStore { public : void SetBuffer(const TDesC& aData); TPtrC GetBuffer() const; private : TBuf<32> iBuffer; public : TInt iIntValue; TUint iUintValue; TReal iRealValue; };
implement the following Externalization()
and Internalization()
global functions:
inline Externalize::Function Externalization(const TNonstore*) {return Externalize::Function();}
inline Internalize::Function Internalization(TNonstore*) {return Internalize::Function();}
declare the following ExternalizeL()
and InternalizeL()
global functions:
void ExternalizeL(const TNonstore& aClass,RWriteStream& aStream);
void InternalizeL(TNonstore& aClass,RReadStream& aStream);
implement the ExternalizeL()
and InternalizeL()
global functions to implement the streaming of TNonstore
's components. For this example class:
void ExternalizeL(const TNonStore& aClass,RWriteStream& aStream) { aStream.WriteInt32L(aClass.iIntValue); aStream.WriteUint32L(aClass.iUintValue); aStream.WriteReal64L(aClass.iRealValue); aStream << aClass.GetBuffer(); } void InternalizeL(TNonStore& aClass,RReadStream& aStream) { aClass.iIntValue = aStream.ReadInt32L(); aClass.iUintValue = aStream.ReadUint32L(); aClass.iRealValue = aStream.ReadReal64L(); TBuf<32> temp; aStream >> temp; aClass.SetBuffer(temp); }