ReflectedMap.h
// ReflectedMap.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2022
@import "IObject.h"
@import "ReflectedType.h"
namespace ceda
{
template <typename K, typename V> class xmap;
///////////////////////////////////////////////////////////////////////////////////////////////////
// xmap<Key,Value> functions
/*
For various types of Key and Payload, xmap<Key,Payload> is implemented as a B+Tree in
application DLLs. It is necessary to provide information to the reflection system to
allow clients to access an xmap in a type invariant manner.
For example, PrintReflectedVariable makes use of the abstract iterator to iterate through
each (Key,Payload) pair of ay given xmap.
*/
/*
Abstract bidirectional iterator for an xmap<Key,Payload>
The following shows an example of forwards iteration through all the (Key,Payload)
elements of a given xmap 'xm'.
void f(ptr<IXMap> xm)
{
ptr<IBiDirIterator> i = xm->GetIterator();
ssize_t payloadOffset = xm->GetPayloadOffset();
while(const void* key = i->GetElement())
{
const void* payload = (const octet_t*)key + payloadOffset;
// todo use key,payload
i->Next();
}
i->Close(); // iterator must be closed when no longer required
}
*/
$interface+ IBiDirIterator
{
// An iterator must always be closed when it is no longer required
void Close();
// Returns the address of the current element pointed to by this iterator, or else
// returns nullptr if the iterator is positioned one before the first or one after the
// last element.
const void* GetElement();
// Used to step the iterator forwards or backwards
void Next();
void Prev();
};
// Provides some useful functions for dealing with serialisable elements of some type
// todo: There is no need for 'self' so it would be more efficient to simply use a set
// of function pointers
$interface+ IKeyType
{
// Retrieve the size of a buffer that should be allocated for a variable
//ssize_t size() const;
// Write the value of the variable at 'addr' to the given archive
void SerialiseVariable(Archive& ar, const void* addr) const;
// Read the value of the variable from the given archive
void DeserialiseVariable(InputArchive& ar, void* addr) const;
void SkipVariable(InputArchive& ar) const;
// Construct a variable at 'addr'
//void Construct(void* addr) const;
// Destruct a variable at 'addr'
//void Destruct(void* addr) const;
};
$interface+ IXMap
{
// A bit weird to think these as methods!
void Construct();
void CopyConstruct(const void* rhs);
void CopyAssign(const void* rhs);
ssize_t GetKeySize() const;
// Look up the map with the given key.
// Returns address of payload if found otherwise nullptr
const void* Get(const void* key) const;
// Performs a look up on the xmap. Reads the key from the archive, and uses
// that key to index into the xmap. Sets 'payload' to the address of the payload or
// else nullptr if the key was not found
void Search(InputArchive& ar, const void*& payload) const;
// Must be called with an exclusive lock
// Searches the map for the given key.
// If no entry is found then inserts an entry using a default constructed payload value.
// It is permissible to subsequently modify the payload in the same transaction without
// needing to mark any persistable objects as dirty - because the B+Tree leaf
// node containing the payload is marked as dirty by this function.
// Returns a pointer to the payload. Never returns nullptr.
void* Insert(const void* key);
// Must be called with an exclusive lock
// Reads a key value from the given archive, then searches the map for that key.
// If no entry is found then inserts an entry using a default constructed payload value.
// It is permissible to subsequently modify the payload in the same transaction without
// needing to mark any persistable objects as dirty - because the B+Tree leaf
// node containing the payload is marked as dirty by this function.
// Returns a pointer to the payload. Never returns nullptr.
void DeserialiseAndInsert(InputArchive& ar, void*& payload);
// Total number of elements in the map
ssize_t size() const;
// Get the offset to the payload from the pointer to the key in any given
// (Key,Payload) pair
ssize_t GetPayloadOffset() const;
// Retrieves an iterator that can be used to iterate through all (Key,Payload) pairs
// of the map
// The returned iterator must be closed after it is no longer required.
ptr<IBiDirIterator> GetIterator() const;
ptr<IKeyType> GetKeyType() const;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// ReflectedMap
struct ReflectedMap
{
inline ptr<IXMap> make_ptr_IXMap(void* self) const
{
cxAssert(self);
cxAssert(IXMapFnTable);
return make_ptr<IXMap>(self,IXMapFnTable);
}
inline ptr<const IXMap> make_ptr_IXMap(const void* self) const
{
cxAssert(self);
cxAssert(IXMapFnTable);
return make_ptr<IXMap>(self,IXMapFnTable);
}
// Conceptually like
// const xmap<K,V>& m = *data;
// Key k;
// ar >> k;
// return m.HasKey(k) ? &m[k] : nullptr;
inline const void* Search(const void* data, InputArchive& ar) const
{
cxAssert(data);
cxAssert(IXMapFnTable);
cxAssert(IXMapFnTable->Search);
const void* p;
(IXMapFnTable->Search)(data, ar, p);
return p;
}
// Conceptually like
// xmap<K,V>& m = *data;
// Key k;
// ar >> k;
// return &m[k];
inline void* DeserialiseAndInsert(void* data, InputArchive& ar) const
{
cxAssert(data);
cxAssert(IXMapFnTable);
cxAssert(IXMapFnTable->DeserialiseAndInsert);
void* p;
(IXMapFnTable->DeserialiseAndInsert)(data, ar, p);
cxAssert(p);
return p;
}
const TypeOps& ops;
ReflectedType key;
ReflectedType value;
const IXMap::FnTable* IXMapFnTable = nullptr;
};
@api xostream& operator<<(xostream& os, const ReflectedMap& r);
template<typename T> struct is_map { constexpr static bool value = false; };
template<typename K, typename V> struct is_map<xmap<K,V>> { constexpr static bool value = true; };
template<typename K, typename V>
inline const ReflectedMap& GetReflectedMap()
{
static ReflectedMap s =
{
GetTypeOpsX<xmap<K,V>>(),
GetReflectedType<K>(),
GetReflectedType<V>(),
&IXMap::Stubs<xmap<K,V>>::GetTable()
};
return s;
}
template<typename K, typename V>
struct GetReflectedType_class<xmap<K,V>>
{
static inline ReflectedType get()
{
ReflectedType r;
r.tag = EReflectedTypeTag::Map;
r.Map = &GetReflectedMap<K,V>();
return r;
}
};
} // namespace ceda