Added "archive" project

This commit is contained in:
Anonymous
2014-01-13 05:42:56 -07:00
parent 86d346888a
commit b5923a7b6f
42 changed files with 6745 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 2.8)
project(archive)
if(WIN32)
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
endif()
add_subdirectory(src)
@@ -0,0 +1 @@
#include "../../src/shared/Archive.h"
@@ -0,0 +1,5 @@
#ifdef WIN32
#include "../../src/win32/ArchiveMutex.h"
#else
#include "../../src/linux/ArchiveMutex.h"
#endif
@@ -0,0 +1 @@
#include "../../src/shared/AutoByteStream.h"
@@ -0,0 +1 @@
#include "../../src/shared/AutoDeltaByteStream.h"
@@ -0,0 +1 @@
#include "../../src/shared/AutoDeltaMap.h"
@@ -0,0 +1 @@
#include "../../src/shared/AutoDeltaObserverOps.h"
@@ -0,0 +1 @@
#include "../../src/shared/AutoDeltaPackedMap.h"
@@ -0,0 +1 @@
#include "../../src/shared/AutoDeltaQueue.h"
@@ -0,0 +1,2 @@
#include "../../src/shared/AutoDeltaSet.h"
@@ -0,0 +1,2 @@
#include "../../src/shared/AutoDeltaSetObserver.h"
@@ -0,0 +1 @@
#include "../../src/shared/AutoDeltaVariableCallback.h"
@@ -0,0 +1 @@
#include "../../src/shared/AutoDeltaVariableObserver.h"
@@ -0,0 +1 @@
#include "../../src/shared/AutoDeltaVector.h"
@@ -0,0 +1 @@
#include "../../src/shared/AutoDeltaVectorObserver.h"
@@ -0,0 +1 @@
#include "../../src/shared/ByteStream.h"
@@ -0,0 +1 @@
#include "../../src/shared/FirstArchive.h"
+46
View File
@@ -0,0 +1,46 @@
set(SHARED_SOURCES
shared/Archive.h
shared/AutoByteStream.cpp
shared/AutoByteStream.h
shared/AutoDeltaByteStream.cpp
shared/AutoDeltaByteStream.h
shared/AutoDeltaMap.h
shared/AutoDeltaObserverOps.h
shared/AutoDeltaPackedMap.cpp
shared/AutoDeltaPackedMap.h
shared/AutoDeltaQueue.h
shared/AutoDeltaSet.h
shared/AutoDeltaSetObserver.h
shared/AutoDeltaVariableCallback.h
shared/AutoDeltaVariableObserver.h
shared/AutoDeltaVector.h
shared/AutoDeltaVectorObserver.h
shared/ByteStream.cpp
shared/ByteStream.h
shared/FirstArchive.h
)
if(WIN32)
set(PLATFORM_SOURCES
win32/ArchiveMutex.cpp
win32/ArchiveMutex.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32)
else()
set(PLATFORM_SOURCES
linux/ArchiveMutex.cpp
linux/ArchiveMutex.h
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/linux)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared)
add_library(archive
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
@@ -0,0 +1,34 @@
// ======================================================================
//
//
// Copyright 6/19/2001 Sony Online Entertainment
//
// ======================================================================
#include "ArchiveMutex.h"
namespace Archive
{
ArchiveMutex::ArchiveMutex()
{
pthread_mutex_init(&mutex, 0);
}
ArchiveMutex::~ArchiveMutex()
{
pthread_mutex_destroy(&mutex);
}
void ArchiveMutex::enter()
{
pthread_mutex_lock(&mutex);
}
void ArchiveMutex::leave()
{
pthread_mutex_unlock(&mutex);
}
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef _ArchiveMutex_H
#define _ArchiveMutex_H
#include <pthread.h>
namespace Archive
{
class ArchiveMutex
{
public:
ArchiveMutex();
~ArchiveMutex();
void enter();
void leave();
pthread_mutex_t &getInternalMutex() { return mutex; }
private:
ArchiveMutex(const ArchiveMutex &o);
ArchiveMutex &operator =(const ArchiveMutex &o);
pthread_mutex_t mutex;
};
};
#endif
+407
View File
@@ -0,0 +1,407 @@
#ifndef _Archive_H
#define _Archive_H
//---------------------------------------------------------------------
#include "ByteStream.h"
#include <string>
#include <map>
#include <deque>
#include <set>
//---------------------------------------------------------------------
namespace Archive {
//---------------------------------------------------------------------
inline void get(ReadIterator & source, double & target)
{
source.get(&target, 8);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, float & target)
{
source.get(&target, 4);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, unsigned long int & target)
{
source.get(&target, 4);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, signed long int & target)
{
source.get(&target, 4);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, unsigned int & target)
{
source.get(&target, 4);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, signed int & target)
{
source.get(&target, 4);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, unsigned short int & target)
{
source.get(&target, 2);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, signed short int & target)
{
source.get(&target, 2);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, unsigned char & target)
{
source.get(&target, 1);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, signed char & target)
{
source.get(&target, 1);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, std::string & target)
{
unsigned short len;
unsigned int size;
get(source, len);
if (len < 65535)
size = len;
else
get(source, size);
const char * c = reinterpret_cast<const char * const>(source.getBuffer());
target = std::string(c, size);
source.advance(size);
}
//---------------------------------------------------------------------
inline void get(ReadIterator & source, bool & target)
{
source.get(&target, 1);
}
//-----------------------------------------------------------------------
inline void get(ReadIterator & source, ByteStream & target)
{
unsigned int s;
get(source, s);
target.put(source.getBuffer(), s);
source.advance(s);
}
//----------------------------------------------------------------------
template<typename A, typename B> inline void get(ReadIterator & source, std::pair<A,B> & target)
{
get(source, target.first);
get(source, target.second);
}
//---------------------------------------------------------------------
template<typename A> inline void get(ReadIterator & source, std::vector<A>& target)
{
target.clear();
signed int length = 0;
source.get(&length, 4);
A temp;
for(int i = 0; i < length; ++i)
{
get(source, temp);
target.push_back(temp);
}
}
//-----------------------------------------------------------------------
template<typename A> inline void get(ReadIterator & source, std::set<A>& target)
{
target.clear();
signed int length = 0;
source.get(&length, 4);
A temp;
for(int i = 0; i < length; ++i)
{
get(source, temp);
target.insert(temp);
}
}
//-----------------------------------------------------------------------
template<typename A> inline void get(ReadIterator & source, std::deque<A>& target)
{
target.clear();
signed int length = 0;
source.get(&length, 4);
A temp;
for(int i = 0; i < length; ++i)
{
get(source, temp);
target.push_back(temp);
}
}
//-----------------------------------------------------------------------
template<typename A> inline void get_ptr(ReadIterator & source, std::vector<const A *>& target)
{
target.clear();
signed int length = 0;
source.get(&length, 4);
// A temp;
for(int i = 0; i < length; ++i)
{
A * temp = new A;
get(source, temp);
target.push_back(temp);
}
}
//-----------------------------------------------------------------------
template<typename Key, typename Value> inline void get(ReadIterator & source, std::map<Key, Value> & target)
{
size_t numKeys;
get(source, numKeys);
size_t i;
for(i = 0; i < numKeys; ++i)
{
Key k;
get(source, k);
Value v;
get(source, v);
target[k] = v;
}
}
//---------------------------------------------------------------------
template<typename A> inline void get(ReadIterator & source, A * target, int length)
{
for(int i = 0; i < length; ++i)
{
get(source, target[i]);
}
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const double & source)
{
target.put(&source, 8);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const float & source)
{
target.put(&source, 4);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const unsigned long int & source)
{
target.put(&source, 4);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const signed long int & source)
{
target.put(&source, 4);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const unsigned int & source)
{
target.put(&source, 4);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const signed int & source)
{
target.put(&source, 4);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const unsigned short int & source)
{
target.put(&source, 2);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const signed short int & source)
{
target.put(&source, 2);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const unsigned char & source)
{
target.put(&source, 1);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const signed char & source)
{
target.put(&source, 1);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const char & source)
{
target.put(&source, 1);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const std::string & source)
{
if (source.size() < 65535)
{
unsigned short len = static_cast<unsigned short>(source.size());
put(target, len);
}
else
{
unsigned short len = static_cast<unsigned short>(65535);
put(target, len);
unsigned int size = source.size();
put(target, size);
}
target.put(source.data(), source.size());
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, const bool & source)
{
target.put(&source, 1);
}
//---------------------------------------------------------------------
inline void put(ByteStream & target, Archive::ReadIterator & source)
{
put(target, source.getSize());
target.put(source.getBuffer(), source.getSize());
source.advance(source.getSize());
}
//-----------------------------------------------------------------------
inline void put(ByteStream & target, const ByteStream & source)
{
put(target, source.begin().getSize());
target.put(source.begin().getBuffer(), source.begin().getSize());
}
//----------------------------------------------------------------------
template<typename A, typename B> inline void put(ByteStream & target, const std::pair<A,B> & source)
{
put(target, source.first);
put(target, source.second);
}
//---------------------------------------------------------------------
template<typename A> inline void put(ByteStream & target, const std::vector<A> & source)
{
signed int length = source.size();
target.put(&length, 4);
for(int i = 0; i < length; ++i)
{
put(target, source[i]);
}
}
//-----------------------------------------------------------------------
template<typename A> inline void put(ByteStream & target, const std::set<A> & source)
{
signed int length = source.size();
target.put(&length, 4);
for (typename std::set<A>::const_iterator i = source.begin(); i != source.end(); ++i)
put(target, *i);
}
//-----------------------------------------------------------------------
template<typename A> inline void put(ByteStream & target, const std::deque<A> & source)
{
signed int length = source.size();
target.put(&length, 4);
for(int i = 0; i < length; ++i)
{
put(target, source[i]);
}
}
//-----------------------------------------------------------------------
template<typename Key, typename Value> inline void put(ByteStream & target, const std::map<Key, Value> & source)
{
size_t numKeys = source.size();
put(target, numKeys);
for (typename std::map<Key, Value>::const_iterator i = source.begin(); i != source.end(); ++i)
{
put(target, i->first);
put(target, i->second);
}
}
//---------------------------------------------------------------------
template<typename A> inline void put(ByteStream & target, const A * source, int length)
{
for(int i = 0; i < length; ++i)
{
put(target, source[i]);
}
}
//---------------------------------------------------------------------
}//namespace Archive
//---------------------------------------------------------------------
#endif // _Archive_H
@@ -0,0 +1,165 @@
//---------------------------------------------------------------------
#include "FirstArchive.h"
#include "Archive.h"
#include "AutoByteStream.h"
#include "ByteStream.h"
namespace Archive {
//---------------------------------------------------------------------
/**
@brief construct a AutoByteStream
Invokes the default constructor for the members vector
@see ByteStream
@author Justin Randall
*/
AutoByteStream::AutoByteStream() :
members()
{
}
//---------------------------------------------------------------------
/**
@brief destroy the AutoByteStream
Doesn't do anything special.
@see ByteStream
@author Justin Randall
*/
AutoByteStream::~AutoByteStream()
{
}
//---------------------------------------------------------------------
/**
@brief Add a AutoVariable to a list of data to be automatically
packed or unpacked.
Add the instance of a AutoVariableBase derivative to the
AutoByteStream's list of values to be packed and unpacked
automatically. The AutoByteStream will handle correct packing
and unpacking order as long as the variables are added in
order. Typically, these variables are added during construction
of some AutoByteStream derived class.
Once a variable has been added, it cannot be removed.
@param newVariable A reference to the instance of the
AutoVariableBase that will be added to the
AutoByteStream's list of tracked values.
@see AutoByteStream
@see AutoVariableBase
@see AutoVariable
@see ByteStream
@author Justin Randall
*/
void AutoByteStream::addVariable(AutoVariableBase & newVariable)
{
members.push_back(&newVariable);
}
//-----------------------------------------------------------------------
const unsigned int AutoByteStream::getItemCount() const
{
return members.size();
}
//---------------------------------------------------------------------
/**
@brief Pack the values (AutoVariableBase or derivatives) into the
ByteStream Buffer
When the pack method is invoked, all of the members added with
addVariable are placed, in the order they were added, into the
ByteStream's buffer. The ByteStream returns a reference to itself
after the pack operation has completed.
@see AutoVariableBase::pack
@see ByteStream::pack
@see ByteStream
@see AutoByteStream
@see AutoVariable
@return a reference to this AutoByteStream
@author Justin Randall
*/
void AutoByteStream::pack(ByteStream & target) const
{
std::vector<AutoVariableBase *>::const_iterator i;
unsigned short packedSize=static_cast<unsigned short>(members.size());
Archive::put(target,packedSize);
for(i = members.begin(); i != members.end(); ++i)
{
(*i)->pack(target);
}
}
//---------------------------------------------------------------------
/**
@brief Restore values from an ByteStream buffer
Values are restored from the source ByteStream's buffer in the order
that this ByteStream's members were added (using addVariable).
@param source The ByteStream containing the source data starting at
the ByteStream's current read position.
@see AutoByteStream::pack
@see AutoByteStream
@see ByteStream::unpack
@see ByteStream::pack
@see ByteStream
@see AutoVariableBase::unpack
@see AutoVariableBase
@author Justin Randall
*/
void AutoByteStream::unpack(ReadIterator & source)
{
std::vector<AutoVariableBase *>::iterator i;
unsigned short packedSize;
Archive::get(source,packedSize);
for(i = members.begin(); i != members.end(); ++i)
{
(*i)->unpack(source);
}
}
//---------------------------------------------------------------------
/**
@brief construct an AutoVariableBase object
The AutoVariableBase class is pure virtual. This is never directly
invoked.
@author Justin Randall
*/
AutoVariableBase::AutoVariableBase()
{
}
//---------------------------------------------------------------------
/**
@brief AutoVariableBase dtor
Defined, but is pure virtual
@author Justin Randall
*/
AutoVariableBase::~AutoVariableBase()
{
}
//----------------------------------------------------------------------
}//namespace Archive
@@ -0,0 +1,683 @@
#ifndef _INCLUDED_AutoByteStream_H
#define _INCLUDED_AutoByteStream_H
//---------------------------------------------------------------------
#pragma warning ( disable : 4786)
#include "Archive.h"
#include <cassert>
#include <list>
#include <vector>
namespace Archive {
//---------------------------------------------------------------------
class ByteStream;
class AutoVariableBase;
//---------------------------------------------------------------------
/**
@brief AutoAchive is a specialization of ByteStream that automates packing
and unpacking.
To use a AutoByteStream, the client declares AutoVariables for
members it owns and wants to persist. If the client class derives
from some parent which does not provide Auto variables:
Declare a AutoVariable that shadows the parent class' normal
integral type, override pack and unpack. During the pack
operation, the subclass sets the AutoVariable shadowing the
parent value, then invokes AutoByteStream::pack(). Durin the
unpack operation, invoke AutoByteStream::unpack(), then invoke
the parent's setter to assign the parent's value to the
AutoVariable's value.
Example Usage:
\code
class MyAutoByteStream : public AutoByteStream
{
public:
MyAutoByteStream();
~MyAutoByteStream() {};
const float getFloatValue() const;
const int getIntValue() const;
void setValue(const float value);
void setValue(const int value);
private:
AutoVariable<int> i;
};
MyAutoByteStream::MyAutoByteStream() :
i(0)
{
addVariable(i);
}
const int MyAutoByteStream::getIntValue() const
{
return i; // conversion take care of in the AutoVariable template
}
void MyAutoByteStream::setValue(const int newValue)
{
i = newValue;
}
void foo()
{
MyAutoArchvie a;
a.setValue(42);
a.setValue(3.1415f);
receiveNetworkMessage(a.pack());
}
void receiveNetworkMessage(const ByteStream & source)
{
MyAutoByteStream b
b << source;
assert(b.getIntValue() == 42);
assert(b.getFloatValue() == 3.1415f);
}
\endcode
@see AutoVariable<ValueType>
@author Justin Randall
*/
class AutoByteStream
{
public:
AutoByteStream();
virtual ~AutoByteStream();
void addVariable(AutoVariableBase & newVariable);
virtual const unsigned int getItemCount() const;
virtual void pack(ByteStream & target) const;
virtual void unpack(ReadIterator & source);
protected:
/**
@brief a list of member variables that are tracked by this
AutoByteStream object
*/
std::vector<AutoVariableBase *> members;
private:
/** disabled */
AutoByteStream(const AutoByteStream & source);
};
//---------------------------------------------------------------------
/**
@brief A AutoVariableBase is an abstract class which defines a pack
and unpack interface for the AutoByteStream.
AutoVariables derive from this class.
@see AutoVariable<ValueType>
@see AutoByteStream
@see ByteStream
@author Justin Randall
*/
class AutoVariableBase
{
public:
AutoVariableBase();
virtual ~AutoVariableBase();
/** pure virtual */
virtual void pack(ByteStream & target) const = 0;
/** pure virtual */
virtual void unpack(ReadIterator & source) = 0;
};
//----------------------------------------------------------------------
inline void get(ReadIterator &source, AutoVariableBase & target)
{
target.unpack (source);
}
//----------------------------------------------------------------------
inline void put(ByteStream &target, const AutoVariableBase & source)
{
source.pack (target);
}
//-----------------------------------------------------------------------
/**
A stand-alone, authoritative Auto variable template
The AutoVariable contains an instance of a ValueType. It behaves
much like the ValueType it encapsulates, but also provides a
serialization interface for AutoByteStreams.
The use of a AutoVariable is intended to behave similarly to
the actual ValueType it tracks, adding features for automatic
archival and retrieval.
A AutoVariable template should be used in a AutoByteStream
derived class to automatically pack and unpack data when the
ByteStream is packed or unpacked.
Refer to AutoByteStream for example useage of a AutoVariable.
@see AutoByteStream
@see AutoVariableBase
@author Justin Randall
*/
template<class ValueType>
class AutoVariable : public AutoVariableBase
{
public:
AutoVariable();
explicit AutoVariable(const ValueType & source);
virtual ~AutoVariable();
const ValueType & get() const;
virtual void pack(ByteStream & target) const;
void set(const ValueType & rhs);
virtual void unpack(ReadIterator & source);
private:
ValueType value;
};
//---------------------------------------------------------------------
/**
@brief construct an AutoVariable
*/
template<class ValueType>
AutoVariable<ValueType>::AutoVariable() :
AutoVariableBase(),
value()
{
}
//---------------------------------------------------------------------
/**
ValueType copy constructor.
Motivation: Provide an implicit conversion for the AutoVariable
that mimicks the ValueType it represents.
Invoking this copy constructor merely assigns the source value
to the AutoVariable value member.
@param source The source value which will
employ ValueType's assignment
operator to set
AutoVariable::value to the
source value.
@author Justin Randall
*/
template<class ValueType>
AutoVariable<ValueType>::AutoVariable(const ValueType & source) :
AutoVariableBase(),
value(source)
{
}
//---------------------------------------------------------------------
/**
@brief Destroy the AutoVariable object
Doesn't do anything special
@author Justin Randall
*/
template<class ValueType>
AutoVariable<ValueType>::~AutoVariable()
{
}
//---------------------------------------------------------------------
/**
@brief Retrieve the current value of the AutoVariable
@return A const reference to the current value
Example:
\code
AutoVariable<int> i;
i.set(10);
int j = i.get();
\endcode
@author Justin Randall
@see AutoVariableBase
*/
template<class ValueType>
const ValueType & AutoVariable<ValueType>::get() const
{
return value;
}
//---------------------------------------------------------------------
/**
Pack the current value of the AutoVariable
The current value of the AutoVariable is packed at the write
position of the target ByteStream.
The target ByteStream is typically a AutoByteStream, as it has
protected access to the AutoVariable::pack() method.
@param target an ByteStream to receive the value at its
current write position
@see AutoVariable
@see AutoVariableBase
@see AutoByteStream
@author Justin Randall
*/
template<class ValueType>
void AutoVariable<ValueType>::pack(ByteStream & target) const
{
Archive::put(target, value);
}
//---------------------------------------------------------------------
/**
@brief set the current value of a AutoVariable
@param rhs the new value
@author Justin Randall
*/
template<class ValueType>
void AutoVariable<ValueType>::set(const ValueType & rhs)
{
value = rhs;
}
//---------------------------------------------------------------------
/**
Unpack a value from a source ByteStream and set the current value.
A new value is extracted from the source ByteStream at its current
read position and applied to the AutoVariable value member.
The source ByteStream is typically a AutoByteStream, as it has
protected access to the AutoVariable::unpack() method.
@param source The ByteStream supplying the new
value for the
@see AutoByteStream
@see AutoVariableBase
@author Justin Randall
*/
template<class ValueType>
void AutoVariable<ValueType>::unpack(ReadIterator & source)
{
Archive::get(source, value);
}
//-----------------------------------------------------------------------
/**
@brief Like autovariable, but tracks an array (vector) of values
If an array needs to be ByteStreamd automatically, it must be
a vector.
*/
template<class ValueType>
class AutoArray : public AutoVariableBase
{
public:
AutoArray();
AutoArray(const AutoArray & source);
~AutoArray();
typedef std::vector<ValueType> DataVector;
std::vector<ValueType> & get();
const std::vector<ValueType> & get() const;
void set(const std::vector<ValueType> & source);
virtual void pack(ByteStream & target) const;
virtual void unpack(ReadIterator & source);
private:
std::vector<ValueType> array;
};
//-----------------------------------------------------------------------
/**
@brief AutoArray ctor
Instantiate an AutoArray of ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline AutoArray<ValueType>::AutoArray()
{
}
//-----------------------------------------------------------------------
/**
@brief AutoArray copy constructor
Deep copy an AutoArray of ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline AutoArray<ValueType>::AutoArray(const AutoArray & source) :
array(source.array)
{
}
//-----------------------------------------------------------------------
/**
@brief AutoArray dtor
Doesn't do anything special
@author Justin Randall
*/
template<class ValueType>
inline AutoArray<ValueType>::~AutoArray()
{
}
//-----------------------------------------------------------------------
/**
@brief AutoArray accessor routine
@return a const reference to a vector of ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline const std::vector<ValueType> & AutoArray<ValueType>::get() const
{
return array;
}
//-----------------------------------------------------------------------
/**
@brief AutoArray accessor routine
@return a reference to a vector of ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline std::vector<ValueType> & AutoArray<ValueType>::get()
{
return array;
}
//-----------------------------------------------------------------------
/**
@brief AutoArray accessor routine
@param source a const reference to an STL vector of ValueType objects
which are deep copied into this AutoArray's vector of
ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline void AutoArray<ValueType>::set(const std::vector<ValueType> & source)
{
array = source;
}
//-----------------------------------------------------------------------
/**
@brief pack this AutoArray into an Archive::ByteStream
The Archive::ByteStream receives an integer indicating the number
of ValueType objects contained by the AutoArray, followed by each
element of the AutoArray. The data is written at the Archive::ByteStream
object's current write position.
@param target The Archive::ByteStream object that will receive the
AutoArray data.
@see Archive::ByteStream
@see unpack
@author Justin Randall
*/
template<class ValueType>
inline void AutoArray<ValueType>::pack(Archive::ByteStream & target) const
{
unsigned int arraySize = array.size();
Archive::put(target, arraySize);
typename std::vector<ValueType>::const_iterator i;
for(i = array.begin(); i != array.end(); ++i)
{
Archive::put(target, (*i));
}
}
//-----------------------------------------------------------------------
/**
@brief retrieve AutoArray elements from a source Archive::ByteStream
object.
This method will reconstruct a populated ValueArray from an
Archive::ByteStream object that had an AutoArray of the same
ValueType written at the ByteStream's current read position.
First an integer indicating the number of objects in the stream
is retrieved, followed by values for each ValueType object that
was put into the Archive::ByteStream.
@param source The source Archive::ByteStream containing AutoArray
data at it's current read position.
@see Archive::ByteStrea
@see pack
@author Justin Randall
*/
template<class ValueType>
inline void AutoArray<ValueType>::unpack(Archive::ReadIterator & source)
{
unsigned int arraySize;
Archive::get(source, arraySize);
ValueType v;
for(unsigned int i = 0; i < arraySize; ++i)
{
Archive::get(source, v);
array.push_back(v);
}
}
//-----------------------------------------------------------------------
/**
@brief Like autovariable, but tracks an array (list) of values
*/
template<class ValueType>
class AutoList : public AutoVariableBase
{
public:
AutoList();
AutoList(const AutoList & source);
~AutoList();
typedef std::list<ValueType> DataList;
std::list<ValueType> & get();
const std::list<ValueType> & get() const;
void set(const std::list<ValueType> & source);
virtual void pack(ByteStream & target) const;
virtual void unpack(ReadIterator & source);
private:
std::list<ValueType> theList;
};
//-----------------------------------------------------------------------
/**
@brief AutoList ctor
Instantiate an AutoList of ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline AutoList<ValueType>::AutoList()
{
}
//-----------------------------------------------------------------------
/**
@brief AutoList copy constructor
Deep copy an AutoList of ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline AutoList<ValueType>::AutoList(const AutoList & source) :
theList(source.theList)
{
}
//-----------------------------------------------------------------------
/**
@brief AutoList dtor
Doesn't do anything special
@author Justin Randall
*/
template<class ValueType>
inline AutoList<ValueType>::~AutoList()
{
}
//-----------------------------------------------------------------------
/**
@brief AutoList accessor routine
@return a const reference to a list of ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline const std::list<ValueType> & AutoList<ValueType>::get() const
{
return theList;
}
//-----------------------------------------------------------------------
/**
@brief AutoList accessor routine
@return a reference to a list of ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline std::list<ValueType> & AutoList<ValueType>::get()
{
return theList;
}
//-----------------------------------------------------------------------
/**
@brief AutoList accessor routine
@param source a const reference to an STL list of ValueType objects
which are deep copied into this AutoList's list of
ValueType objects
@author Justin Randall
*/
template<class ValueType>
inline void AutoList<ValueType>::set(const std::list<ValueType> & source)
{
theList = source;
}
//-----------------------------------------------------------------------
/**
@brief pack this AutoList into an Archive::ByteStream
The Archive::ByteStream receives an integer indicating the number
of ValueType objects contained by the AutoList, followed by each
element of the AutoList. The data is written at the Archive::ByteStream
object's current write position.
@param target The Archive::ByteStream object that will receive the
AutoList data.
@see Archive::ByteStream
@see unpack
@author Justin Randall
*/
template<class ValueType>
inline void AutoList<ValueType>::pack(Archive::ByteStream & target) const
{
unsigned int arraySize = theList.size();
Archive::put(target, arraySize);
typename std::list<ValueType>::const_iterator i;
for(i = theList.begin(); i != theList.end(); ++i)
{
Archive::put(target, (*i));
}
}
//-----------------------------------------------------------------------
/**
@brief retrieve AutoList elements from a source Archive::ByteStream
object.
This method will reconstruct a populated ValueArray from an
Archive::ByteStream object that had an AutoList of the same
ValueType written at the ByteStream's current read position.
First an integer indicating the number of objects in the stream
is retrieved, followed by values for each ValueType object that
was put into the Archive::ByteStream.
@param source The source Archive::ByteStream containing AutoList
data at it's current read position.
@see Archive::ByteStrea
@see pack
@author Justin Randall
*/
template<class ValueType>
inline void AutoList<ValueType>::unpack(Archive::ReadIterator & source)
{
unsigned int arraySize;
Archive::get(source, arraySize);
ValueType v;
for(unsigned int i = 0; i < arraySize; ++i)
{
Archive::get(source, v);
theList.push_back(v);
}
}
//---------------------------------------------------------------------
}//namespace Archive
#endif // _INCLUDED_AutoByteStream_H
@@ -0,0 +1,218 @@
//-----------------------------------------------------------------------
#include "FirstArchive.h"
#include "Archive.h"
#include "ByteStream.h"
#ifdef _WIN32
#pragma warning (disable: 4702)
#endif
#include "AutoDeltaByteStream.h"
namespace Archive {
//-----------------------------------------------------------------------
OnDirtyCallbackBase::OnDirtyCallbackBase()
{
}
//-----------------------------------------------------------------------
OnDirtyCallbackBase::~OnDirtyCallbackBase()
{
}
//-----------------------------------------------------------------------
/**
@brief construct a AutoDeltaByteStream
@author Justin Randall
*/
AutoDeltaByteStream::AutoDeltaByteStream() :
AutoByteStream(),
dirtyList(),
onDirtyCallback(0)
{
}
//-----------------------------------------------------------------------
/**
@brief destroy a AutoDeltaByteStream
@author Justin Randall
*/
AutoDeltaByteStream::~AutoDeltaByteStream()
{
onDirtyCallback = 0;
}
//-----------------------------------------------------------------------
void AutoDeltaByteStream::addOnDirtyCallback(OnDirtyCallbackBase * newCallback)
{
onDirtyCallback = newCallback;
}
//-----------------------------------------------------------------------
/**
@brief add a member to the dirty list
This protected support method helps a AutoDeltaByteStream identify
dirty variables.
@author Justin Randall
*/
void AutoDeltaByteStream::addToDirtyList(AutoDeltaVariableBase * var)
{
dirtyList.insert(var); //lint !e534 // ignoring iterator returned from insert
if (onDirtyCallback)
{
onDirtyCallback->onDirty();
}
}
//---------------------------------------------------------------------
/**
@brief Add a new variable to the AutoDeltaByteStream.
This method leverages the AutoByteStream member list ot identify
values tracked by the AutoByteStream. Additionally, the variable
index is set so that it may identify itself when it is used
in a non-const manner, and it receives a reference to it's owner
AutoDeltaByteStream.
@author Justin Randall
*/
void AutoDeltaByteStream::addVariable(AutoDeltaVariableBase & var)
{
var.setIndex(static_cast<unsigned short int>(members.size()));
var.setOwner(this);
AutoByteStream::addVariable(var);
}
//---------------------------------------------------------------------
const unsigned int AutoDeltaByteStream::getItemCount() const
{
unsigned short int count = 0;
if (!dirtyList.empty())
{
for (std::set<void *>::const_iterator i = dirtyList.begin(); i != dirtyList.end(); ++i)
{
AutoDeltaVariableBase * const v = reinterpret_cast<AutoDeltaVariableBase *>(*i);
if (v->isDirty())
++count;
}
}
return count;
}
//-----------------------------------------------------------------------
/**
@brief Pack values that have changed since the last time deltas
were collected.
@author Justin Randall
*/
void AutoDeltaByteStream::packDeltas(ByteStream & target) const
{
unsigned short int const count = static_cast<unsigned short int>(getItemCount());
// place count in archive
Archive::put(target, count);
if (count > 0)
{
for (std::set<void *>::const_iterator i = dirtyList.begin(); i != dirtyList.end(); ++i)
{
AutoDeltaVariableBase * const v = reinterpret_cast<AutoDeltaVariableBase *>(*i);
if (v->isDirty())
{
put(target, v->getIndex());
v->packDelta(target);
}
}
}
dirtyList.clear();
}
//-----------------------------------------------------------------------
void AutoDeltaByteStream::clearDeltas() const
{
if (!dirtyList.empty())
{
for (std::set<void *>::const_iterator i = dirtyList.begin(); i != dirtyList.end(); ++i)
{
AutoDeltaVariableBase * const v = reinterpret_cast<AutoDeltaVariableBase *>(*i);
v->clearDelta();
}
dirtyList.clear();
}
}
//-----------------------------------------------------------------------
void AutoDeltaByteStream::removeOnDirtyCallback()
{
onDirtyCallback = 0;
}
//---------------------------------------------------------------------
/**
@brief receive a delta ByteStream and apply the new deltas.
Receive a delta ByteStream and apply the new deltas to the local
object. The ByteStream MUST be created by another AutoDeltaByteStream!
@author Justin Randall
*/
void AutoDeltaByteStream::unpackDeltas(ReadIterator & source)
{
unsigned short int index;
unsigned short int count;
Archive::get(source, count);
while (source.getSize())
{
get(source, index);
AutoDeltaVariableBase * const v = reinterpret_cast<AutoDeltaVariableBase *>(members[index]);
v->unpackDelta(source);
}
}
//-----------------------------------------------------------------------
/**
@brief constructor for an abstract AutoDeltaVariableBase object
@author Justin Randall
*/
AutoDeltaVariableBase::AutoDeltaVariableBase() :
AutoVariableBase(),
index(0),
owner(0)
{
}
//-----------------------------------------------------------------------
/**
@brief desctructor for a AutoDeltaVariableBase or derivative
object.
@author Justin Randall
*/
AutoDeltaVariableBase::~AutoDeltaVariableBase()
{
owner = 0;
}
//-----------------------------------------------------------------------
}//namespace Archive
@@ -0,0 +1,755 @@
#ifndef _INCLUDED_AutoDeltaByteStream_H
#define _INCLUDED_AutoDeltaByteStream_H
//-----------------------------------------------------------------------
#if WIN32
#pragma warning ( disable : 4786 )
#pragma warning ( disable : 4800 )
#endif
#include <cmath>
#include "AutoByteStream.h"
#include "ByteStream.h"
#include <set>
#include <vector>
namespace Archive {
class AutoDeltaVariableBase;
class OnDirtyCallbackBase
{
public:
OnDirtyCallbackBase();
virtual ~OnDirtyCallbackBase() = 0;
virtual void onDirty() = 0;
private:
OnDirtyCallbackBase(const OnDirtyCallbackBase &);
OnDirtyCallbackBase & operator = (const OnDirtyCallbackBase &);
};
template<typename ObjectType>
class OnDirtyCallback : public OnDirtyCallbackBase
{
public:
OnDirtyCallback() :
owner(0),
callback(0)
{
}
OnDirtyCallback(ObjectType &o, void (ObjectType::*onDirty)()) :
owner(&o),
callback(onDirty)
{
}
virtual ~OnDirtyCallback()
{
}
void set(ObjectType &o, void (ObjectType::*onDirty)())
{
owner = &o;
callback = onDirty;
}
virtual void onDirty()
{
if (owner && callback)
((*owner).*callback)();
}
private:
OnDirtyCallback(const OnDirtyCallback &);
OnDirtyCallback & operator = (const OnDirtyCallback &);
private:
ObjectType *owner;
void (ObjectType::*callback)();
};
//-----------------------------------------------------------------------
/**
@brief An ByteStream that knows when it's members have changed.
The AutoDeltaByteStream employs the AutoDeltaVariableBase to
detect changes in it's members. Any AutoDetlaVaraibleBase that
changed since the last packDeltas() method will be placed in the
ByteStream during the next packDeltas() operation.
ByteStream data is packed as <varIndex><value> in memory, so
only AutoDeltaByteStreams may interpret a delta package at run time.
AutoDeltaByteStream objects can also deserialize from ByteStream and
AutoByteStream objects using the unpack() method. To unpack a
delta ByteStream, AutoDeltaByteStream provides unpackDeltas().
AutoDeltaVariable objects, which are contained by a
AutoDeltaByteStream, can set threshold values to trigger a
change (e.g. a value representing heading may need to change
by more than 3 degrees before the object is considered "changed").
Example Usage:
\code
class MyAutoDeltaByteStream : public AutoDeltaByteStream
{
public:
MyAutoDeltaByteStream();
~MyAutoDeltaByteStream();
const float getValue() const;
void setValue(const float value);
private:
AutoDeltaVariable<float> value;
};
MyAutoDeltaByteStream::MyAutoDeltaByteStream() :
value(0.0f)
{
addVariable(value);
value.setDeltaSensitivity(3.0f);
value.clearDelta();
}
const float MyAutoDeltaByteStream::getValue() const
{
return value;
}
void MyAutoDeltaByteStream::setValue(const float newValue)
{
value = newValue;
}
void foo()
{
MyAutoDeltaByteStream a;
MyAutoDeltaByteStream b;
a.setValue(2.0f); // change of 2, not enough to trigger a delta
b.setValue(1.0f);
b.unpackDeltas(a.packDeltas());
assert(b.getValue() == 1.0f); // no deltas from (a)
a.setValue(5.0f); // large enough change
b.unpackDeltas(a.packDeltas());
assert(b.getValue() == a.getValue() && b.getValue() == 5.0f);
}
\endcode
*/
class AutoDeltaByteStream : public AutoByteStream
{
public:
AutoDeltaByteStream ();
virtual ~AutoDeltaByteStream ();
void addOnDirtyCallback (OnDirtyCallbackBase * newCallback);
virtual void addVariable (AutoDeltaVariableBase & var);
virtual const unsigned int getItemCount () const;
virtual void packDeltas (ByteStream & target) const;
virtual void unpackDeltas (ReadIterator & source);
virtual void clearDeltas () const;
void removeOnDirtyCallback ();
protected:
friend class AutoDeltaVariableBase;
void addToDirtyList (AutoDeltaVariableBase * var);
private:
// disable assignment and copy constructors
AutoDeltaByteStream & operator = (const AutoDeltaByteStream & rhs);
AutoDeltaByteStream (const AutoDeltaByteStream & source);
private:
mutable std::set<void *> dirtyList; // contains AutoVariable's that insert themselves on change
OnDirtyCallbackBase * onDirtyCallback;
};
//-----------------------------------------------------------------------
/**
@brief An abstract base class for AutoDeltaVariables
The AutoDeltaVariableBase defines interfaces for
managing how delta's between packDelta operations
are detected.
@see AutoDeltaByteStream
@see AutoByteStream
@see ByteStream
@see AutoVariableBase
@author Justin Randall
*/
class AutoDeltaVariableBase : public AutoVariableBase
{
public:
AutoDeltaVariableBase();
virtual ~AutoDeltaVariableBase() = 0;
/** pure virtual */
virtual void clearDelta() const = 0;
const unsigned short int getIndex() const;
/** pure virtual */
virtual const bool isDirty() const = 0;
void touch();
protected:
friend class AutoDeltaByteStream;
AutoDeltaByteStream * getOwner();
void setIndex(const unsigned short int index);
void setOwner(AutoDeltaByteStream * owner);
/** pure virtual */
virtual void pack(ByteStream & target) const = 0;
/** pure virtual */
virtual void packDelta(ByteStream & target) const = 0;
/** pure virtual */
virtual void unpackDelta(ReadIterator & source) = 0;
private:
unsigned short int index;
AutoDeltaByteStream * owner;
};
//-----------------------------------------------------------------------
/**
@brief Return the AutoByteStream::members index for this instance.
A AutoDeltaVariableBase tracks its index in the members list
of the ByteStream. This helper-value permits deserialization of the
value to the appropriate member when the AutoDeltaByteStream invokes
unpackDeltas(). AutoByteStream::packDeltas() prefixes each
delta value with the index of the AutoDeltaVariable.
<index><value>
@return the index of the variable in AutoByteStream::members
@see AutoByteStream
@see AutoDeltaByteStream
@see ByteStream
@see AutoDeltaByteStream::packDeltas
@see AutoDeltaByteStream::unpackDeltas
@author Justin Randall
*/
inline const unsigned short int AutoDeltaVariableBase::getIndex() const
{
return index;
}
//-----------------------------------------------------------------------
/**
@brief Get a pointer to this variable's owner ByteStream
As the AutoDeltaVariableBase is used in a non-const
manner, it will insert itself into it's owner AutoDeltaByteStream::dirtyList
set.
When the AutoDeltaByteStream executes AutoDeltaByteStream::packDeltas(),
it will iterate through this set to determine which
variables may be dirty, invoke AutoDeltaVariableBase::isDirty() on
each variable in the set, and if it is dirty, include the value
in the ByteStream buffer.
AutoDeltaVariableBase derived classes need to retrieve a
reference to their owner ByteStreams to add them to the
dirtyList set.
@return a pointer to the owner AutoDeltaByteStream
@see AutoDeltaByteStream
@see AutoDeltaByteStream::packDeltas
@see AutoDeltaByteStream::unpackDeltas
@see AutoDeltaVariableBase::pack
@see AutoDeltaVariableBase::unpack
@author Justin Randall
*/
inline AutoDeltaByteStream * AutoDeltaVariableBase::getOwner()
{
return owner;
}
//-----------------------------------------------------------------------
/**
@brief Set the index in the AutoByteStream Members list
This method is overridden so that the owner value may also
be set.
@param newIndex An index into the AutoAchive::members list
@see AutoVariableBase
@see AutoAchive
@see AutoDeltaByteStream
@see ByteStream
@author Justin Randall
*/
inline void AutoDeltaVariableBase::setIndex(const unsigned short int newIndex)
{
index = newIndex;
}
//-----------------------------------------------------------------------
/**
@brief set the AutoDeltaVariableBase::owner member to the address of
some AutoDeltaByteStream instance.
A AutoDeltaVariableBase or derived object must put itself on
it's owner AutoDeltaByteStream::dirtyList
*/
inline void AutoDeltaVariableBase::setOwner(AutoDeltaByteStream * newOwner)
{
owner = newOwner;
}
//-----------------------------------------------------------------------
/**
@brief Put this variable on the owner ByteStream's dirty list
@author Justin Randall
*/
inline void AutoDeltaVariableBase::touch()
{
if(owner)
owner->addToDirtyList(this);
}
//-----------------------------------------------------------------------
/**
@brief an authoritative variable that knows when it has changed
A AutoDeltaVariable is use much like a AutoVariable, but it also
knows when it has changed. In addition to knowing when it has changed,
it also may set some change threshold, so that minor variations
in the value can be ignored by the application.
Example:
\code
class MyAutoDeltaByteStream : public AutoDeltaByteStream
{
public:
MyAutoDeltaByteStream();
~MyAutoDeltaByteStream() {};
void setValue(const int value)
{ i = value; };
const int getValue() const
{ return i; };
private:
AutoDeltaVariable<int> i;
};
MyAutoDeltaByteStream::MyAutoDeltaByteStream()
{
addVariable(i);
i.setDeltaSensitivity(5.0f);
};
void foo()
{
MyAutoDeltaByteStream a;
MyAutoDeltaByteStream b;
ByteStream c;
c = a.pack(); // packs all values (just a.i, really)
b << c; // unpacks all values
assert(a.getValue() == b.getValue());
a.setValue(3);
b.unpackDeltas(a.packDeltas());
assert(a.getValue() != b.getValue());
a.setValue(300);
b.unpackDeltas(a.packDeltas());
assert(a.getValue() == b.getValue());
}
\endcode
@see AutoDeltaVariableBase
@see AutoVariable
@see AutoVariableBase
@see AutoDeltaByteStream
@see AutoByteStream
@see ByteStream
@author Justin Randall
*/
template<typename ValueType>
class AutoDeltaVariable : public AutoDeltaVariableBase
{
public:
AutoDeltaVariable();
AutoDeltaVariable(const AutoDeltaVariable & source);
explicit AutoDeltaVariable(const ValueType & source);
~AutoDeltaVariable();
AutoDeltaVariable & operator = (const AutoDeltaVariable & source);
AutoDeltaVariable & operator = (const ValueType & source);
void clearDelta() const;
const ValueType & get() const;
const bool isDirty() const;
void pack(ByteStream & target) const;
void packDelta(ByteStream & target) const;
virtual void set(const ValueType & source);
virtual void unpack(ReadIterator & source);
virtual void unpackDelta(ReadIterator & source);
private:
ValueType currentValue;
mutable ValueType lastValue;
};
//-----------------------------------------------------------------------
/**
@brief default AutoDeltaVariable constructor
@author Justin Randall
@see AutoVariable
@see AutoVariableBase
@see AutoDeltaVariableBase
@see AutoByteStream
@see ByteStream
*/
template<typename ValueType>
inline AutoDeltaVariable<ValueType>::AutoDeltaVariable() :
AutoDeltaVariableBase(),
currentValue(ValueType()),
lastValue(ValueType())
{
}
//-----------------------------------------------------------------------
/**
@brief AutoDeltaVariable copy constructor
This copy constructor will perform a deep copy of the current
value from the source AutoDeltaVariable. It does not copy
AutoDeltaVariableBase members such as the owner. The owner MUST
be set explicitly.
@author Justin Randall
@see AutoVariable
@see AutoVariableBase
@see AutoDeltaVariableBase
@see AutoByteStream
@see ByteStream
*/
template<typename ValueType>
inline AutoDeltaVariable<ValueType>::AutoDeltaVariable(const AutoDeltaVariable & source) :
AutoDeltaVariableBase(),
currentValue(source.currentValue),
lastValue(source.currentValue)
{
}
//-----------------------------------------------------------------------
/**
@brief AutoDeltaVariable copy constructor
A deep copy of the source value is placed in the current value. All
other members use default constructors in the initalizer list.
\code
MyAutoDeltaByteStream::MyAutoDeltaByteStream()
{
// set myAutoInt current value to 35
myAutoInt(35);
myAutoInt.setOwner(this);
// copy myAutoInt
myAutoInt2(myAutoInt);
myAutoInt2.setOwner(this);
// myAutoInt2 now has a current value of 35
}
\endcode
@author Justin Randall
@see AutoVariable
@see AutoVariableBase
@see AutoDeltaVariableBase
@see AutoByteStream
@see ByteStream
*/
template<typename ValueType>
inline AutoDeltaVariable<ValueType>::AutoDeltaVariable(const ValueType & source) :
AutoDeltaVariableBase(),
currentValue(source),
lastValue(source)
{
}
//-----------------------------------------------------------------------
/**
@brief AutoDeltaVariable destructor
Nothing special happens in this desctructor.
@see AutoDeltaVariableBase
@see AutoByteStream
@see AutoDeltaByteStream
@see ByteStream
@author Justin Randall
*/
template<typename ValueType>
inline AutoDeltaVariable<ValueType>::~AutoDeltaVariable()
{
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline AutoDeltaVariable<ValueType> & AutoDeltaVariable<ValueType>::operator =(const AutoDeltaVariable<ValueType> & rhs)
{
if(&rhs != this)
set(rhs.currentValue);
return *this;
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline AutoDeltaVariable<ValueType> & AutoDeltaVariable<ValueType>::operator =(const ValueType & rhs)
{
if(rhs != currentValue)
set(rhs);
return *this;
}
//-----------------------------------------------------------------------
/**
@brief assign the lastValue to the currentValue to avert isDirty()
returning true.
@author Justin Randall
*/
template<typename ValueType>
inline void AutoDeltaVariable<ValueType>::clearDelta() const
{
lastValue = currentValue;
}
//---------------------------------------------------------------------
/**
@brief return the current value of the AutoDeltaVariable
@return the current value of the AutoDeltaVariable
@see AutoDeltaVariableBase
@see AutoVariable
@see AutoDeltaByteStream
@see AutoByteStream
@see ByteStream
@author Justin Randall
*/
template<typename ValueType>
inline const ValueType & AutoDeltaVariable<ValueType>::get() const
{
return currentValue;
}
//-----------------------------------------------------------------------
/**
@brief compare last and current values to be sure the value
to determine if the value has changed.
When a AutoDeltaVariable is used in a non-const manner, it is placed
on the AutoDeltaByteStream::dirtyList until AutoDeltaByteStream::packDeltas()
is invoked. All members on the list are checked to see if their value
has changed enough to warrant a new delta ByteStream.
Any change in values triggers isDirty() to return true.
@return true if the variable has changed
@see AutoDeltaVariable
@see AutoDeltaVariableBase
@see AutoDeltaByteStream
@see AutoVariable
@see AutoVariableBase
@see AutoByteStream
@see ByteStream
@author Justin Randall
*/
template<typename ValueType>
inline const bool AutoDeltaVariable<ValueType>::isDirty() const
{
return lastValue != currentValue;
}
//-----------------------------------------------------------------------
/**
@brief pack the ValueType into the target ByteStream
If the ByteStream understands how to pack the type, or if
a derived class can break the value into it's integral components,
then it is placed into the ByteStream.
This can be invoked either by an ByteStream base class, or from
AutoDeltaByteStream::packDeltas(). If packing delta values, the
AutoDeltaByteStream first packs an index number into the ByteStream. In
this case, the ByteStream can ONLY be unpacked via another
AutoDeltaByteStream::unpackDeltas(), and the other instance must
declare the same AutoVariableBase types in exactly the same order!
@param target A target ByteStream object receiving the value
@see AutoDeltaVariableBase
@see AutoVariableBase
@see AutoDeltaByteStream
@see AutoByteStream
@see ByteStream
@author Justin Randall
*/
template<typename ValueType>
inline void AutoDeltaVariable<ValueType>::pack(ByteStream & target) const
{
Archive::put(target, currentValue);
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaVariable<ValueType>::packDelta(ByteStream & target) const
{
pack(target);
clearDelta();
}
//---------------------------------------------------------------------
/**
@brief Set the current value of this AutoDeltaVariable
@see AutoDeltaVariableBase
@see AutoDeltaByteStream
@see AutoVariable
@see AutoByteStream
@see ByteStream
@author Justin Randall
*/
template<typename ValueType>
inline void AutoDeltaVariable<ValueType>::set(const ValueType & source)
{
if (currentValue != source)
{
currentValue = source;
touch();
}
}
//-----------------------------------------------------------------------
/**
@brief retrieve a value from the source ByteStream
Read the variable value from the source ByteStream at the current read
position in the ByteStream. To work properly, the ByteStream read position
MUST contain the value -- that is, variables must be retrieve in the
order they were packed.
AutoByteStream classes and their derivatives automatically pack and
unpack data in the correct order. This protected method is visible
only to ByteStreams.
@param source The source ByteStream containing the desired value at
its current read position
@see AutoDeltaVariable
@see AutoDeltaVariableBase
@see AutoDeltaByteStream
@see AutoVariableBase
@see AutoByteStream
@see ByteStream
@author Justin Randall
*/
template<typename ValueType>
inline void AutoDeltaVariable<ValueType>::unpack(ReadIterator & source)
{
Archive::get(source, currentValue);
clearDelta();
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaVariable<ValueType>::unpackDelta(ReadIterator & source)
{
Archive::get(source, currentValue);
touch();
}
//---------------------------------------------------------------------
struct DefaultObjectType {};
//-----------------------------------------------------------------------
static const unsigned char CONTAINER_SET = 0;
static const unsigned char CONTAINER_ERASE = 1;
/**
@brief base container synchronization class
@author Justin Randall
*/
class AutoDeltaContainer : public AutoDeltaVariableBase
{
public:
AutoDeltaContainer();
/** pure virtual */
virtual ~AutoDeltaContainer() = 0;
/** pure virtual */
virtual const size_t size() const = 0;
};
//-----------------------------------------------------------------------
/**
@brief ctor
@author Justin Randall
*/
inline AutoDeltaContainer::AutoDeltaContainer() :
AutoDeltaVariableBase()
{
}
//-----------------------------------------------------------------------
/**
@brief dtor
@author Justin Randall
*/
inline AutoDeltaContainer::~AutoDeltaContainer()
{
}
//-----------------------------------------------------------------------
}//namespace Archive
#endif // _INCLUDED__AutoDeltaByteStream_H
+754
View File
@@ -0,0 +1,754 @@
#ifndef _INCLUDED_AutoDeltaMap_H
#define _INCLUDED_AutoDeltaMap_H
//-----------------------------------------------------------------------
#include "AutoDeltaByteStream.h"
#include <map>
//-----------------------------------------------------------------------
namespace Archive {
//-----------------------------------------------------------------------
/**
@brief an auto-synchronization map template
The AutoDeltaMap implements a map container that knows when and what
has changed in the map. The map may be added just like any other
AutoDeltaVariableBase -- invoke addVariable(mapInstance)
This particular AutoDeltaMap is implemented as a map, though
the interface does not require it to be implemented as such.
@see AutoDeltaVariableBase
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType=DefaultObjectType>
class AutoDeltaMap : public AutoDeltaContainer
{
public:
struct Command
{
enum Commands
{
ADD,
ERASE,
SET
};
unsigned char cmd;
KeyType key;
ValueType value;
};
public: // methods
typedef std::map<KeyType, ValueType> MapType;
typedef typename MapType::const_iterator const_iterator;
AutoDeltaMap();
AutoDeltaMap(const AutoDeltaMap & source);
~AutoDeltaMap();
void clear();
void clearDelta() const;
const_iterator erase(const KeyType & key);
const_iterator erase(const_iterator & i);
bool empty() const;
const_iterator find(const KeyType & key) const;
const_iterator lower_bound(const KeyType & key) const;
const MapType & getMap() const;
std::pair<const_iterator, bool> insert(const KeyType & key, const ValueType & value);
const bool isDirty() const;
void pack(ByteStream & target) const;
void packDelta(ByteStream & target) const;
void set(const KeyType & key, const ValueType & value);
const size_t size() const;
void unpack(ReadIterator & source);
void unpackDelta(ReadIterator & source);
static void pack(ByteStream & target, const std::vector<Command> & data);
static void unpack(ReadIterator & source, std::vector<Command> & data);
static void unpackDelta(ReadIterator & source, std::vector<Command> & data);
const_iterator begin() const;
const_iterator end() const;
void setOnErase (ObjectType * owner, void (ObjectType::*onErase)(const KeyType &, const ValueType &));
void setOnInsert (ObjectType * owner, void (ObjectType::*onInsert)(const KeyType &, const ValueType &));
void setOnSet (ObjectType * owner, void (ObjectType::*onSet)(const KeyType &, const ValueType &, const ValueType &));
private:
AutoDeltaMap &operator=(const AutoDeltaMap &);
void onErase(const KeyType &, const ValueType &);
void onInsert(const KeyType &, const ValueType &);
void onSet(const KeyType &, const ValueType &, const ValueType &);
MapType container;
size_t baselineCommandCount;
mutable std::vector<Command> changes;
std::pair<ObjectType *, void (ObjectType::*)(const KeyType &, const ValueType &)> *onEraseCallback;
std::pair<ObjectType *, void (ObjectType::*)(const KeyType &, const ValueType &)> *onInsertCallback;
std::pair<ObjectType *, void (ObjectType::*)(const KeyType &, const ValueType &, const ValueType &)> *onSetCallback;
};
//-----------------------------------------------------------------------
/**
@brief default constructor, inits base class, container and container
copy
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline AutoDeltaMap<KeyType, ValueType, ObjectType>::AutoDeltaMap() :
AutoDeltaContainer(),
container(),
baselineCommandCount(0),
changes(),
onEraseCallback(0),
onInsertCallback(0),
onSetCallback(0)
{
}
//-----------------------------------------------------------------------
/**
@brief copy constructor
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline AutoDeltaMap<KeyType, ValueType, ObjectType>::AutoDeltaMap(const AutoDeltaMap<KeyType, ValueType, ObjectType> & source) :
AutoDeltaContainer(),
container(source.container),
baselineCommandCount(0),
changes(),
onEraseCallback(0),
onInsertCallback(0),
onSetCallback(0)
{
}
//-----------------------------------------------------------------------
/**
@brief dtor
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline AutoDeltaMap<KeyType, ValueType, ObjectType>::~AutoDeltaMap()
{
delete onEraseCallback;
delete onInsertCallback;
delete onSetCallback;
}
//-----------------------------------------------------------------------
/**
@brief like std::map::begin(), returns a const_iterator to the first
element in the map.
Wraps a call to std::map<ValueType>::begin
@return const_iterator to the first element of the map
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline typename AutoDeltaMap<KeyType, ValueType, ObjectType>::const_iterator AutoDeltaMap<KeyType, ValueType, ObjectType>::begin() const
{
return container.begin();
}
//-----------------------------------------------------------------------
/**
@brief support routine to clear the map.
@author Steve Jakab
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::clear()
{
//@todo: this is very inefficient!
while (begin() != end())
{
const_iterator i = begin();
erase(i);
}
}
//-----------------------------------------------------------------------
/**
@brief support routine to clear deltas in the map.
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::clearDelta() const
{
changes.clear();
}
//-----------------------------------------------------------------------
/**
@brief like std::map::end(), returns a const_iterator to the end
of the map.
@return a const_iterator to the end of the map
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline typename AutoDeltaMap<KeyType, ValueType, ObjectType>::const_iterator AutoDeltaMap<KeyType, ValueType, ObjectType>::end() const
{
return container.end();
}
//-----------------------------------------------------------------------
/**
@brief invokes map::erase(KeyType &)
Removes an element from the map
@param key A keyType describing some element of the map
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline typename AutoDeltaMap<KeyType, ValueType, ObjectType>::const_iterator AutoDeltaMap<KeyType, ValueType, ObjectType>::erase(const KeyType & key)
{
typename std::map<KeyType, ValueType>::iterator f(container.find(key));
if (f != container.end())
{
Command c;
c.cmd = Command::ERASE;
c.key = (*f).first;
c.value = (*f).second;
changes.push_back(c);
++baselineCommandCount;
container.erase(f++);
touch();
onErase(key, c.value);
}
return f;
}
//-----------------------------------------------------------------------
/**
@brief invokes map::erase(const_iterator &)
Removes and element from the map
@param i a const_iterator describing an element in the map
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline typename AutoDeltaMap<KeyType, ValueType, ObjectType>::const_iterator AutoDeltaMap<KeyType, ValueType, ObjectType>::erase(const_iterator & i)
{
return erase((*i).first);
}
//-----------------------------------------------------------------------
/**
@brief invokes map::empty()
Returns true if the map is empty.
@author Acy Stapp
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline bool AutoDeltaMap<KeyType, ValueType, ObjectType>::empty() const
{
return container.empty();
}
//-----------------------------------------------------------------------
/**
@brief return a map::<ValueType>::const_iterator
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline typename AutoDeltaMap<KeyType, ValueType, ObjectType>::const_iterator AutoDeltaMap<KeyType, ValueType, ObjectType>::find(const KeyType & key) const
{
return container.find(key);
}
// ----------------------------------------------------------------------
template<class KeyType, typename ValueType, typename ObjectType>
inline typename AutoDeltaMap<KeyType, ValueType, ObjectType>::const_iterator AutoDeltaMap<KeyType, ValueType, ObjectType>::lower_bound(const KeyType & key) const
{
return container.lower_bound(key);
}
//----------------------------------------------------------------------
template<class KeyType, typename ValueType, typename ObjectType>
inline const typename AutoDeltaMap<KeyType, ValueType, ObjectType>::MapType & AutoDeltaMap<KeyType, ValueType, ObjectType>::getMap() const
{
return container;
}
//-----------------------------------------------------------------------
template<class KeyType, typename ValueType, typename ObjectType>
#if defined(linux) || _MSC_VER >= 1300
inline std::pair<typename AutoDeltaMap<KeyType, ValueType, ObjectType>::const_iterator, bool> AutoDeltaMap<KeyType, ValueType, ObjectType>::insert(const KeyType & key, const ValueType & value)
#else
inline std::pair<AutoDeltaMap<KeyType, ValueType, ObjectType>::const_iterator, bool> AutoDeltaMap<KeyType, ValueType, ObjectType>::insert(const KeyType & key, const ValueType & value)
#endif
{
typedef typename std::map<KeyType, ValueType>::const_iterator iter;
typedef std::pair<iter, bool> insertResult;
iter i = container.find(key);
if (i != container.end())
return std::make_pair(i, false);
Command c;
c.cmd = Command::ADD;
c.key = key;
c.value = value;
insertResult result = container.insert(std::make_pair(key, value));
touch();
onInsert(key, value);
changes.push_back(c);
++baselineCommandCount;
return result;
}
//-----------------------------------------------------------------------
/**
@brief is the map dirty?
If any operation has modified the map adds changes to its list,
so if there are any changes, the map is dirty.
@return true if the map is dirty
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline const bool AutoDeltaMap<KeyType, ValueType, ObjectType>::isDirty() const
{
return (!changes.empty());
}
//-----------------------------------------------------------------------
/**
@brief pack the whole container
Iterates through all elements in the container, packing them in
the supplied ByteStream.
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::pack(ByteStream & target) const
{
typename std::map<KeyType, ValueType>::const_iterator i;
Archive::put(target, container.size());
Archive::put(target, baselineCommandCount);
unsigned char cmd;
for(i = container.begin(); i != container.end(); ++i)
{
cmd = Command::ADD;
Archive::put(target, cmd);
Archive::put(target, (*i).first);
Archive::put(target, (*i).second);
}
}
//-----------------------------------------------------------------------
/**
@brief Pack the whole container from a list of updates, without
instantiating the container.
This converts a vector of commands to a stream of bytes. This
byte stream can be unpacked into an AutoDeltaMap.
This function is useful when reading the data from a file or database.
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::pack(ByteStream & target, const std::vector<Command> &data)
{
Archive::put(target, data.size());
Archive::put(target, static_cast<size_t>(0)); // baselineCommandCount
for(typename std::vector<Command>::const_iterator c(data.begin()); c != data.end(); ++c)
{
assert(c->cmd == Command::ADD); // only add is valid in packing the whole container
Archive::put(target, c->cmd);
Archive::put(target, c->key);
Archive::put(target, c->value);
}
}
//-----------------------------------------------------------------------
/**
@brief only pack elements which have changed
This runs through the list of changes which has already been
generated, and packs them.
Each add, remove or set are prefixed with a CONTAINER_SET or
CONTAINER_ERASE command. (adds and sets both use CONTAINER_SET).
@param target a ByteStream object that will receive the delta package
at its current write position
@author Justin Randall
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::packDelta(ByteStream & target) const
{
Archive::put(target, changes.size());
Archive::put(target, baselineCommandCount);
for (typename std::vector<Command>::iterator i = changes.begin(); i != changes.end(); ++i)
{
const Command & c = (*i);
Archive::put(target, c.cmd);
switch (c.cmd)
{
case Command::ADD:
case Command::SET:
case Command::ERASE:
{
Archive::put(target, c.key);
Archive::put(target, c.value);
}
break;
default:
assert(false); // unknown command put INTO the archive!!!! THis will
// cause a crash when unpacking on a remote system
}
}
clearDelta();
}
//-----------------------------------------------------------------------
/**
@brief get the number of elements in the map
@return the number of elements in the map
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline const size_t AutoDeltaMap<KeyType, ValueType, ObjectType>::size() const
{
return container.size();
}
//-----------------------------------------------------------------------
/**
@brief set an element in the map
If the key does not exist in the map, then an add is queued (which
will trigger a delta), the value is added to the map, and touch() is
called place the container on the AutoDeltaByteStream's dirty list.
If they key exists, and the values differ, and if the key is not in the
changes set, the old value is stored in changes, the new value is in
the current container's map and the container invokes touch() to
place itself on the AutoDeltaByteStream's dirty list.
@param key Unique identifier for the value
@param value value associated with the unique key
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::set(const KeyType & key, const ValueType & value)
{
Command c;
typename std::map<KeyType, ValueType>::iterator i = container.find(key);
if (i == container.end())
{
c.cmd = Command::ADD;
c.key = key;
c.value = value;
container[key] = value;
touch();
onInsert(key, value);
changes.push_back(c);
++baselineCommandCount;
}
else
{
// did it really change?
if ((*i).second != value)
{
c.cmd = Command::SET;
c.key = key;
c.value = value;
ValueType oldValue = i->second;
// set it!
i->second = value;
touch();
onSet(key, oldValue, value);
changes.push_back(c);
++baselineCommandCount;
}
}
}
//-----------------------------------------------------------------------
/**
@brief rebuild the container from a byte stream
The container first determines the number of changes that will be
applied, which is the first element in the ByteStream.
Then, for each element, the command is read (CONTAINER_SET or
CONTAINER_ERASE). If it is a CONTAINER_SET, then the key and value
are read from the byte stream and applied to the container. If the
command is CONTAINER_ERASE, the key is retrieved, and the key/value
pair is erased from the container.
@param source a ByteStream containing the delta or baseline package.
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::unpack(ReadIterator & source)
{
// unpacking baseline data
container.clear();
clearDelta();
Command c;
size_t commandCount;
Archive::get(source, commandCount);
Archive::get(source, baselineCommandCount);
for (size_t i = 0; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
assert(c.cmd == Command::ADD); // only add is valid in unpack
Archive::get(source, c.key);
Archive::get(source, c.value);
container[c.key] = c.value;
onInsert(c.key, c.value);
}
}
//-----------------------------------------------------------------------
/**
@brief Get the elements of the container without instantiating it.
This reads the byte stream like the non-static unpack(), but it constructs
a vector of commands that would build the container.
This is useful for writing the data to an external data store, e.g.
a file or a database.
@param source a ByteStream containing the delta or baseline package.
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::unpack(ReadIterator & source, std::vector<Command> & data)
{
// unpacking baseline data
Command c;
size_t commandCount;
size_t baselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, baselineCommandCount);
for (size_t i = 0; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
assert(c.cmd == Command::ADD); // only add is valid in unpack
Archive::get(source, c.key);
Archive::get(source, c.value);
data.push_back(c);
}
}
//-----------------------------------------------------------------------
/**
@brief update the container from a byte stream
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::unpackDelta(ReadIterator & source)
{
Command c;
size_t skipCount, commandCount, targetBaselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, targetBaselineCommandCount);
// if (commandCount+baselineCommandCount) < targetBaselineCommandCount, it
// means that we have missed some changes and are behind; when this happens,
// catch up by applying all the deltas that came in, and set
// baselineCommandCount to targetBaselineCommandCount
if ((commandCount+baselineCommandCount) > targetBaselineCommandCount)
skipCount = commandCount+baselineCommandCount-targetBaselineCommandCount;
else
skipCount = 0;
// If this fails, it means that the deltas we are receiving are relative to baselines
// which are newer than what we currently have. This usually means either we were not
// observing an object for a time when deltas were sent, but aren't getting new
// baselines, or our version of the container has been modified locally.
if (skipCount > commandCount)
skipCount = commandCount;
size_t i;
for (i = 0; i < skipCount; ++i)
{
Archive::get(source, c.cmd);
Archive::get(source, c.key);
Archive::get(source, c.value);
}
for ( ; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
switch(c.cmd)
{
case Command::ADD:
case Command::SET:
{
Archive::get(source, c.key);
Archive::get(source, c.value);
AutoDeltaMap::set(c.key, c.value);
}
break;
case Command::ERASE:
{
Archive::get(source, c.key);
Archive::get(source, c.value);
AutoDeltaMap::erase(c.key);
}
break;
default:
assert(false); // unknown command
break;
}
}
// if we are behind, catch up
if (baselineCommandCount < targetBaselineCommandCount)
baselineCommandCount = targetBaselineCommandCount;
}
//-----------------------------------------------------------------------
/**
@brief Get the deltas to the container without instantiating it.
This reads the byte stream like the non-static unpackDeltas(), but it constructs
a vector of commands that would update the container.
This is useful for writing the data to an external data store, e.g.
a file or a database.
@param source a ByteStream containing the delta or baseline package.
*/
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::unpackDelta(ReadIterator & source, std::vector<Command> & data)
{
Command c;
size_t commandCount, targetBaselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, targetBaselineCommandCount);
for (size_t i=0 ; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
switch(c.cmd)
{
case Command::ADD:
case Command::SET:
case Command::ERASE:
{
Archive::get(source, c.key);
Archive::get(source, c.value);
}
break;
default:
assert(false); // unknown command
break;
}
data.push_back(c);
}
}
//-----------------------------------------------------------------------
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::onSet(const KeyType &key, const ValueType &oldValue, const ValueType &newValue)
{
if (onSetCallback && onSetCallback->first)
{
ObjectType &owner = *onSetCallback->first;
void (ObjectType::*cb)(const KeyType &, const ValueType &, const ValueType &) = onSetCallback->second;
(owner.*cb)(key, oldValue, newValue);
}
}
//-----------------------------------------------------------------------
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::onErase(const KeyType &key, const ValueType &value)
{
if (onEraseCallback && onEraseCallback->first)
{
ObjectType &owner = *onEraseCallback->first;
void (ObjectType::*cb)(const KeyType &, const ValueType &) = onEraseCallback->second;
(owner.*cb)(key, value);
}
}
//-----------------------------------------------------------------------
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::onInsert(const KeyType &key, const ValueType &value)
{
if (onInsertCallback && onInsertCallback->first)
{
ObjectType &owner = *onInsertCallback->first;
void (ObjectType::*cb)(const KeyType &, const ValueType &) = onInsertCallback->second;
(owner.*cb)(key, value);
}
}
//-----------------------------------------------------------------------
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::setOnErase(ObjectType * owner, void (ObjectType::*cb)(const KeyType &, const ValueType &))
{
delete onEraseCallback;
onEraseCallback = new std::pair<ObjectType *, void (ObjectType::*)(const KeyType &, const ValueType &)>;
onEraseCallback->first = owner;
onEraseCallback->second = cb;
}
//-----------------------------------------------------------------------
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::setOnInsert(ObjectType * owner, void (ObjectType::*cb)(const KeyType &, const ValueType &))
{
delete onInsertCallback;
onInsertCallback = new std::pair<ObjectType *, void (ObjectType::*)(const KeyType &, const ValueType &)>;
onInsertCallback->first = owner;
onInsertCallback->second = cb;
}
//-----------------------------------------------------------------------
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaMap<KeyType, ValueType, ObjectType>::setOnSet(ObjectType * owner, void (ObjectType::*cb)(const KeyType &, const ValueType &, const ValueType &))
{
delete onSetCallback;
onSetCallback = new std::pair<ObjectType *, void (ObjectType::*)(const KeyType &, const ValueType &, const ValueType &)>;
onSetCallback->first = owner;
onSetCallback->second = cb;
}
//-----------------------------------------------------------------------
}//namespace Archive
#endif // _INCLUDED__AutoDeltaMap_H
@@ -0,0 +1,35 @@
// ======================================================================
//
// AutoDeltaObserverOps.h
// Copyright 2001, 2002 Sony Online Entertainment Inc.
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_AutoDeltaObserverOps_H
#define INCLUDED_AutoDeltaObserverOps_H
//-----------------------------------------------------------------------
namespace Archive {
// enum list of every operation that can be performed on an observed object
enum AutoDeltaObserverOp
{
// base observer ops
ADOO_generic,
ADOO_clear,
ADOO_erase,
ADOO_pop_back,
ADOO_push_back,
ADOO_insert,
ADOO_set,
ADOO_setAll,
ADOO_unpack,
ADOO_unpackDelta,
};
}//namespace Archive
#endif // INCLUDED_AutoDeltaObserverOps_H
@@ -0,0 +1,32 @@
// ======================================================================
//
// AutoDeltaPackedMap.cpp
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#include "FirstArchive.h"
#include "AutoDeltaPackedMap.h"
#include <stdio.h>
// ======================================================================
namespace Archive
{
int countCharacter(const std::string &str, char c)
{
int result=0;
for (std::string::const_iterator i=str.begin(); i!=str.end(); ++i)
{
if (*i==c)
++result;
}
return result;
}
} //namespace
// ======================================================================
@@ -0,0 +1,240 @@
// ======================================================================
//
// AutoDeltaPackedMap.h
// copyright (c) 2004 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_AutoDeltaPackedMap_H
#define INCLUDED_AutoDeltaPackedMap_H
// ======================================================================
#include <stdio.h>
#include "AutoDeltaMap.h"
// ======================================================================
namespace Archive
{
int countCharacter(const std::string &str, char c);
//These are implemented in sharedFoundation/NetworkIdArchive
#ifdef WIN32
void get(ReadIterator & source, unsigned __int64 & target);
void put(ByteStream & target, const unsigned __int64 & source);
#else
void get(ReadIterator & source, unsigned long long int & target);
void put(ByteStream & target, const unsigned long long int & source);
#endif
/**
* An AutoDeltaPackedMap is an AutoDeltaMap that will be packed into
* a single value for storage. It functions as an AutoDeltaMap in
* all respects except that packDeltas() will send the entire map
* on the network.
*/
template<class KeyType, typename ValueType, typename ObjectType=DefaultObjectType>
class AutoDeltaPackedMap : public AutoDeltaMap<KeyType, ValueType, ObjectType>
{
public:
AutoDeltaPackedMap();
AutoDeltaPackedMap(const AutoDeltaPackedMap & source);
~AutoDeltaPackedMap();
static void unpack(ReadIterator & source, std::string & buffer);
static void pack(ByteStream & target, const std::string & buffer);
virtual void packDelta(ByteStream & target) const;
virtual void unpackDelta(ReadIterator & source);
void setOnChanged(ObjectType * owner, void (ObjectType::*onChanged)());
private:
static void internal_unpack(ReadIterator & source, std::string & buffer, const char * format);
static void internal_pack(ByteStream & target, const std::string & buffer, const char * format);
void onChanged();
std::pair<ObjectType *, void (ObjectType::*)()> *onChangedCallback;
private:
AutoDeltaPackedMap & operator=(const AutoDeltaPackedMap &rhs);
};
template<class KeyType, typename ValueType, typename ObjectType>
inline AutoDeltaPackedMap<KeyType, ValueType, ObjectType>::AutoDeltaPackedMap() :
AutoDeltaMap<KeyType, ValueType, ObjectType>(),
onChangedCallback(0)
{
}
template<class KeyType, typename ValueType, typename ObjectType>
inline AutoDeltaPackedMap<KeyType, ValueType, ObjectType>::AutoDeltaPackedMap(const AutoDeltaPackedMap<KeyType, ValueType, ObjectType> & source) :
AutoDeltaMap<KeyType, ValueType, ObjectType>(source),
onChangedCallback(0)
{
}
template<class KeyType, typename ValueType, typename ObjectType>
inline AutoDeltaPackedMap<KeyType, ValueType, ObjectType>::~AutoDeltaPackedMap()
{
delete onChangedCallback;
}
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaPackedMap<KeyType, ValueType, ObjectType>::packDelta(ByteStream & target) const
{
AutoDeltaMap<KeyType, ValueType, ObjectType>::pack(target);
}
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaPackedMap<KeyType, ValueType, ObjectType>::unpackDelta(ReadIterator & source)
{
AutoDeltaMap<KeyType, ValueType, ObjectType>::unpack(source);
onChanged();
}
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaPackedMap<KeyType, ValueType, ObjectType>::internal_pack(ByteStream & target, const std::string & buffer, const char* format)
{
char temp[200];
typename AutoDeltaMap<KeyType, ValueType, ObjectType>::Command c;
Archive::put(target, countCharacter(buffer,':'));
Archive::put(target, static_cast<size_t>(0)); // baselineCommandCount
int tempPos = 0;
for (std::string::const_iterator i=buffer.begin(); i!=buffer.end(); ++i)
{
if (*i==':')
{
temp[tempPos]='\0';
sscanf(temp,format,&c.key, &c.value);
Archive::put(target, static_cast<unsigned char>(AutoDeltaMap<KeyType, ValueType, ObjectType>::Command::ADD));
Archive::put(target, c.key);
Archive::put(target, c.value);
tempPos=0;
}
else
{
temp[tempPos++]=*i;
}
}
}
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaPackedMap<KeyType, ValueType, ObjectType>::internal_unpack(ReadIterator & source, std::string & buffer, const char *format)
{
char temp[200];
typename AutoDeltaMap<KeyType, ValueType, ObjectType>::Command c;
size_t commandCount;
size_t baselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, baselineCommandCount);
if (commandCount==0)
{
buffer=' '; // An empty map is represented as a single space, because a completely empty string is used to mean "no change"
}
else
{
for (size_t i = 0; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
Archive::get(source, c.key);
Archive::get(source, c.value);
#ifdef WIN32
_snprintf(temp, sizeof(temp)-1, format, c.key, c.value);
#else
snprintf(temp, sizeof(temp)-1, format, c.key, c.value);
#endif
temp[sizeof(temp)-1]='\0';
buffer+=temp;
}
}
}
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaPackedMap<KeyType, ValueType, ObjectType>::onChanged()
{
if (onChangedCallback && onChangedCallback->first)
{
ObjectType &owner = *onChangedCallback->first;
void (ObjectType::*cb)() = onChangedCallback->second;
(owner.*cb)();
}
}
template<class KeyType, typename ValueType, typename ObjectType>
inline void AutoDeltaPackedMap<KeyType, ValueType, ObjectType>::setOnChanged(ObjectType * owner, void (ObjectType::*cb)())
{
delete onChangedCallback;
onChangedCallback = new std::pair<ObjectType *, void (ObjectType::*)()>;
onChangedCallback->first = owner;
onChangedCallback->second = cb;
}
// ======================================================================
// pack-to-string functions for specific types
inline void AutoDeltaPackedMap<int, float>::pack(ByteStream & target, const std::string & buffer)
{
internal_pack(target, buffer, "%i %f");
}
inline void AutoDeltaPackedMap<int, float>::unpack(ReadIterator & source, std::string & buffer)
{
internal_unpack(source, buffer, "%i %.2f:");
}
inline void AutoDeltaPackedMap<int, int>::pack(ByteStream & target, const std::string & buffer)
{
internal_pack(target, buffer, "%i %i");
}
inline void AutoDeltaPackedMap<int, int>::unpack(ReadIterator & source, std::string & buffer)
{
internal_unpack(source, buffer, "%i %i:");
}
inline void AutoDeltaPackedMap<int, unsigned long>::pack(ByteStream & target, const std::string & buffer)
{
internal_pack(target, buffer, "%i %u");
}
inline void AutoDeltaPackedMap<int, unsigned long>::unpack(ReadIterator & source, std::string & buffer)
{
internal_unpack(source, buffer, "%i %u:");
}
#ifdef WIN32
inline void AutoDeltaPackedMap<unsigned long, unsigned __int64>::pack(ByteStream & target, const std::string & buffer)
{
internal_pack(target, buffer, "%lu %I64u");
}
inline void AutoDeltaPackedMap<unsigned long, unsigned __int64>::unpack(ReadIterator & source, std::string & buffer)
{
internal_unpack(source, buffer, "%lu %I64u:");
}
#else
inline void AutoDeltaPackedMap<unsigned long, unsigned long long int>::pack(ByteStream & target, const std::string & buffer)
{
internal_pack(target, buffer, "%lu %llu");
}
inline void AutoDeltaPackedMap<unsigned long, unsigned long long int>::unpack(ReadIterator & source, std::string & buffer)
{
internal_unpack(source, buffer, "%lu %llu:");
}
#endif
} //namespace
// ======================================================================
#endif
@@ -0,0 +1,408 @@
#ifndef _INCLUDED_AutoDeltaQueue_H
#define _INCLUDED_AutoDeltaQueue_H
//-----------------------------------------------------------------------
#include "AutoDeltaByteStream.h"
#include <list>
namespace Archive {
//-----------------------------------------------------------------------
/**
@brief an auto-synchronization list template
The AutoDeltaQueue implements a list container that knows when and what
has changed in the list. The list may be added just like any other
AutoDeltaVariableBase -- invoke addVariable(queueInstance)
This particular AutoDeltaQueue is implemented as a list, though
the interface does not require it to be implemented as such.
@see AutoDeltaVariableBase
*/
template<typename ValueType>
class AutoDeltaQueue: public AutoDeltaContainer
{
public: // methods
typedef std::list<ValueType> QueueType;
typedef typename QueueType::iterator iterator;
typedef typename QueueType::const_iterator const_iterator;
AutoDeltaQueue();
AutoDeltaQueue(AutoDeltaQueue const &source);
~AutoDeltaQueue();
void clear();
void clearDelta() const;
iterator find(ValueType const &value);
const_iterator find(ValueType const &value) const;
void erase(iterator i);
void erase(int position);
bool empty() const;
const bool isDirty() const;
void pack(ByteStream &target) const;
void packDelta(ByteStream &target) const;
const size_t size() const;
void unpack(ReadIterator &source);
void unpackDelta(ReadIterator &source);
void push(ValueType const &value);
void pop();
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
private: // members
struct ModifyCommand
{
enum Commands
{
PUSH,
ERASE
};
unsigned char cmd;
ValueType value;
int position;
};
QueueType container;
size_t baselineCommandCount;
mutable std::vector<ModifyCommand> changes;
AutoDeltaQueue &operator=(AutoDeltaQueue const &);
};
//-----------------------------------------------------------------------
template<typename ValueType>
inline AutoDeltaQueue<ValueType>::AutoDeltaQueue() :
AutoDeltaContainer(),
container(),
baselineCommandCount(0),
changes()
{
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline AutoDeltaQueue<ValueType>::AutoDeltaQueue(const AutoDeltaQueue<ValueType> &source) :
AutoDeltaContainer(),
container(source.container),
baselineCommandCount(0),
changes()
{
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline AutoDeltaQueue<ValueType>::~AutoDeltaQueue()
{
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline typename AutoDeltaQueue<ValueType>::iterator AutoDeltaQueue<ValueType>::begin()
{
return container.begin();
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline typename AutoDeltaQueue<ValueType>::const_iterator AutoDeltaQueue<ValueType>::begin() const
{
return container.begin();
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::clear()
{
//@todo: this is very inefficient!
while (begin() != end())
{
erase(begin());
}
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::clearDelta() const
{
changes.clear();
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline typename AutoDeltaQueue<ValueType>::iterator AutoDeltaQueue<ValueType>::end()
{
return container.end();
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline typename AutoDeltaQueue<ValueType>::const_iterator AutoDeltaQueue<ValueType>::end() const
{
return container.end();
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::erase(iterator i)
{
if (i != container.end())
{
ModifyCommand c;
c.cmd = ModifyCommand::ERASE;
c.position = std::distance(container.begin(), i);
changes.push_back(c);
++baselineCommandCount;
container.erase(i);
touch();
}
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::erase(int position)
{
if (position < static_cast<int>(size()))
{
ModifyCommand c;
c.cmd = ModifyCommand::ERASE;
c.position = position;
changes.push_back(c);
++baselineCommandCount;
iterator i = begin();
std::advance(i, position);
container.erase(i);
touch();
}
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::pop()
{
if (!empty())
{
ModifyCommand c;
c.cmd = ModifyCommand::ERASE;
c.position = 0;
changes.push_back(c);
++baselineCommandCount;
container.pop_front();
touch();
}
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline bool AutoDeltaQueue<ValueType>::empty() const
{
return container.empty();
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline typename AutoDeltaQueue<ValueType>::iterator AutoDeltaQueue<ValueType>::find(ValueType const &value)
{
return container.find(value);
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline typename AutoDeltaQueue<ValueType>::const_iterator AutoDeltaQueue<ValueType>::find(ValueType const &value) const
{
return container.find(value);
}
//----------------------------------------------------------------------
template<typename ValueType>
inline const bool AutoDeltaQueue<ValueType>::isDirty() const
{
return (!changes.empty());
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::pack(ByteStream &target) const
{
const_iterator i;
Archive::put(target, container.size());
Archive::put(target, baselineCommandCount);
unsigned char cmd;
for (i = container.begin(); i != container.end(); ++i)
{
cmd = ModifyCommand::PUSH;
Archive::put(target, cmd);
Archive::put(target, (*i));
}
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::packDelta(ByteStream &target) const
{
Archive::put(target, changes.size());
Archive::put(target, baselineCommandCount);
for (typename std::vector<ModifyCommand>::iterator i = changes.begin(); i != changes.end(); ++i)
{
const ModifyCommand &c = (*i);
Archive::put(target, c.cmd);
switch(c.cmd)
{
case ModifyCommand::PUSH:
{
Archive::put(target, c.value);
}
break;
case ModifyCommand::ERASE:
{
Archive::put(target, c.position);
}
break;
}
}
clearDelta();
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline const size_t AutoDeltaQueue<ValueType>::size() const
{
return container.size();
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::push(ValueType const &value)
{
ModifyCommand c;
c.cmd = ModifyCommand::PUSH;
c.value = value;
container.push_back(value);
touch();
changes.push_back(c);
++baselineCommandCount;
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::unpack(ReadIterator &source)
{
// unpacking baseline data
container.clear();
clearDelta();
ModifyCommand c;
size_t commandCount;
Archive::get(source, commandCount);
Archive::get(source, baselineCommandCount);
for (size_t i = 0; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
assert(c.cmd == ModifyCommand::PUSH); // only push valid for pack/unpack
Archive::get(source, c.value);
container.push_back(c.value);
}
}
//-----------------------------------------------------------------------
template<typename ValueType>
inline void AutoDeltaQueue<ValueType>::unpackDelta(ReadIterator &source)
{
ModifyCommand c;
size_t skipCount, commandCount, targetBaselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, targetBaselineCommandCount);
skipCount = commandCount+baselineCommandCount-targetBaselineCommandCount;
// If this fails, it means that the deltas we are receiving are relative to baselines
// which are newer than what we currently have. This usually means either we were not
// observing an object for a time when deltas were sent, but aren't getting new
// baselines, or our version of the container has been modified locally.
if (skipCount > commandCount)
skipCount = commandCount;
size_t i;
for (i = 0; i < skipCount; ++i)
{
Archive::get(source, c.cmd);
switch (c.cmd)
{
case ModifyCommand::PUSH:
{
Archive::get(source, c.value);
}
break;
case ModifyCommand::ERASE:
{
Archive::get(source, c.position);
}
break;
default:
assert(false);
break;
}
}
for ( ; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
switch (c.cmd)
{
case ModifyCommand::PUSH:
{
Archive::get(source, c.value);
AutoDeltaQueue::push(c.value);
}
break;
case ModifyCommand::ERASE:
{
Archive::get(source, c.position);
AutoDeltaQueue::erase(c.position);
}
break;
default:
assert(false); // unknown command
break;
}
}
}
//-----------------------------------------------------------------------
} //namespace Archive
#endif // _INCLUDED__AutoDeltaQueue_H
+537
View File
@@ -0,0 +1,537 @@
// ======================================================================
//
// AutoDeltaSet.h
//
// Copyright 2003 Sony Online Entertainment
//
// ======================================================================
#ifndef _INCLUDED_AutoDeltaSet_H
#define _INCLUDED_AutoDeltaSet_H
// ======================================================================
#include "AutoDeltaByteStream.h"
// ======================================================================
namespace Archive {
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType = DefaultObjectType>
class AutoDeltaSet: public AutoDeltaContainer
{
public:
typedef std::set<ValueType> SetType;
typedef typename SetType::size_type size_type;
typedef typename SetType::const_iterator const_iterator;
typedef typename SetType::const_reverse_iterator const_reverse_iterator;
public:
struct Command
{
enum
{
ERASE,
INSERT,
CLEAR
};
unsigned char cmd;
ValueType value;
};
public:
AutoDeltaSet();
~AutoDeltaSet();
const_iterator begin() const;
const_iterator end() const;
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
void clearDelta() const;
const bool isDirty() const;
void pack(ByteStream &target) const;
void packDelta(ByteStream &target) const;
SetType const & get() const;
const size_t size() const;
bool empty() const;
bool contains(ValueType const &t) const;
const_iterator find(ValueType const &t) const;
virtual void clear();
virtual const_iterator erase(ValueType const &t);
virtual const_iterator erase(const_iterator &i);
virtual void insert(ValueType const &t);
virtual void unpack(ReadIterator &source);
virtual void unpackDelta(ReadIterator &source);
static void pack(ByteStream &target, std::set<ValueType> const &data);
static void unpack(ReadIterator &source, std::vector<Command> &data);
static void unpackDelta(ReadIterator &source, std::vector<Command> &data);
void setOnChanged(ObjectType *owner, void (ObjectType::*onChanged)());
void setOnErase(ObjectType *owner, void (ObjectType::*onErase)(ValueType const &));
void setOnInsert(ObjectType *owner, void (ObjectType::*onInsert)(ValueType const &));
private:
void onChanged();
void onErase(const ValueType &);
void onInsert(const ValueType &);
private:
SetType m_set;
size_t m_baselineCommandCount;
mutable std::vector<Command> m_commands;
std::pair<ObjectType *, void (ObjectType::*)()> *m_onChangedCallback;
std::pair<ObjectType *, void (ObjectType::*)(ValueType const &)> *m_onEraseCallback;
std::pair<ObjectType *, void (ObjectType::*)(ValueType const &)> *m_onInsertCallback;
private:
AutoDeltaSet(AutoDeltaSet const &);
};
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline AutoDeltaSet<ValueType, ObjectType>::AutoDeltaSet() :
AutoDeltaContainer(),
m_set(),
m_baselineCommandCount(0),
m_commands(),
m_onChangedCallback(0),
m_onEraseCallback(0),
m_onInsertCallback(0)
{
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline AutoDeltaSet<ValueType, ObjectType>::~AutoDeltaSet()
{
delete m_onChangedCallback;
delete m_onEraseCallback;
delete m_onInsertCallback;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaSet<ValueType, ObjectType>::const_iterator AutoDeltaSet<ValueType, ObjectType>::begin() const
{
return m_set.begin();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::clear()
{
if (!empty())
{
Command c;
c.cmd = Command::CLEAR;
m_commands.push_back(c);
++m_baselineCommandCount;
for (typename SetType::iterator i = m_set.begin(); i != m_set.end(); ++i)
onErase(*i);
m_set.clear();
touch();
onChanged();
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::clearDelta() const
{
m_commands.clear();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaSet<ValueType, ObjectType>::const_iterator AutoDeltaSet<ValueType, ObjectType>::end() const
{
return m_set.end();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaSet<ValueType, ObjectType>::const_iterator AutoDeltaSet<ValueType, ObjectType>::erase(ValueType const &value)
{
typename SetType::const_iterator i(find(value));
return erase(i);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaSet<ValueType, ObjectType>::const_iterator AutoDeltaSet<ValueType, ObjectType>::erase(const_iterator &i)
{
if (i != m_set.end())
{
Command c;
c.cmd = Command::ERASE;
c.value = *i;
m_commands.push_back(c);
++m_baselineCommandCount;
m_set.erase(i++);
touch();
onErase(c.value);
onChanged();
}
return i;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline bool AutoDeltaSet<ValueType, ObjectType>::contains(ValueType const &value) const
{
return m_set.find(value) != m_set.end();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaSet<ValueType, ObjectType>::const_iterator AutoDeltaSet<ValueType, ObjectType>::find(ValueType const &value) const
{
return m_set.find(value);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaSet<ValueType, ObjectType>::SetType const &AutoDeltaSet<ValueType, ObjectType>::get() const
{
return m_set;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::insert(ValueType const &value)
{
if (m_set.insert(value).second)
{
Command c;
c.cmd = Command::INSERT;
c.value = value;
m_commands.push_back(c);
++m_baselineCommandCount;
touch();
onInsert(value);
onChanged();
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const bool AutoDeltaSet<ValueType, ObjectType>::isDirty() const
{
return m_commands.size() > 0;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::onChanged()
{
if (m_onChangedCallback)
{
if (m_onChangedCallback->first)
{
ObjectType &owner = *m_onChangedCallback->first;
void (ObjectType::*cb)() = m_onChangedCallback->second;
(owner.*cb)();
}
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::onErase(ValueType const &value)
{
if (m_onEraseCallback)
{
if (m_onEraseCallback->first)
{
ObjectType &owner = *m_onEraseCallback->first;
void (ObjectType::*cb)(ValueType const &) = m_onEraseCallback->second;
(owner.*cb)(value);
}
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::onInsert(ValueType const &value)
{
if (m_onInsertCallback)
{
if (m_onInsertCallback->first)
{
ObjectType &owner = *m_onInsertCallback->first;
void (ObjectType::*cb)(ValueType const &) = m_onInsertCallback->second;
(owner.*cb)(value);
}
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::pack(ByteStream &target) const
{
Archive::put(target, m_set.size());
Archive::put(target, m_baselineCommandCount);
for (typename SetType::const_iterator i = m_set.begin(); i != m_set.end(); ++i)
Archive::put(target, *i);
}
// ----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::pack(ByteStream &target, std::set<ValueType> const &data)
{
Archive::put(target, data.size());
Archive::put(target, static_cast<size_t>(0)); // baselineCommandCount
for (typename std::set<ValueType>::const_iterator i = data.begin(); i != data.end(); ++i)
Archive::put(target, *i);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::packDelta(ByteStream &target) const
{
Archive::put(target, m_commands.size());
Archive::put(target, m_baselineCommandCount);
for (typename std::vector<Command>::iterator i = m_commands.begin(); i != m_commands.end(); ++i)
{
Command const &c = *i;
Archive::put(target, c.cmd);
switch (c.cmd)
{
case Command::ERASE:
case Command::INSERT:
Archive::put(target, c.value);
break;
case Command::CLEAR:
break;
}
}
clearDelta();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaSet<ValueType, ObjectType>::const_reverse_iterator AutoDeltaSet<ValueType, ObjectType>::rbegin() const
{
return m_set.rbegin();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaSet<ValueType, ObjectType>::const_reverse_iterator AutoDeltaSet<ValueType, ObjectType>::rend() const
{
return m_set.rend();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::setOnChanged(ObjectType *owner, void (ObjectType::*cb)())
{
delete m_onChangedCallback;
m_onChangedCallback = new std::pair<ObjectType *, void (ObjectType::*)()>;
m_onChangedCallback->first = owner;
m_onChangedCallback->second = cb;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::setOnErase(ObjectType *owner, void (ObjectType::*cb)(ValueType const &))
{
delete m_onEraseCallback;
m_onEraseCallback = new std::pair<ObjectType *, void (ObjectType::*)(ValueType const &)>;
m_onEraseCallback->first = owner;
m_onEraseCallback->second = cb;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::setOnInsert(ObjectType *owner, void (ObjectType::*cb)(ValueType const &))
{
delete m_onInsertCallback;
m_onInsertCallback = new std::pair<ObjectType *, void (ObjectType::*)(ValueType const &)>;
m_onInsertCallback->first = owner;
m_onInsertCallback->second = cb;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline bool AutoDeltaSet<ValueType, ObjectType>::empty() const
{
return m_set.empty();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const size_t AutoDeltaSet<ValueType, ObjectType>::size() const
{
return m_set.size();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::unpack(ReadIterator &source)
{
m_set.clear();
clearDelta();
size_t commandCount;
ValueType value;
Archive::get(source, commandCount);
Archive::get(source, m_baselineCommandCount);
for (size_t i = 0; i < commandCount; ++i)
{
Archive::get(source, value);
m_set.insert(value);
}
onChanged();
}
// ----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::unpack(ReadIterator &source, std::vector<Command> &data)
{
Command c;
size_t commandCount, targetBaselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, targetBaselineCommandCount);
c.cmd = Command::INSERT;
for (size_t i = 0; i < commandCount; ++i)
{
Archive::get(source,c.value);
data.push_back(c);
}
}
// ----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::unpackDelta(ReadIterator &source, std::vector<Command> &data)
{
Command c;
size_t commandCount, targetBaselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, targetBaselineCommandCount);
for (size_t i = 0 ; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
switch (c.cmd)
{
case Command::ERASE:
case Command::INSERT:
Archive::get(source, c.value);
break;
case Command::CLEAR:
break;
default:
assert(false);
break;
}
data.push_back(c);
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaSet<ValueType, ObjectType>::unpackDelta(ReadIterator &source)
{
Command c;
size_t skipCount, commandCount, targetBaselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, targetBaselineCommandCount);
// if (commandCount+baselineCommandCount) < targetBaselineCommandCount, it
// means that we have missed some changes and are behind; when this happens,
// catch up by applying all the deltas that came in, and set
// baselineCommandCount to targetBaselineCommandCount
if ((commandCount+m_baselineCommandCount) > targetBaselineCommandCount)
skipCount = commandCount+m_baselineCommandCount-targetBaselineCommandCount;
else
skipCount = 0;
if (skipCount > commandCount)
skipCount = commandCount;
size_t i = 0;
for ( ; i < skipCount; ++i)
{
Archive::get(source, c.cmd);
if (c.cmd != Command::CLEAR)
Archive::get(source, c.value);
}
for ( ; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
switch (c.cmd)
{
case Command::ERASE:
Archive::get(source, c.value);
AutoDeltaSet::erase(c.value);
break;
case Command::INSERT:
Archive::get(source, c.value);
AutoDeltaSet::insert(c.value);
break;
case Command::CLEAR:
AutoDeltaSet::clear();
break;
}
}
// if we are behind, catch up
if (m_baselineCommandCount < targetBaselineCommandCount)
m_baselineCommandCount = targetBaselineCommandCount;
}
//---------------------------------------------------------------------
}//namespace Archive
// ======================================================================
#endif // _INCLUDED__AutoDeltaSet_H
@@ -0,0 +1,135 @@
// ======================================================================
//
// AutoDeltaSetObserver.h
//
// Copyright 2003 Sony Online Entertainment
//
// ======================================================================
#ifndef _INCLUDED_AutoDeltaSetObserver_H
#define _INCLUDED_AutoDeltaSetObserver_H
// ======================================================================
#include "AutoDeltaSet.h"
#include "AutoDeltaObserverOps.h"
// ----------------------------------------------------------------------
namespace Archive {
// ----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType = DefaultObjectType>
class AutoDeltaSetObserver: public AutoDeltaSet<ValueType, ObjectType>
{
public:
typedef std::set<ValueType> SetType;
typedef typename SetType::const_iterator const_iterator;
AutoDeltaSetObserver();
~AutoDeltaSetObserver();
void setSourceObject(SourceObjectType *source);
virtual void clear ();
virtual typename SetType::const_iterator erase(ValueType const &value);
virtual typename SetType::const_iterator erase(const_iterator & i);
virtual void insert (ValueType const &value);
virtual void unpack (ReadIterator &source);
virtual void unpackDelta (ReadIterator &source);
private:
AutoDeltaSetObserver(AutoDeltaSetObserver const &);
AutoDeltaSetObserver &operator=(AutoDeltaSetObserver const &);
private:
SourceObjectType *sourceObject;
};
//----------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::AutoDeltaSetObserver() :
AutoDeltaSet<ValueType, ObjectType>(),
sourceObject(0)
{
}
//----------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::~AutoDeltaSetObserver()
{
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::setSourceObject(SourceObjectType *source)
{
sourceObject = source;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::clear()
{
Callback callback(sourceObject, ADOO_clear);
AutoDeltaSet<ValueType, ObjectType>::clear();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline typename AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::const_iterator AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::erase(ValueType const &value)
{
Callback callback(sourceObject, ADOO_erase);
return AutoDeltaSet<ValueType, ObjectType>::erase(value);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline typename AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::const_iterator AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::erase(const_iterator & i)
{
Callback callback(sourceObject, ADOO_erase);
return AutoDeltaSet<ValueType, ObjectType>::erase(i);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::insert(ValueType const &value)
{
Callback callback(sourceObject, ADOO_insert);
AutoDeltaSet<ValueType, ObjectType>::insert(value);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::unpack(ReadIterator &source)
{
Callback callback(sourceObject, ADOO_unpack);
AutoDeltaSet<ValueType, ObjectType>::unpack(source);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaSetObserver<ValueType, Callback, SourceObjectType, ObjectType>::unpackDelta(ReadIterator &source)
{
Callback callback(sourceObject, ADOO_unpackDelta);
AutoDeltaSet<ValueType, ObjectType>::unpackDelta(source);
}
//-----------------------------------------------------------------------
}
// ======================================================================
#endif
@@ -0,0 +1,240 @@
#ifndef _INCLUDED_AutoDeltaVariableCallback_H
#define _INCLUDED_AutoDeltaVariableCallback_H
#include "AutoDeltaByteStream.h"
namespace Archive {
/**
@brief an authoritative variable that provides notification when changed
An AutoDeltaVariableCallback is an AutoDeltaVariable. It extends the functionality
of AutoDeltaVariable by providing an interface for getting callbacks when the value changes.
To use the AutoDeltaVariableCallback, you must pass it a callback structure. An example is provided here:
struct ExampleDataCallback
{
void modified(TangibleObject & target, const std::string & value) const;
};
This simple structure defines only one function, which will be invoked by the AutoDeltaVariableCallback
when the variable is changed by a set(), operator=, or unpack() method.
Then to declare an AutoDeltaVariableCallback as a member of an example class you might:
class MyExampleClass
{
private:
struct ExampleDataCallback
{
//define modified to call MyExampleClass::dataModified(value)
void modified(MyExampleClass & target, ValueType & value) const {target.dataModified(value);}
};
//Friend it so that outsiders don't screw with the callback function but so that it can use it.
friend struct ExampleDataCallback;
void dataModified(ValueType & value);
Archive::AutoDeltaVariableCallback<ValueType, ExampleDataCallback, MyExampleClass> m_data;
};
In the constructor of MyExampleClass:
m_data->setSourceObject(this); //This registers the correct instance of the object with the variable
addVariable(m_data); //See AutoDeltaVariable for why this is done.
@see AutoDeltaVariable
@see AutoDeltaVariableBase
@author Chris Mayer
*/
template<class ValueType, class Callback, class SourceObjectType>
class AutoDeltaVariableCallback : public AutoDeltaVariable<ValueType>
{
public:
AutoDeltaVariableCallback();
AutoDeltaVariableCallback(const AutoDeltaVariableCallback & source);
explicit AutoDeltaVariableCallback(const ValueType & source);
~AutoDeltaVariableCallback();
AutoDeltaVariableCallback & operator = (const AutoDeltaVariableCallback & source);
AutoDeltaVariableCallback & operator = (const ValueType & source);
virtual void set(const ValueType & source);
void setSourceObject(SourceObjectType * source);
virtual void unpack(ReadIterator & source);
virtual void unpackDelta(ReadIterator & source);
private:
Callback callback;
SourceObjectType* sourceObject;
};
//----------------------------------------------------------------
/**
@brief default AutoDeltaVariableCallback constructor
@author Chris Mayer
@see AutoDeltaVariable
*/
template<class ValueType, class Callback, class SourceObjectType>
inline AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::AutoDeltaVariableCallback() :
AutoDeltaVariable<ValueType>(),
sourceObject(0)
{
}
//----------------------------------------------------------------
/**
@brief default AutoDeltaVariableCallback copy constructor
@author Chris Mayer
@see AutoDeltaVariable
*/
template<class ValueType, class Callback, class SourceObjectType>
inline AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::AutoDeltaVariableCallback(const AutoDeltaVariableCallback & source) :
AutoDeltaVariable<ValueType>(source),
sourceObject(0)
{
}
//----------------------------------------------------------------
/**
@brief default AutoDeltaVariableCallback constructor given value
@author Chris Mayer
@see AutoDeltaVariable
*/
template<class ValueType, class Callback, class SourceObjectType>
inline AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::AutoDeltaVariableCallback(const ValueType & source) :
AutoDeltaVariable<ValueType>(source),
sourceObject(0)
{
}
//----------------------------------------------------------------
/**
@brief default AutoDeltaVariableCallback destructor
@author Chris Mayer
@see AutoDeltaVariable
*/
template<class ValueType, class Callback, class SourceObjectType>
inline AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::~AutoDeltaVariableCallback()
{
}
//----------------------------------------------------------------
template<class ValueType, class Callback, class SourceObjectType>
inline AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType> & AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::operator =(const AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType> & rhs)
{
if (&rhs != this)
set(rhs.get());
return *this;
}
//-----------------------------------------------------------------------
template<class ValueType, class Callback, class SourceObjectType>
inline AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType> & AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::operator = (const ValueType & rhs)
{
if (rhs != this->get())
set(rhs);
return *this;
}
//-----------------------------------------------------------------------
/**
@brief setSourceObject registers the object that owns the variable so that we can provide callback notification.
This function should be called in the owning classes constructor before it is used.
Failure to call this function before the variable's first use will cause an assertion failure.
@author Chris Mayer
@see AutoDeltaVariable
*/
template<class ValueType, class Callback, class SourceObjectType>
inline void AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::setSourceObject(SourceObjectType * source)
{
sourceObject = source;
}
//-----------------------------------------------------------------------
/**
@brief overload AutoDeltaVariable::set to provide for callback notification
::set() will notifiy the callback object after setting the value by calling the base class ::set() function.
@author Chris Mayer
@see AutoDeltaVariable
*/
template<class ValueType, class Callback, class SourceObjectType>
inline void AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::set(const ValueType & source)
{
ValueType const tmp = this->get();
AutoDeltaVariable<ValueType>::set(source);
if (sourceObject != NULL && tmp != source)
callback.modified(*sourceObject, tmp, source, true);
}
//-----------------------------------------------------------------------
/**
@brief overload AutoDeltaVariable::unpack to provide for callback notification
::unpack() will notifiy the callback object after setting the value by calling the base class ::unpack() function.
@author Chris Mayer
@see AutoDeltaVariable
*/
template<class ValueType, class Callback, class SourceObjectType>
inline void AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::unpack(ReadIterator & source)
{
ValueType const before = this->get();
AutoDeltaVariable<ValueType>::unpack(source);
if (sourceObject)
{
ValueType const &after = this->get();
if (before != after)
callback.modified(*sourceObject, before, after, false);
}
}
//-----------------------------------------------------------------------
template<class ValueType, class Callback, class SourceObjectType>
inline void AutoDeltaVariableCallback<ValueType, Callback, SourceObjectType>::unpackDelta(ReadIterator & source)
{
ValueType const before = this->get();
AutoDeltaVariable<ValueType>::unpackDelta(source);
if (sourceObject)
{
ValueType const &after = this->get();
if (before != after)
callback.modified(*sourceObject, before, after, false);
}
}
//-----------------------------------------------------------------------
}
#endif
@@ -0,0 +1,131 @@
#ifndef _INCLUDED_AutoDeltaVariableObserver_H
#define _INCLUDED_AutoDeltaVariableObserver_H
#include "AutoDeltaByteStream.h"
#include "AutoDeltaObserverOps.h"
namespace Archive {
/**
@brief an authoritative variable that provides notification both prior to and after change
*/
template<class ValueType, typename Callback, class SourceObjectType>
class AutoDeltaVariableObserver : public AutoDeltaVariable<ValueType>
{
public:
AutoDeltaVariableObserver();
AutoDeltaVariableObserver(const AutoDeltaVariableObserver & source);
explicit AutoDeltaVariableObserver(const ValueType & source);
~AutoDeltaVariableObserver();
AutoDeltaVariableObserver & operator = (const AutoDeltaVariableObserver & source);
AutoDeltaVariableObserver & operator = (const ValueType & source);
virtual void set(const ValueType & source);
void setSourceObject(SourceObjectType * source);
virtual void unpack(ReadIterator & source);
virtual void unpackDelta(ReadIterator & source);
private:
SourceObjectType* sourceObject;
};
//----------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::AutoDeltaVariableObserver() :
AutoDeltaVariable<ValueType>(),
sourceObject(0)
{
}
//----------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::AutoDeltaVariableObserver(const AutoDeltaVariableObserver & source) :
AutoDeltaVariable<ValueType>(source),
sourceObject(0)
{
}
//----------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::AutoDeltaVariableObserver(const ValueType & source) :
AutoDeltaVariable<ValueType>(source),
sourceObject(0)
{
}
//----------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::~AutoDeltaVariableObserver()
{
}
//----------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType> & AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::operator =(const AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType> & rhs)
{
if (&rhs != this)
set(rhs.get());
return *this;
}
//-----------------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType> & AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::operator = (const ValueType & rhs)
{
if (rhs != this->get())
set(rhs);
return *this;
}
//-----------------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline void AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::setSourceObject(SourceObjectType * source)
{
sourceObject = source;
}
//-----------------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline void AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::set(const ValueType & source)
{
Callback callback(sourceObject, ADOO_set);
AutoDeltaVariable<ValueType>::set(source);
}
//-----------------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline void AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::unpack(ReadIterator & source)
{
Callback callback(sourceObject, ADOO_unpack);
AutoDeltaVariable<ValueType>::unpack(source);
}
//-----------------------------------------------------------------------
template<class ValueType, typename Callback, class SourceObjectType>
inline void AutoDeltaVariableObserver<ValueType, Callback, SourceObjectType>::unpackDelta(ReadIterator & source)
{
Callback callback(sourceObject, ADOO_unpackDelta);
AutoDeltaVariable<ValueType>::unpackDelta(source);
}
//-----------------------------------------------------------------------
}
#endif
@@ -0,0 +1,796 @@
#ifndef _INCLUDED_AutoDeltaVector_H
#define _INCLUDED_AutoDeltaVector_H
//-----------------------------------------------------------------------
#include "AutoDeltaByteStream.h"
//-----------------------------------------------------------------------
namespace Archive {
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType=DefaultObjectType>
class AutoDeltaVector : public AutoDeltaContainer
{
typedef typename std::vector<ValueType>::size_type size_type;
public:
typedef typename std::vector<ValueType>::const_iterator const_iterator;
typedef typename std::vector<ValueType>::const_reverse_iterator const_reverse_iterator;
typedef std::vector<ValueType> VectorType;
public:
struct Command
{
enum
{
ERASE,
INSERT,
SET,
SETALL,
CLEAR
};
unsigned char cmd;
unsigned short int index;
ValueType value;
};
public:
AutoDeltaVector();
explicit AutoDeltaVector(size_t initialSize);
~AutoDeltaVector();
const ValueType & back () const;
const_iterator begin () const;
void clearDelta () const;
const_iterator end () const;
const int find (const ValueType & t) const;
const ValueType & front () const;
const VectorType & get () const;
const ValueType & get (const unsigned int element) const;
const bool isDirty () const;
void pack (ByteStream & target) const;
void packDelta (ByteStream & target) const;
void reserve (size_type n);
void resize (size_type n, ValueType x = ValueType());
virtual void clear ();
virtual void erase (const unsigned int element);
virtual void pop_back ();
virtual void push_back (const ValueType & t);
virtual void insert (const unsigned int before, const ValueType & newValue);
virtual void set (const unsigned int element, const ValueType & newValue);
virtual void set (const VectorType & newValue);
virtual void unpack (ReadIterator & source);
virtual void unpackDelta (ReadIterator & source);
static void pack (ByteStream & target, const std::vector<ValueType> & data);
static void unpack (ReadIterator & source, std::vector<Command> & data);
static void unpackDelta (ReadIterator & source, std::vector<Command> & data);
void setOnChanged (ObjectType * owner, void (ObjectType::*onChanged)());
void setOnErase (ObjectType * owner, void (ObjectType::*onErase)(const unsigned int, const ValueType &));
void setOnInsert (ObjectType * owner, void (ObjectType::*onInsert)(const unsigned int, const ValueType &));
void setOnSet (ObjectType * owner, void (ObjectType::*onSet)(const unsigned int, const ValueType &, const ValueType &));
const size_t size () const;
bool empty () const;
const ValueType & operator[] (const unsigned int element) const;
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
private:
void packCommand(const Command & command, ByteStream & target) const;
void onChanged();
void onErase(const unsigned int, const ValueType &);
void onInsert(const unsigned int, const ValueType &);
void onSet(const unsigned int, const ValueType &, const ValueType &);
private:
std::vector<ValueType> v;
size_t baselineCommandCount;
mutable std::vector<Command> commands;
std::pair<ObjectType *, void (ObjectType::*)()> * onChangedCallback;
std::pair<ObjectType *, void (ObjectType::*)(const unsigned int, const ValueType &)> * onEraseCallback;
std::pair<ObjectType *, void (ObjectType::*)(const unsigned int, const ValueType &)> * onInsertCallback;
std::pair<ObjectType *, void (ObjectType::*)(const unsigned int, const ValueType &, const ValueType &)> * onSetCallback;
private:
AutoDeltaVector(const AutoDeltaVector &);
};
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline AutoDeltaVector<ValueType, ObjectType>::AutoDeltaVector() :
AutoDeltaContainer(),
v(),
baselineCommandCount(0),
commands(),
onChangedCallback(0),
onEraseCallback(0),
onInsertCallback(0),
onSetCallback(0)
{
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline AutoDeltaVector<ValueType, ObjectType>::AutoDeltaVector(size_t initialSize) :
AutoDeltaContainer(),
v(initialSize),
baselineCommandCount(0),
commands(),
onChangedCallback(0),
onEraseCallback(0),
onInsertCallback(0),
onSetCallback(0)
{
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline AutoDeltaVector<ValueType, ObjectType>::~AutoDeltaVector()
{
delete onChangedCallback;
delete onEraseCallback;
delete onInsertCallback;
delete onSetCallback;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaVector<ValueType, ObjectType>::const_iterator AutoDeltaVector<ValueType, ObjectType>::begin() const
{
return v.begin();
}
//-----------------------------------------------------------------------
/**
* @todo this is very inefficient
*/
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::clear()
{
if (!empty())
{
Command c;
c.cmd = Command::CLEAR;
commands.push_back(c);
++baselineCommandCount;
for (unsigned int i = 0; i < v.size(); ++i)
onErase(i, v[i]);
v.clear();
touch();
onChanged();
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const ValueType & AutoDeltaVector<ValueType, ObjectType>::back() const
{
return v.back();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::clearDelta() const
{
commands.clear();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaVector<ValueType, ObjectType>::const_iterator AutoDeltaVector<ValueType, ObjectType>::end() const
{
return v.end();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::erase(const unsigned int element)
{
if(element < size())
{
Command c;
c.cmd = Command::ERASE;
//-- cast to shorts to reduce net traffic. If we are synchronizing
// vectors with more than 65,535 elements, we have some serious
// design issues
c.index = static_cast<unsigned short>(element);
//--
commands.push_back(c);
++baselineCommandCount;
typename std::vector<ValueType>::iterator i = v.begin();
std::advance(i, element);
ValueType old = (*i);
v.erase(i);
touch();
onErase(element, old);
onChanged();
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const int AutoDeltaVector<ValueType, ObjectType>::find(const ValueType & item) const
{
int count = 0;
for (typename std::vector<ValueType>::const_iterator i = v.begin(); i != v.end(); ++i)
{
if (item == (*i))
{
return count;
}
++count;
}
return -1;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const ValueType & AutoDeltaVector<ValueType, ObjectType>::front() const
{
assert (!v.empty ());
return v.front();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const ValueType & AutoDeltaVector<ValueType, ObjectType>::get(const unsigned int element) const
{
assert (v.size () > element);
return v[element];
}
//----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const typename AutoDeltaVector<ValueType, ObjectType>::VectorType & AutoDeltaVector<ValueType, ObjectType>::get() const
{
return v;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::insert(const unsigned int before, const ValueType & newValue)
{
Command c;
c.cmd = Command::INSERT;
c.index = static_cast<unsigned short>(before);
c.value = newValue;
commands.push_back(c);
++baselineCommandCount;
if (v.size() < before)
v.resize(before);
typename std::vector<ValueType>::iterator i = v.begin();
std::advance(i, before);
v.insert(i, newValue);
touch();
onInsert(before, newValue);
onChanged();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const bool AutoDeltaVector<ValueType, ObjectType>::isDirty() const
{
return commands.size() > 0;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::onChanged()
{
if(onChangedCallback)
{
if(onChangedCallback->first)
{
ObjectType & owner = *onChangedCallback->first;
void (ObjectType::*cb)() = onChangedCallback->second;
(owner.*cb)();
}
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::onErase(const unsigned int element, const ValueType & oldValue)
{
if(onEraseCallback)
{
if(onEraseCallback->first)
{
ObjectType & owner = *onEraseCallback->first;
void (ObjectType::*cb)(const unsigned int, const ValueType &) = onEraseCallback->second;
(owner.*cb)(element, oldValue);
}
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::onInsert(const unsigned int element, const ValueType & newValue)
{
if(onInsertCallback)
{
if(onInsertCallback->first)
{
ObjectType & owner = *onInsertCallback->first;
void (ObjectType::*cb)(const unsigned int, const ValueType &) = onInsertCallback->second;
(owner.*cb)(element, newValue);
}
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::onSet(const unsigned int element, const ValueType & oldValue, const ValueType & newValue)
{
if(onSetCallback)
{
if(onSetCallback->first)
{
ObjectType & owner = *onSetCallback->first;
void (ObjectType::*cb)(const unsigned int, const ValueType &, const ValueType &) = onSetCallback->second;
(owner.*cb)(element, oldValue, newValue);
}
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::pack(ByteStream & target) const
{
Archive::put(target, v.size());
Archive::put(target, baselineCommandCount);
typename std::vector<ValueType>::const_iterator i;
for (i = v.begin(); i != v.end(); ++i)
{
Archive::put(target, (*i));
}
}
// ----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::pack(ByteStream & target, const std::vector<ValueType> & data)
{
Archive::put(target, data.size());
Archive::put(target, static_cast<size_t>(0)); // baselineCommandCount
typename std::vector<ValueType>::const_iterator i;
for (i = data.begin(); i != data.end(); ++i)
{
Archive::put(target, *i);
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::packDelta(ByteStream & target) const
{
Archive::put(target, commands.size());
Archive::put(target, baselineCommandCount);
typename std::vector<Command>::iterator i;
for (i = commands.begin(); i != commands.end(); ++i)
{
const Command & c = (*i);
Archive::put(target, c.cmd);
switch(c.cmd)
{
case Command::ERASE:
Archive::put(target, c.index);
break;
case Command::INSERT:
Archive::put(target, c.index);
Archive::put(target, c.value);
break;
case Command::SET:
Archive::put(target, c.index);
Archive::put(target, c.value);
break;
case Command::SETALL:
{
Archive::put(target, c.index); // size
for (unsigned int j = 0; j < c.index; ++j)
{
++i;
Archive::put(target, (*i).value);
}
}
break;
case Command::CLEAR:
break;
}
}
clearDelta();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::pop_back()
{
if (v.size() > 0)
AutoDeltaVector::erase(v.size() - 1);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::push_back(const ValueType & t)
{
AutoDeltaVector::insert(v.size(), t);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaVector<ValueType, ObjectType>::const_reverse_iterator AutoDeltaVector<ValueType, ObjectType>::rbegin() const
{
return v.rbegin();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline typename AutoDeltaVector<ValueType, ObjectType>::const_reverse_iterator AutoDeltaVector<ValueType, ObjectType>::rend() const
{
return v.rend();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::reserve(size_type n)
{
v.reserve(n);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::resize(size_type n, ValueType x)
{
size_type size = v.size();
if (size < n)
{
// expand the vector
v.resize(n);
for (size_t i = size; i < n; ++i)
set(i, x);
}
else if (size > n)
{
// contract the vector
for (size_t i = size - 1; i >= n; --i)
{
erase(i);
//-- must do this since our counter is unsigned
if (i == 0)
break;
}
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::set(const unsigned int element, const ValueType & newValue)
{
if (element < v.size () && v[element] == newValue)
return;
Command c;
c.cmd = Command::SET;
c.index = static_cast<unsigned short>(element);
c.value = newValue;
commands.push_back(c);
++baselineCommandCount;
if(element >= v.size())
v.resize(element + 1);
ValueType old = v[element];
v[element] = newValue;
touch();
onSet(element, old, newValue);
onChanged();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::set(const VectorType & newValue)
{
Command c;
c.cmd = Command::SETALL;
c.index = static_cast<unsigned short>(newValue.size());
commands.push_back(c);
++baselineCommandCount;
v = newValue;
for (unsigned int i = 0; i < newValue.size(); ++i)
{
c.cmd = Command::SET;
c.index = static_cast<unsigned short>(i);
c.value = v[i];
commands.push_back(c);
++baselineCommandCount;
}
touch();
onChanged();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::setOnChanged(ObjectType * owner, void (ObjectType::*cb)())
{
delete onChangedCallback;
onChangedCallback = new std::pair<ObjectType *, void (ObjectType::*)()>;
onChangedCallback->first = owner;
onChangedCallback->second = cb;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::setOnErase(ObjectType * owner, void (ObjectType::*cb)(const unsigned int, const ValueType &))
{
delete onEraseCallback;
onEraseCallback = new std::pair<ObjectType *, void (ObjectType::*)(const unsigned int, const ValueType &)>;
onEraseCallback->first = owner;
onEraseCallback->second = cb;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::setOnInsert(ObjectType * owner, void (ObjectType::*cb)(const unsigned int, const ValueType &))
{
delete onInsertCallback;
onInsertCallback = new std::pair<ObjectType *, void (ObjectType::*)(const unsigned int, const ValueType &)>;
onInsertCallback->first = owner;
onInsertCallback->second = cb;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::setOnSet(ObjectType * owner, void (ObjectType::*cb)(const unsigned int, const ValueType &, const ValueType &))
{
delete onSetCallback;
onSetCallback = new std::pair<ObjectType *, void (ObjectType::*)(const unsigned int, const ValueType &, const ValueType &)>;
onSetCallback->first = owner;
onSetCallback->second = cb;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline bool AutoDeltaVector<ValueType, ObjectType>::empty() const
{
return v.empty();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const size_t AutoDeltaVector<ValueType, ObjectType>::size() const
{
return v.size();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::unpack(ReadIterator & source)
{
// unpacking the whole kazaba
v.clear();
clearDelta();
size_t commandCount;
ValueType value;
Archive::get(source, commandCount);
Archive::get(source, baselineCommandCount);
for (size_t i = 0; i < commandCount; ++i)
{
Archive::get(source, value);
v.push_back(value);
}
onChanged();
}
// ----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::unpack(ReadIterator & source, std::vector<Command> & data)
{
// unpacking the whole kazaba
size_t commandCount;
size_t bcc;
Command c;
Archive::get(source, commandCount);
Archive::get(source, bcc);
for (size_t i = 0; i < commandCount; ++i)
{
Archive::get(source,c.value);
c.index = static_cast<unsigned short int>(i);
c.cmd = Command::INSERT;
data.push_back(c);
}
}
// ----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::unpackDelta(ReadIterator & source, std::vector<Command> & data)
{
Command c;
size_t commandCount, targetBaselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, targetBaselineCommandCount);
for (size_t i=0 ; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
switch (c.cmd)
{
case Command::ERASE:
Archive::get(source, c.index);
break;
case Command::INSERT:
Archive::get(source, c.index);
Archive::get(source, c.value);
break;
case Command::SET:
Archive::get(source, c.index);
Archive::get(source, c.value);
break;
case Command::SETALL: // SETALL is not supported by the static AutoDeltaVector unpack function, because there's no place to put the value
assert(false);
case Command::CLEAR:
break;
default:
assert(false);
break;
}
data.push_back(c);
}
}
//-----------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline void AutoDeltaVector<ValueType, ObjectType>::unpackDelta(ReadIterator & source)
{
Command c;
size_t skipCount, commandCount, targetBaselineCommandCount;
Archive::get(source, commandCount);
Archive::get(source, targetBaselineCommandCount);
skipCount = commandCount+baselineCommandCount-targetBaselineCommandCount;
// note: SETALL commands come across with a command count of 1+newsize
if (skipCount > commandCount)
skipCount = commandCount;
size_t i;
for (i = 0; i < skipCount; ++i)
{
Archive::get(source, c.cmd);
if (c.cmd != Command::CLEAR)
Archive::get(source, c.index);
if (c.cmd == Command::SETALL)
{
for (unsigned int j = 0; j < c.index; ++j)
{
++i;
Archive::get(source, c.value);
}
}
else if (c.cmd != Command::ERASE && c.cmd != Command::CLEAR)
Archive::get(source, c.value);
}
for ( ; i < commandCount; ++i)
{
Archive::get(source, c.cmd);
switch (c.cmd)
{
case Command::ERASE:
{
Archive::get(source, c.index);
AutoDeltaVector::erase(c.index);
}
break;
case Command::INSERT:
{
Archive::get(source, c.index);
Archive::get(source, c.value);
AutoDeltaVector::insert(c.index, c.value);
}
break;
case Command::SET:
{
Archive::get(source, c.index);
Archive::get(source, c.value);
AutoDeltaVector::set(c.index, c.value);
}
break;
case Command::SETALL:
{
Archive::get(source, c.index); // size
VectorType tempVec;
tempVec.reserve(c.index);
ValueType value;
for (unsigned int j = 0; j < c.index; ++j)
{
++i;
Archive::get(source, value);
tempVec.push_back(value);
}
AutoDeltaVector::set(tempVec);
}
break;
case Command::CLEAR:
AutoDeltaVector::clear();
break;
}
}
}
//---------------------------------------------------------------------
template<typename ValueType, typename ObjectType>
inline const ValueType & AutoDeltaVector<ValueType, ObjectType>::operator[] (const unsigned int element) const
{
return get(element);
}
//---------------------------------------------------------------------
}//namespace Archive
#endif // _INCLUDED__AutoDeltaVector_H
@@ -0,0 +1,192 @@
#ifndef _INCLUDED_AutoDeltaVectorObserver_H
#define _INCLUDED_AutoDeltaVectorObserver_H
#include "AutoDeltaVector.h"
#include "AutoDeltaObserverOps.h"
namespace Archive {
/**
@brief an authoritative variable that provides notification both prior to and after change
*/
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType=DefaultObjectType>
class AutoDeltaVectorObserver : public AutoDeltaVector<ValueType, ObjectType>
{
public:
typedef std::vector<ValueType> VectorType;
AutoDeltaVectorObserver();
AutoDeltaVectorObserver(const AutoDeltaVectorObserver & source);
explicit AutoDeltaVectorObserver(const ValueType & source);
~AutoDeltaVectorObserver();
AutoDeltaVectorObserver & operator = (const AutoDeltaVectorObserver & source);
AutoDeltaVectorObserver & operator = (const ValueType & source);
void setSourceObject(SourceObjectType * source);
virtual void clear ();
virtual void erase (const unsigned int element);
virtual void pop_back ();
virtual void push_back (const ValueType & t);
virtual void insert (const unsigned int before, const ValueType &newValue);
virtual void set (const unsigned int element, const ValueType &source);
virtual void set (const VectorType & newValue);
virtual void unpack (ReadIterator & source);
virtual void unpackDelta (ReadIterator & source);
private:
SourceObjectType* sourceObject;
};
//----------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::AutoDeltaVectorObserver() :
AutoDeltaVector<ValueType, ObjectType>(),
sourceObject(0)
{
}
//----------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::AutoDeltaVectorObserver(const AutoDeltaVectorObserver & source) :
AutoDeltaVector<ValueType, ObjectType>(source),
sourceObject(0)
{
}
//----------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::AutoDeltaVectorObserver(const ValueType & source) :
AutoDeltaVector<ValueType, ObjectType>(source),
sourceObject(0)
{
}
//----------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::~AutoDeltaVectorObserver()
{
}
//----------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType> & AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::operator =(const AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType> & rhs)
{
if (&rhs != this)
set(rhs.get());
return *this;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType> & AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::operator = (const ValueType & rhs)
{
if (rhs != this->get())
set(rhs);
return *this;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::setSourceObject(SourceObjectType * source)
{
sourceObject = source;
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::clear()
{
Callback callback(sourceObject, ADOO_clear);
AutoDeltaVector<ValueType, ObjectType>::clear();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::erase(const unsigned int element)
{
Callback callback(sourceObject, ADOO_erase);
AutoDeltaVector<ValueType, ObjectType>::erase(element);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::pop_back()
{
Callback callback(sourceObject, ADOO_pop_back);
AutoDeltaVector<ValueType, ObjectType>::pop_back();
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::push_back(const ValueType & t)
{
Callback callback(sourceObject, ADOO_push_back);
AutoDeltaVector<ValueType, ObjectType>::push_back(t);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::insert(const unsigned int before, const ValueType &newValue)
{
Callback callback(sourceObject, ADOO_insert);
AutoDeltaVector<ValueType, ObjectType>::insert(before, newValue);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::set(const unsigned int element, const ValueType & source)
{
Callback callback(sourceObject, ADOO_set);
AutoDeltaVector<ValueType, ObjectType>::set(element, source);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::set(const VectorType &newValue)
{
Callback callback(sourceObject, ADOO_setAll);
AutoDeltaVector<ValueType, ObjectType>::set(newValue);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::unpack(ReadIterator & source)
{
Callback callback(sourceObject, ADOO_unpack);
AutoDeltaVector<ValueType, ObjectType>::unpack(source);
}
//-----------------------------------------------------------------------
template<typename ValueType, typename Callback, class SourceObjectType, typename ObjectType>
inline void AutoDeltaVectorObserver<ValueType, Callback, SourceObjectType, ObjectType>::unpackDelta(ReadIterator & source)
{
Callback callback(sourceObject, ADOO_unpackDelta);
AutoDeltaVector<ValueType, ObjectType>::unpackDelta(source);
}
//-----------------------------------------------------------------------
}
#endif
+371
View File
@@ -0,0 +1,371 @@
//---------------------------------------------------------------------
#include "FirstArchive.h"
#include "ByteStream.h"
#include "ArchiveMutex.h"
#include <cassert>
// ======================================================================
//static volatile int s_dataFreeListLocked;
static Archive::ArchiveMutex s_archiveMutex;
// ======================================================================
namespace Archive {
//---------------------------------------------------------------------
/**
@brief ReadIterator ctor
Initializes the read position to zero, and the ByteStream member value
is NULL
*/
ReadIterator::ReadIterator() :
readPtr(0),
stream(0)
{
}
//---------------------------------------------------------------------
/**
@brief ReadIterator copy constructor
Sets the current position to the source read position and the
ByteStream pointer to the source ByteStream.
*/
ReadIterator::ReadIterator(const ReadIterator & source) :
readPtr(source.readPtr),
stream(source.stream)
{
}
//---------------------------------------------------------------------
/**
@brief construct a read iterator with the position at zero and
the ByteStream set to the source.
*/
ReadIterator::ReadIterator(ByteStream const &source) :
readPtr(0),
stream(&source)
{
}
//---------------------------------------------------------------------
/**
@brief destroy a read iterator object, set the ByteStream member to
zero.
*/
ReadIterator::~ReadIterator()
{
stream = 0;
}
//---------------------------------------------------------------------
/**
Comparison operator
Indicates whether the two iterators point to the same place in the
same bytestream.
@author Acy Stapp
*/
bool ReadIterator::operator==(ReadIterator const &rhs) const
{
// We are almost guaranteed to be comparing iterators from the same
// bytestream, so we put that test last, giving the other test a
// chance to fail and avoid the almost certainty.
if (readPtr != rhs.readPtr)
return false;
return stream == rhs.stream;
}
//---------------------------------------------------------------------
/**
Construct an ByteStream object.
This constructor merely initializes members, No buffer allocation
occurs.
@author Justin Randall
*/
ByteStream::ByteStream() :
allocatedSize(0),
allocatedSizeLimit(0),
beginReadIterator(),
data(0),
size(0)
{
beginReadIterator = ReadIterator(*this);
}
//---------------------------------------------------------------------
/**
@brief Construct an ByteStream from a byte buffer
@author Justin Randall
*/
ByteStream::ByteStream(unsigned char const * const newBuffer, const unsigned int bufferSize) :
allocatedSize(bufferSize),
allocatedSizeLimit(0),
data(0),
size(bufferSize)
{
data = Data::getNewData();
if (data->size < size)
{
delete[] data->buffer;
if(size > 0)
data->buffer = new unsigned char[size];
else
data->buffer = 0;
data->size = size;
}
if (size > 0)
memcpy(data->buffer, newBuffer, size);
beginReadIterator = ReadIterator(*this);
}
//---------------------------------------------------------------------
/**
ByteStream Copy Constructor
*/
ByteStream::ByteStream(ByteStream const &source):
allocatedSize(source.getSize()), // only allocate what is really there, be opportinistic when grow()'ing
allocatedSizeLimit(0),
data(source.data),
size(source.getSize())
{
if (source.data)
source.data->ref();
beginReadIterator = ReadIterator(*this);
}
//-----------------------------------------------------------------------
/**
@brief ByteStream copy constructor
Creates a new byte stream, deep copying the source stream from the
source read iterator.
*/
ByteStream::ByteStream(ReadIterator &source) :
allocatedSize(0),
allocatedSizeLimit(0),
data(Data::getNewData()),
size(0)
{
put(source.getBuffer(), source.getSize());
source.advance(source.getSize());
beginReadIterator = ReadIterator(*this);
}
//---------------------------------------------------------------------
/**
ByteStream destructor
Deletes the assocated buffer and resets allocateSize, buffer, and
size to zero.
@author Justin Randall
*/
ByteStream::~ByteStream()
{
if (data)
{
data->deref();
data = 0; //lint !e672 (data deref insures the data is deleted if no one references it)
}
allocatedSize = 0;
size = 0;
}
//---------------------------------------------------------------------
/**
Assignment operator
If the ByteStream right hand side is not the same ByteStream, performs
a deep copy of the ByteStream.
@author Justin Randall
*/
ByteStream &ByteStream::operator=(ByteStream const &rhs)
{
if (this != &rhs)
{
if (data)
data->deref(); // deref local data
if (rhs.data)
rhs.data->ref();
allocatedSize = rhs.allocatedSize;
allocatedSizeLimit = rhs.allocatedSizeLimit;
size = rhs.size;
data = rhs.data; //lint !e672 (data is ref counted)
}
return *this;
}
//---------------------------------------------------------------------
/**
@brief Accesses ByteStream data
@param target a user supplied buffer that must be at least as
large as targetSize
@param readIterator An accessor that indicates where the read operation
will begin
@param targetSize specifies the number of bytes to read from the
ByteStream
@author Justin Randall
*/
void ByteStream::get(void *target, ReadIterator &readIterator, const unsigned long int targetSize) const
{
if (data && readIterator.getReadPosition() + targetSize <= allocatedSize)
{
memcpy(target, &data->buffer[readIterator.getReadPosition()], targetSize);
}
else
{
static const char * const desc = "Archive::ByteStream - read beyond end of buffer";
ReadException ex(desc);
throw (ex);
}
}
//---------------------------------------------------------------------
/**
@brief deep copy new data to the ByteStream
If the data member is shared with another ByteStream, then it is
copied before this operation begins. The ByteStream buffer is increased
to hold the new data (determined by the requested sourceSize).
@param source a user supplied buffer that contains data to be
copied to the ByteStream
@param sourceSize The number of bytes in the source buffer which
will be copied to the ByteStream.
@author Justin Randall
*/
void ByteStream::put(void const * const source, const unsigned int sourceSize)
{
if (!data)
data = Data::getNewData();
if (data->getRef() > 1)
{
unsigned char const * const tmp = data->buffer;
data->deref();
data = Data::getNewData();
if (data->size < sourceSize)
{
delete[] data->buffer;
if (size > 0)
data->buffer = new unsigned char[size];
else
data->buffer = 0;
data->size = size;
}
if (size > 0)
memcpy(data->buffer, tmp, size);
allocatedSize = size;
}
growToAtLeast(size + sourceSize);
memcpy(&data->buffer[size], source, sourceSize);
size += sourceSize;
}
//---------------------------------------------------------------------
void ByteStream::reAllocate(const unsigned int newSize)
{
allocatedSize = newSize;
if (!data)
data = Data::getNewData();
if (data->size < allocatedSize)
{
unsigned char * tmp = new unsigned char[newSize];
if (data->buffer)
memcpy(tmp, data->buffer, size);
delete[] data->buffer;
data->buffer = tmp;
data->size = newSize;
}
}
//---------------------------------------------------------------------
std::vector<ByteStream::Data *> &ByteStream::Data::lockDataFreeList()
{
static DataFreeList freeList;
s_archiveMutex.enter();
return freeList.freeList;
}
//-----------------------------------------------------------------------
void ByteStream::Data::unlockDataFreeList()
{
s_archiveMutex.leave();
}
//-----------------------------------------------------------------------
ByteStream::Data *ByteStream::Data::getNewData()
{
Data *result = 0;
std::vector<Data *> &dataFreeList = lockDataFreeList();
if (dataFreeList.empty())
{
unlockDataFreeList();
result = new Data;
}
else
{
result = dataFreeList.back();
dataFreeList.pop_back();
unlockDataFreeList();
}
result->refCount = 1;
return result;
}
//---------------------------------------------------------------------
void ByteStream::Data::releaseOldData(ByteStream::Data *oldData)
{
assert(reinterpret_cast<unsigned int>(oldData) != 0xefefefefu);
if (oldData->size > 4096)
delete oldData;
else
{
std::vector<Data *> &dataFreeList = lockDataFreeList();
if (dataFreeList.size() > 256)
delete oldData;
else
{
oldData->refCount = 0;
dataFreeList.push_back(oldData);
}
unlockDataFreeList();
}
}
//---------------------------------------------------------------------
}//namespace Archive
//---------------------------------------------------------------------
+408
View File
@@ -0,0 +1,408 @@
#ifndef _ByteStream_H
#define _ByteStream_H
//---------------------------------------------------------------------
#if WIN32
#pragma warning ( disable : 4786 ) // dentifier was truncated to '255' characters in the debug information
#pragma warning ( disable : 4514 ) // inlined function has been removed
#endif
#include <vector>
//---------------------------------------------------------------------
namespace Archive
{
//---------------------------------------------------------------------
class ReadException : public std::exception
{
public:
explicit ReadException(const char * const what);
ReadException(const ReadException & source);
ReadException & operator = (const ReadException & rhs);
~ReadException() throw();
const char * what() const throw();
private:
const char * m_what;
};
//---------------------------------------------------------------------
inline ReadException::ReadException(const char * what) :
m_what(what)
{
}
//---------------------------------------------------------------------
inline ReadException::ReadException(const ReadException & source) :
m_what(source.m_what)
{
}
//---------------------------------------------------------------------
inline ReadException::~ReadException() throw()
{
}
//---------------------------------------------------------------------
inline ReadException & ReadException::operator = (const ReadException & rhs)
{
m_what = rhs.m_what;
return *this;
}
//---------------------------------------------------------------------
inline const char * ReadException::what() const throw()
{
return m_what;
}
class ByteStream;
class ReadIterator
{
public:
ReadIterator ();
ReadIterator (const ReadIterator & source);
explicit ReadIterator (const ByteStream & source);
~ReadIterator ();
ReadIterator & operator = (const ReadIterator & source);
bool operator == (const ReadIterator & other) const;
bool operator != (const ReadIterator & other) const;
void advance (const unsigned int distance);
void get (void * target, const unsigned long int readSize);
const unsigned int getSize () const;
const unsigned char * const getBuffer () const;
const unsigned int getReadPosition () const;
private:
unsigned int readPtr;
const ByteStream * stream;
};
inline bool ReadIterator::operator != (const ReadIterator &other) const
{
return !(*this == other);
}
//---------------------------------------------------------------------
/** \class ByteStream ByteStream.h "Archive/ByteStream.h"
@brief A byte ByteStream
*/
class ByteStream
{
public: // ctor/dtors
ByteStream();
ByteStream(const unsigned char * const buffer, const unsigned int bufferSize);
ByteStream(const ByteStream & source);
virtual ~ByteStream();
typedef Archive::ReadIterator ReadIterator;
public: // inner classes
/** \class ReadIterator ByteStream.h "Archive/ByteStream.h"
@brief an iterator object used to retrieve data from a ByteStream
The ReadIterator is employed to coordinate multiple consumers of
a ByteStream object without altering the ByteStream itself. It is a const-like
iterator that will not change the contents of a ByteStream. Multiple ByteStream
consumers may access data in the ByteStream using ReadIterators.
@author Justin Randall
*/
public:
ByteStream(ReadIterator & source);
ByteStream & operator = (const ByteStream & source);
ByteStream & operator = (ReadIterator & source);
const ReadIterator & begin() const;
const ReadIterator end() const;
void clear();
const unsigned char * const getBuffer() const;
const unsigned int getSize() const;
void put(const void * const source, const unsigned int sourceSize);
void setAllocatedSizeLimit(unsigned int limit);
private:
void get(void * target, ReadIterator & readIterator, const unsigned long int readSize) const;
void growToAtLeast(const unsigned int targetSize);
void reAllocate(const unsigned int newSize);
private: // inner classes
class Data
{
public:
~Data();
static Data * getNewData();
const int getRef () const;
void deref ();
void ref ();
protected:
friend class ByteStream;
friend class Archive::ReadIterator;
unsigned char * buffer;
unsigned long size;
private:
struct DataFreeList
{
~DataFreeList()
{
std::vector<ByteStream::Data *>::iterator i;
for(i = freeList.begin(); i != freeList.end(); ++i)
{
delete (*i);
}
};
std::vector<Data *> freeList;
};
Data();
// explicit Data(unsigned char * buffer);
static std::vector<Data *> & lockDataFreeList();
static void unlockDataFreeList();
static void releaseOldData(Data * oldData);
private:
int refCount;
};
private:
friend class Archive::ReadIterator;
unsigned int allocatedSize;
unsigned int allocatedSizeLimit;
ReadIterator beginReadIterator;
Data * data;
unsigned int size;
}; //lint !e1934
//---------------------------------------------------------------------
inline ByteStream::Data::Data() :
buffer(0),
size(0),
refCount(1)
{
}
//---------------------------------------------------------------------
/*
inline ByteStream::Data::Data(unsigned char * newBuffer) :
buffer(newBuffer),
refCount(1)
{
}
*/
//---------------------------------------------------------------------
inline ByteStream::Data::~Data()
{
refCount = 0;
delete[] buffer;
}
//---------------------------------------------------------------------
inline void ByteStream::Data::deref()
{
refCount--;
if(refCount < 1)
releaseOldData(this);
// delete this;
}
//-----------------------------------------------------------------------
inline const int ByteStream::Data::getRef() const
{
return refCount;
}
//---------------------------------------------------------------------
inline void ByteStream::Data::ref()
{
refCount++;
}
//-----------------------------------------------------------------------
inline ReadIterator & ReadIterator::operator = (const ReadIterator & rhs)
{
if(&rhs != this)
{
readPtr = rhs.readPtr;
stream = rhs.stream;
}
return *this;
}
//---------------------------------------------------------------------
inline void ReadIterator::get(void * target, const unsigned long int readSize)
{
if(stream)
{
stream->get(target, *this, readSize);
readPtr += readSize;
}
else
{
static const char * const desc = "Archive::ReadIterator::get - read operation on null stream object";
ReadException ex(desc);
throw (ex);
}
}
//---------------------------------------------------------------------
inline const unsigned int ReadIterator::getSize() const
{
if(stream)
return stream->getSize() - readPtr;
return 0;
}
//---------------------------------------------------------------------
inline const ReadIterator & ByteStream::begin() const
{
return beginReadIterator;
}
//---------------------------------------------------------------------
inline const ReadIterator ByteStream::end() const
{
ReadIterator result(*this);
result.advance(size);
return result;
}
//---------------------------------------------------------------------
inline void ReadIterator::advance(const unsigned int distance)
{
readPtr += distance;
}
//---------------------------------------------------------------------
inline const unsigned int ReadIterator::getReadPosition() const
{
return readPtr;
}
//---------------------------------------------------------------------
inline const unsigned char * const ReadIterator::getBuffer() const
{
if(stream && stream->data)
return &stream->data->buffer[readPtr];
return 0;
}
//---------------------------------------------------------------------
/**
@brief clear read and write settings for the ByteStream
This does not free allocated memory. Instead, it keeps the ByteStream
buffer and sets the read and write pointers back to the beginning
of the ByteStream
@author Justin Randall
*/
inline void ByteStream::clear()
{
size = 0;
if ((allocatedSizeLimit) && (allocatedSize > allocatedSizeLimit))
{
if (data)
{
data->deref();
data = 0;
}
allocatedSize = 0;
reAllocate(allocatedSizeLimit);
}
}
//---------------------------------------------------------------------
/**
@brief get the whole ByteStream buffer (very const)
*/
inline const unsigned char * const ByteStream::getBuffer() const
{
if (data)
return data->buffer;
return 0;
}
//---------------------------------------------------------------------
/**
@brief Get the size, in bytes, of the ByteStream buffer
@return the size, in bytes, of the ByteStream buffer
@author Justin Randall
*/
inline const unsigned int ByteStream::getSize() const
{
return size;
}
//---------------------------------------------------------------------
/**
This private method ensures that the ByteStream buffer is large enough
to receive data at least as large as the requested targetSize.
@param unsigned int targetSize The desired size to increase the
ByteStream buffer.
@author Justin Randall
*/
inline void ByteStream::growToAtLeast(const unsigned int targetSize)
{
if(allocatedSize < targetSize)
{
if(allocatedSize < 4096)
{
reAllocate(allocatedSize + allocatedSize + targetSize);
}
else
{
reAllocate(allocatedSize + targetSize);
}
}
}
//---------------------------------------------------------------------
inline void ByteStream::setAllocatedSizeLimit(const unsigned int limit)
{
allocatedSizeLimit = limit;
if ((allocatedSizeLimit) && (allocatedSize < allocatedSizeLimit))
reAllocate(allocatedSizeLimit);
}
} // namespace Archive
//---------------------------------------------------------------------
#endif // _ByteStream_H
+19
View File
@@ -0,0 +1,19 @@
// FirstArchive.h
// copyright 2001 Verant Interactive
// Author: Justin Randall
#ifndef _INCLUDED_FirstArchive_H
#define _INCLUDED_FirstArchive_H
//-----------------------------------------------------------------------
#pragma warning ( disable : 4514 ) // unreferenced inline function has been removed
#pragma warning ( disable : 4710 ) // not inlined
#pragma warning ( disable : 4702 ) // unreachable code
#include "Archive.h"
#include "ByteStream.h"
#include <string>
//-----------------------------------------------------------------------
#endif // _INCLUDED_FirstArchive_H
@@ -0,0 +1,35 @@
// ======================================================================
//
//
// Copyright 6/19/2001 Sony Online Entertainment
//
// ======================================================================
#include "FirstArchive.h"
#include "ArchiveMutex.h"
namespace Archive
{
ArchiveMutex::ArchiveMutex()
{
InitializeCriticalSection(&m_criticalSection);
}
ArchiveMutex::~ArchiveMutex()
{
DeleteCriticalSection(&m_criticalSection);
}
void ArchiveMutex::enter()
{
EnterCriticalSection(&m_criticalSection);
}
void ArchiveMutex::leave()
{
LeaveCriticalSection(&m_criticalSection);
}
}
+27
View File
@@ -0,0 +1,27 @@
#ifndef _ArchiveMutex_H
#define _ArchiveMutex_H
#include <windows.h>
namespace Archive
{
class ArchiveMutex
{
public:
ArchiveMutex();
~ArchiveMutex();
void enter();
void leave();
private:
ArchiveMutex(const ArchiveMutex &o);
ArchiveMutex &operator =(const ArchiveMutex &o);
CRITICAL_SECTION m_criticalSection;
};
}
#endif
@@ -0,0 +1,16 @@
// FirstArchive.cpp
// copyright 2001 Verant Interactive
// Author: Justin Randall
//-----------------------------------------------------------------------
#include "FirstArchive.h"
//-----------------------------------------------------------------------
namespace
{
void supress_warning_LNK4221()
{
}
}