blob: f839ba610ea29000da12a09fad4cd5645423f4e6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "geode_defs.hpp"
#include "begin_native.hpp"
#include <geode/DataOutput.hpp>
#include "end_native.hpp"
#include "native_conditional_unique_ptr.hpp"
#include "Log.hpp"
#include "ExceptionTypes.hpp"
#include "Serializable.hpp"
#include "CacheableString.hpp"
#include "CacheableDate.hpp"
#include "CacheableVector.hpp"
#include "CacheableArrayList.hpp"
#include "CacheableStack.hpp"
using namespace System;
using namespace System::Runtime::CompilerServices;
namespace Apache
{
namespace Geode
{
namespace Client
{
namespace native = apache::geode::client;
ref class Cache;
interface class ISerializable;
/// <summary>
/// Provides operations for writing primitive data values, and
/// user-defined objects implementing ISerializable, to a byte stream.
/// This class is intentionally not thread safe.
/// </summary>
public ref class DataOutput sealed
{
private:
System::Int32 m_cursor;
bool m_isManagedObject;
System::Byte * m_bytes;
System::Int32 m_remainingBufferLength;
bool m_ispdxSerialization;
native_conditional_unique_ptr<native::DataOutput>^ m_nativeptr;
Apache::Geode::Client::Cache^ m_cache;
public:
/// <summary>
/// Default constructor.
/// </summary>
DataOutput(Apache::Geode::Client::Cache^ cache);
/// <summary>
/// Write length of the array to the <c>DataOutput</c>.
/// </summary>
/// <param name="len">Array len to write.</param>
void WriteArrayLen( System::Int32 len );
/// <summary>
/// Write a signed byte to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The signed byte to write.</param>
void WriteSByte( SByte value );
/// <summary>
/// Write a boolean value to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The boolean value to write.</param>
void WriteBoolean( bool value );
/// <summary>
/// Write a char value to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The char value to write.</param>
void WriteChar( Char value );
/// <summary>
/// Write a given length of bytes to the <c>DataOutput</c>.
/// </summary>
/// <param name="bytes">The array of bytes to write.</param>
/// <param name="len">
/// The number of bytes from the start of array to write.
/// </param>
void WriteBytes( array<Byte>^ bytes, System::Int32 len );
/// <summary>
/// Write an array of bytes to the <c>DataOutput</c>.
/// </summary>
/// <param name="bytes">The array of bytes to write.</param>
inline void WriteBytes( array<Byte>^ bytes )
{
WriteBytes( bytes, ( bytes == nullptr ? -1 : bytes->Length ) );
}
/// <summary>
/// Write a given length of signed bytes to the <c>DataOutput</c>.
/// </summary>
/// <param name="bytes">The array of signed bytes to write.</param>
/// <param name="len">
/// The number of bytes from the start of array to write.
/// </param>
void WriteSBytes( array<SByte>^ bytes, System::Int32 len );
/// <summary>
/// Write an array of signed bytes to the <c>DataOutput</c>.
/// </summary>
/// <param name="bytes">The array of signed bytes to write.</param>
inline void WriteSBytes( array<SByte>^ bytes )
{
WriteSBytes( bytes, ( bytes == nullptr ? -1 : bytes->Length ) );
}
/// <summary>
/// Write a given length of bytes without its length to the
/// <c>DataOutput</c>.
/// </summary>
/// <param name="bytes">The array of bytes to write.</param>
/// <param name="len">
/// The number of bytes from the start of array to write.
/// </param>
void WriteBytesOnly( array<Byte>^ bytes, System::UInt32 len );
void WriteBytesOnly( array<Byte>^ bytes, System::UInt32 len, System::UInt32 offset );
/// <summary>
/// Write an array of bytes without its length to the
/// <c>DataOutput</c>.
/// </summary>
/// <param name="bytes">The array of bytes to write.</param>
inline void WriteBytesOnly( array<Byte>^ bytes )
{
WriteBytesOnly( bytes, ( bytes == nullptr ? 0 : bytes->Length ) );
}
/// <summary>
/// Write a given length of signed bytes without its length
/// to the <c>DataOutput</c>.
/// </summary>
/// <param name="bytes">The array of signed bytes to write.</param>
/// <param name="len">
/// The number of bytes from the start of array to write.
/// </param>
void WriteSBytesOnly( array<SByte>^ bytes, System::UInt32 len );
/// <summary>
/// Write an array of signed bytes without its length
/// to the <c>DataOutput</c>.
/// </summary>
/// <param name="bytes">The array of signed bytes to write.</param>
inline void WriteSBytesOnly( array<SByte>^ bytes )
{
WriteSBytesOnly( bytes, ( bytes == nullptr ? 0 : bytes->Length ) );
}
/// <summary>
/// Write a 16-bit integer to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The 16-bit integer to write.</param>
void WriteInt16( System::Int16 value );
/// <summary>
/// Write a 32-bit integer to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The 32-bit integer to write.</param>
void WriteInt32( System::Int32 value );
/// <summary>
/// Write a 64-bit integer to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The 64-bit integer to write.</param>
void WriteInt64( System::Int64 value );
/// <summary>
/// Write a float to the DataOutput.
/// </summary>
/// <param name="value">The float value to write.</param>
void WriteFloat( float value );
/// <summary>
/// Write a double precision real number to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">
/// The double precision real number to write.
/// </param>
void WriteDouble( double value );
/// <summary>
/// Write a string using java-modified UTF-8 encoding to
/// <c>DataOutput</c>.
/// The maximum length supported is 2^16-1 beyond which the string
/// shall be truncated.
/// </summary>
/// <param name="value">The UTF encoded string to write.</param>
void WriteUTF( String^ value );
void WriteString(String^ value);
/// <summary>
/// Write a <c>Serializable</c> object to the <c>DataOutput</c>.
/// This is provided to conveniently pass primitive types (like string)
/// that shall be implicitly converted to corresponding
/// <c>ISerializable</c> wrapper types.
/// </summary>
/// <param name="obj">The object to write.</param>
void WriteObject( Object^ obj );
/// <summary>
/// Advance the buffer cursor by the given offset.
/// </summary>
/// <param name="offset">
/// The offset by which to advance the cursor.
/// </param>
void AdvanceCursor( System::UInt32 offset );
/// <summary>
/// Rewind the buffer cursor by the given offset.
/// </summary>
/// <param name="offset">
/// The offset by which to rewind the cursor.
/// </param>
void RewindCursor( System::UInt32 offset );
/// <summary>
/// Get a copy of the current buffer.
/// </summary>
array<Byte>^ GetBuffer( );
/// <summary>
/// Get the length of current data in the buffer.
/// </summary>
property size_t BufferLength
{
size_t get( );
}
property Apache::Geode::Client::Cache^ Cache
{
Apache::Geode::Client::Cache^ get() { return m_cache; }
}
/// <summary>
/// Reset the cursor to the start of the buffer.
/// </summary>
void Reset( );
/// <summary>
/// Write a Dictionary to the DataOutput.
/// </summary>
/// <param name="value">The object which implements IDictionary to write.</param>
void WriteDictionary(System::Collections::IDictionary^ value);
/// <summary>
/// Write a date to the DataOutput.
/// </summary>
/// <param name="value">The date value to write.</param>
void WriteDate(System::DateTime value);
/// <summary>
/// Write a collection to the DataOutput.
/// </summary>
/// <param name="value">The object which implements IList to write.</param>
void WriteCollection(System::Collections::IList^ value);
/// <summary>
/// Write a char array to the DataOutput.
/// </summary>
/// <param name="value">The char array to write.</param>
void WriteCharArray(array<Char>^ value);
/// <summary>
/// Write a bool array to the DataOutput.
/// </summary>
/// <param name="value">The bool array to write.</param>
void WriteBooleanArray(array<bool>^ value);
/// <summary>
/// Write a short array to the DataOutput.
/// </summary>
/// <param name="value">The short array to write.</param>
void WriteShortArray(array<Int16>^ value);
/// <summary>
/// Write a int array to the DataOutput.
/// </summary>
/// <param name="value">The int array to write.</param>
void WriteIntArray(array<Int32>^ value);
/// <summary>
/// Write a long array to the DataOutput.
/// </summary>
/// <param name="value">The long array to write.</param>
void WriteLongArray(array<Int64>^ value);
/// <summary>
/// Write a float array to the DataOutput.
/// </summary>
/// <param name="value">The float array to write.</param>
void WriteFloatArray(array<float>^ value);
/// <summary>
/// Write a double array to the DataOutput.
/// </summary>
/// <param name="value">The double array to write.</param>
void WriteDoubleArray(array<double>^ value);
/// <summary>
/// Write a object array to the DataOutput.
/// </summary>
/// <param name="value">The object array to write.</param>
void WriteObjectArray(List<Object^>^ value);
/// <summary>
/// Write a array of sign byte array to the DataOutput.
/// </summary>
/// <param name="value">The array of sign byte array to write.</param>
void WriteArrayOfByteArrays(array<array<Byte>^>^ value);
internal:
native::DataOutput* GetNative()
{
return m_nativeptr->get();
}
void WriteDotNetObjectArray(Object^ objectArray);
/// <summary>
/// Write a byte to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The byte to write.</param>
void WriteByte( Byte value );
/// <summary>
/// Write an unsigned short integer (System::Int16) to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The unsigned 16-bit integer to write.</param>
void WriteUInt16( System::UInt16 value );
/// <summary>
/// Write an unsigned 32-bit integer to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The unsigned 32-bit integer to write.</param>
void WriteUInt32( System::UInt32 value );
/// <summary>
/// Write an unsigned 64-bit integer to the <c>DataOutput</c>.
/// </summary>
/// <param name="value">The unsigned 64-bit integer to write.</param>
void WriteUInt64( System::UInt64 value );
/// <summary>
/// Write a string using java-modified UTF-8 encoding to
/// <c>DataOutput</c>.
/// Length should be more than 2^16 -1.
/// </summary>
/// <param name="value">The UTF encoded string to write.</param>
void WriteUTFHuge( String^ value );
/// <summary>
/// Write a string(only ASCII char) to
/// <c>DataOutput</c>.
/// Length should be more than 2^16 -1.
/// </summary>
/// <param name="value">The UTF encoded string to write.</param>
void WriteASCIIHuge( String^ value );
System::Int32 GetBufferLengthPdx()
{
try
{
return (System::Int32)m_nativeptr->get()->getBufferLength();
}
finally
{
GC::KeepAlive(m_nativeptr);
}
}
System::Int32 GetCursorPdx()
{
return m_cursor;
}
native::Pool* GetPool();
void WriteStringArray(array<String^>^ strArray);
void EncodeUTF8String( String^ input, int encLength )
{
const int strLength = input->Length;
const int end = m_cursor + encLength;
for ( int i = 0; i < strLength && m_cursor < end; i++ )
{
unsigned short c = (unsigned short)input[i];
if( c == 0 )
{
m_bytes[m_cursor++] = 0xc0;
m_bytes[m_cursor++] = 0x80;
}
else if ( c < 0x80 )//ASCII character
{
// 7-bits done in one byte.
m_bytes[m_cursor++] = (System::Byte)c;
}
else if ( c < 0x800 )
{
// 8-11 bits done in 2 bytes
m_bytes[m_cursor++] = ( 0xC0 | c >> 6 );
m_bytes[m_cursor++] = ( 0x80 | c & 0x3F );
}
else
{
// 12-16 bits done in 3 bytes
m_bytes[m_cursor++] = ( 0xE0 | c >> 12 );
m_bytes[m_cursor++] = ( 0x80 | c >> 6 & 0x3F );
m_bytes[m_cursor++] = ( 0x80 | c & 0x3F );
}
}
// TODO ASSERT end = m_cursor
}
static int getEncodedLength(String^ input)
{
int count = 0;
for ( int i = 0; i < input->Length; i++ )
{
unsigned short c = (unsigned short)input[i];
if( c == 0)
{
count += 2;
}
else if ( c < 0x80 )//ASCII character
{
count++;
}
else if ( c < 0x800 )
{
count += 2;
}
else
{
count += 3;
}
}// end for
return count;
}
void setPdxSerialization(bool val)
{
m_ispdxSerialization = val;
}
void WriteStringWithType( String^ value );
static int8_t GetTypeId(System::UInt32 classId );
static int8_t DSFID(System::UInt32 classId);
static inline DSCode getDataSerializableDsCode(int32_t classId) {
if (classId <= std::numeric_limits<int8_t>::max() &&
classId >= std::numeric_limits<int8_t>::min()) {
return DSCode::CacheableUserData;
} else if (classId <= std::numeric_limits<int16_t>::max() &&
classId >= std::numeric_limits<int16_t>::min()) {
return DSCode::CacheableUserData2;
} else {
return DSCode::CacheableUserData4;
}
}
static inline int8_t getDataSerializableFixedIdDsCode(int32_t fixedId) {
if (fixedId <= std::numeric_limits<int8_t>::max() &&
fixedId >= std::numeric_limits<int8_t>::min()) {
return static_cast<int8_t>(DSCode::FixedIDByte);
} else if (fixedId <= std::numeric_limits<int16_t>::max() &&
fixedId >= std::numeric_limits<int16_t>::min()) {
return static_cast<int8_t>(DSCode::FixedIDShort);
} else {
return static_cast<int8_t>(DSCode::FixedIDInt);
}
}
void WriteObjectInternal( ISerializable^ obj );
void WriteBytesToUMDataOutput();
void WriteObject(bool% obj);
void WriteObject(Byte% obj);
void WriteObject(Char% obj);
void WriteObject(Double% obj);
void WriteObject(Single% obj);
void WriteObject(System::Int16% obj);
void WriteObject(System::Int32% obj);
void WriteObject(System::Int64% obj);
void WriteObject(UInt16% obj);
void WriteObject(UInt32% obj);
void WriteObject(UInt64% obj);
template <typename mType>
void WriteObject(array<mType>^ %objArray)
{
if(objArray != nullptr) {
int arrayLen = objArray->Length;
WriteArrayLen(arrayLen);
if(arrayLen > 0) {
int i = 0;
for( i = 0; i < arrayLen; i++ ){
WriteObject(objArray[i]);
}
}
}
else {
WriteByte(0xff);
}
}
bool IsManagedObject()
{
return m_isManagedObject;
}
void SetBuffer()
{
m_cursor = 0;
try
{
m_bytes = const_cast<System::Byte *>(m_nativeptr->get()->getCursor());
m_remainingBufferLength = (System::Int32)m_nativeptr->get()->getRemainingBufferLength();
}
finally
{
GC::KeepAlive(m_nativeptr);
}
}
System::Byte* GetStartBufferPosition()
{
try
{
return const_cast<System::Byte *>( m_nativeptr->get()->getBuffer());
}
finally
{
GC::KeepAlive(m_nativeptr);
};
}
inline void EnsureCapacity( System::Int32 size )
{
System::Int32 bytesLeft = m_remainingBufferLength - m_cursor;
if ( bytesLeft < size ) {
try
{
auto p = m_nativeptr->get();
p->ensureCapacity(m_cursor + size);
m_bytes = const_cast<System::Byte *>( p->getCursor());
m_remainingBufferLength = (System::Int32)p->getRemainingBufferLength();
}
catch(apache::geode::client::OutOfMemoryException ex )
{
throw gcnew OutOfMemoryException(ex);
}
finally
{
GC::KeepAlive(m_nativeptr);
}
}
}
//it expects list is not null
inline void WriteList(System::Collections::IList^ list)
{
this->WriteArrayLen(list->Count);
for each (Object^ obj in list)
this->WriteObject(obj);
}
System::Byte* GetBytes(System::Byte* src, System::UInt32 size)
{
try
{
return m_nativeptr->get()->getBufferCopyFrom(src, size);
}
finally
{
GC::KeepAlive(m_nativeptr);
}
}
System::Int32 GetRemainingBufferLength()
{
try
{
return (System::Int32) m_nativeptr->get()->getRemainingBufferLength();
}
finally
{
GC::KeepAlive(m_nativeptr);
}
}
/// <summary>
/// Internal constructor to wrap a native object pointer
/// </summary>
/// <param name="nativeptr">The native object pointer</param>
inline DataOutput(apache::geode::client::DataOutput* nativeptr, bool managedObject, Apache::Geode::Client::Cache^ cache)
{
m_cache = cache;
m_nativeptr = gcnew native_conditional_unique_ptr<native::DataOutput>(nativeptr);
m_isManagedObject = managedObject;
m_cursor = 0;
m_bytes = const_cast<System::Byte *>(nativeptr->getCursor());
m_remainingBufferLength = (System::Int32)nativeptr->getRemainingBufferLength();
m_ispdxSerialization = false;
}
};
} // namespace Client
} // namespace Geode
} // namespace Apache