mirror of
https://github.com/SWG-Source/src.git
synced 2026-07-29 23:15:56 -04:00
Added "archive" project
This commit is contained in:
@@ -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"
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user