ReflectedVectorBC.h

// ReflectedVectorBC.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007

@import "IObject.h"
@import "ReflectionByteCode.h"

namespace ceda
{

enum EReflectedVectorCode
{
    RVC_OK,
    RVC_BAD_INDEX,
    RVC_TYPE_ERROR
};

// Returns the current number of elements in a xvector<T> variable at address 'vec'.
// rbc describes the element type T.
@api ssize_t GetReflectedVectorSize(ReflectionByteCode rbc, const void* vec);

// Returns address of the element that was inserted
@api void* PushBackDefaultConstructedElementOntoReflectedVector(ReflectionByteCode rbc, void* vec);

// Concatenate array of T of size 'array_rhs_size' at address 'array_rhs' onto vector<T> at address 'vec_lhs'
// rbc describes the element type T.
@api void ConcatReflectedVectorFromArray(ReflectionByteCode rbc, void* vec_lhs, const void* array_rhs, ssize_t array_rhs_size);

// Concatenate vector<T> at address 'vec_rhs' onto vector<T> at address 'vec_lhs'
// rbc describes the element type T.
@api void ConcatReflectedVector(ReflectionByteCode rbc, void* vec_lhs, const void* vec_rhs);

@api bool ConcatReflectedVector(
    ReflectionByteCode rbc_lhs, void* vec_lhs, 
    ReflectionByteCode rbc_rhs, const void* vec_rhs, 
    bool allowExplicitConversions);

// Insert elements copied from the range [s1,s2) from array in T of size src_n at address src into the xvector<T> at 
// address dst at position d
// rbc describes the element type T.
// Returns false if any of d,s1 or s2 are invalid.
@api bool InsertFromArrayIntoReflectedVector(ReflectionByteCode rbc, void* dst, ssize_t d, const void* src, ssize_t src_n, ssize_t s1, ssize_t s2);

// Insert elements copied from the range [s1,s2) from xvector<T> at address src into the xvector<T> at 
// address dst at position d
// rbc describes the element type T.
// Returns false if any of d,s1 or s2 are invalid.
@api bool InsertIntoReflectedVector(ReflectionByteCode rbc, void* dst, ssize_t d, const void* src, ssize_t s1, ssize_t s2);

// Returns RVC_OK, RVC_BAD_INDEX or RVC_TYPE_ERROR
@api EReflectedVectorCode InsertIntoReflectedVector(
    ReflectionByteCode rbc_dst, void* dst, ssize_t d, 
    ReflectionByteCode rbc_src, const void* src, ssize_t s1, ssize_t s2, 
    bool allowExplicitConversions);
    
// Construct the xvector<T> at address dst from a copy of the slice [s1,s2) from the array in T of size src_n at
// src.
// rbc describes the element type T.
// Return false if [s1,s2) out of range
@api bool ConstructReflectedVectorFromSliceOfArray(ReflectionByteCode rbc, void* dst, const void* src, ssize_t src_n, ssize_t s1, ssize_t s2);

// Construct the xvector<T> at address dst from a copy of the slice [s1,s2) from the vector<T> at
// src.
// rbc describes the element type T.
// Return false if [s1,s2) out of range
@api bool ConstructFromSliceOfReflectedVector(ReflectionByteCode rbc, void* dst, const void* src, ssize_t s1, ssize_t s2);

// Perform push_back of the value of type T at address 'x' on the vector<T> at address 'vec'
// rbc describes the element type T.
@api void PushBackOntoReflectedVector(ReflectionByteCode rbc, void* vec, const void* x);

// Insert value of type T at address 'x' into the vector<T> at address 'vec', at index position i
// rbc describes the element type T.
// Returns false if i is out of range.
@api bool InsertElementIntoReflectedVector(ReflectionByteCode rbc, void* vec, ssize_t i, const void* x);

// Returns the address of the ith element of the array of T of size n at address 'array'
// rbc describes the element type T.
// Returns nullptr if i is invalid.
@api void* GetElementOfReflectedArray(ReflectionByteCode rbc, void* array, ssize_t n, ssize_t i);

// Returns the address of the ith element of the xvector<T> at address 'vec'
// rbc describes the element type T.
// Returns nullptr if i is invalid.
@api void* GetElementOfReflectedVector(ReflectionByteCode rbc, void* vec, ssize_t i);

// Erase the elements in the range [i1,i2) from the xvector<T> at address vec
// rbc describes the element type T.
// Returns false if [i1,i2) is an invalid range.
@api bool EraseSliceInReflectedVector(ReflectionByteCode rbc, void* vec, ssize_t i1, ssize_t i2);

// Reverse the elements of the xvector<T> as address vec
// rbc describes the element type T.
// Assumes that vector elements are relocatable
@api void ReverseReflectedVector(ReflectionByteCode rbc, void* vec);

// Returns the index of the first element in the array in T of size 'size' at address 
// 'array' that is equivalent in value to the variable of type T at address 'elt'.
// 'rbc' describes the element type T.
@api ssize_t FindFirstElementInReflectedArray(ReflectionByteCode rbc, const void* array, ssize_t size, const void* elt);

// Returns the index of the first element in the xvector<T> at address 'vec' that is equivalent in 
// value to the variable of type T at address 'elt'.
// 'rbc' describes the element type T.
@api ssize_t FindFirstElementInReflectedVector(ReflectionByteCode rbc, const void* vec, const void* val);

// Returns the number of elements in the array in T of size 'size' at address 'array' that 
// are equivalent in value to the variable of type T at address 'elt'.
// 'rbc' describes the element type T.
@api ssize_t GetElementFrequencyInReflectedArray(ReflectionByteCode rbc, const void* array, ssize_t size, const void* elt);

// Returns the number of elements in the xvector<T> at address vec that are equivalent in value to
// the variable of type T at address val.
// rbc describes the element type T.
@api ssize_t GetElementFrequencyInReflectedVector(ReflectionByteCode rbc, const void* vec, const void* val);

// Sort the xvector<T> as address vec.  rbc describes the element type T.
// Assumes that vector elements are relocatable
@api void SortReflectedVector(ReflectionByteCode rbc, void* vec);


///////////////////////////////////////////////////////////////////////////////////////////////////
// Methods that generate operations on vector models

/*
It is currently assumed that the elements are simple types without need for constructors
and destructors.  Therefore (for example), copying an element only requires a memcpy.
*/

// Concatenate vector<T> at address 'vec_rhs' onto vector<T> at address 'vec_lhs'
// rbc describes the element type T.
@api void genop_ConcatVector(ptr<IObject> ds, const FieldPath& path,
    ReflectionByteCode rbc, void* vec_lhs, const void* vec_rhs);

@api bool genop_ConcatVector(
    ptr<IObject> ds, const FieldPath& path,
    ReflectionByteCode rbc_lhs, void* vec_lhs, 
    ReflectionByteCode rbc_rhs, const void* vec_rhs, 
    bool allowExplicitConversions);

@api bool genop_InsertIntoVector(ptr<IObject> ds, const FieldPath& path, 
    ReflectionByteCode rbc, void* dst, ssize_t d, const void* src, ssize_t s1, ssize_t s2);

@api EReflectedVectorCode genop_InsertIntoVector(
    ptr<IObject> ds, const FieldPath& path,
    ReflectionByteCode rbc_dst, void* dst, ssize_t d, 
    ReflectionByteCode rbc_src, const void* src, ssize_t s1, ssize_t s2, 
    bool allowExplicitConversions);

@api void genop_PushBackOntoVector(
    ptr<IObject> ds, const FieldPath& path,
    ReflectionByteCode rbc, void* vec, const void* x);

@api bool genop_InsertElementIntoVector(
    ptr<IObject> ds, const FieldPath& path,
    ReflectionByteCode rbc, void* vec, ssize_t i, const void* x);

@api bool genop_EraseSliceInVector(
    ptr<IObject> ds, const FieldPath& path,
    ReflectionByteCode rbc, void* vec, ssize_t i1, ssize_t i2);

///////////////////////////////////////////////////////////////////////////////////////////////////
// ReflectedVectorBC

struct @api ReflectedVectorBC
{
    void Init(ReflectionByteCode rbcElement);
    void clear(VectorOfByte& vf) const;
    void resize(VectorOfByte& vf, ssize_t size) const;

    // Serialise the elements of vf in the index range [p,p+n) to the given archive
    void SerialiseElements(Archive& ar, const VectorOfByte& vf, ssize_t p, ssize_t n);

    void Serialise(Archive& ar, const VectorOfByte& vf) const;
    void Deserialise(InputArchive& ar, VectorOfByte& vf) const;
    void ScanOver(InputArchive& ar) const;
    void EraseRange(VectorOfByte& vf, ssize_t p1, ssize_t p2) const;
    void DestructElements(VectorOfByte& vf, ssize_t p1, ssize_t p2) const;

    inline const octet_t* MoveFrom(VectorOfByte& vf, ssize_t d, const octet_t* src, ssize_t count)
    {
        const octet_t* src_end = src + count * elementSize;
        vf.insert(d*elementSize, src, src_end);
        return src_end;
    }

    ReflectionByteCode rbcElement;
    ssize_t elementSize = 0;
    bool isPOD = false;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// ReflectedVectorBCVariable

struct ReflectedVectorBCVariable
{
    ReflectedVectorBCVariable(const ReflectedVectorBC& rv) : rv(rv) {}

    inline ssize_t size() const
    {
        cxAssert(data->size() % rv.elementSize == 0);
        ssize_t size = data->size() / rv.elementSize;
        cxAssert(size >= 0);
        return size;

        // Much slower because the elementSize is calculated from the byte code every time
        //return GetReflectedVectorSize(rv.rbcElement,data);
    }

    inline void clear()
    {
        rv.clear(*data);
    }

    inline void resize(ssize_t newSize)
    {
        rv.resize(*data, newSize);
    }

    inline void reverse()
    {
        ReverseReflectedVector(rv.rbcElement, data);
    }
    
    inline void sort()
    {
        SortReflectedVector(rv.rbcElement, data);
    }
    
    inline void Serialise(Archive& ar) const
    {
        rv.Serialise(ar, *data);
    }
    
    inline void Deserialise(InputArchive& ar)
    {
        rv.Deserialise(ar, *data);
    }

    inline void EraseRange(ssize_t p1, ssize_t p2)
    {
        rv.EraseRange(*data, p1, p2);
    }

    inline void erase(ssize_t pos, ssize_t count)
    {
        EraseRange(pos, pos+count);
    }

    bool Insert(ssize_t d, const void* src, ssize_t s1, ssize_t s2)
    {
        return InsertIntoReflectedVector(rv.rbcElement, data, d, src, s1, s2);
    }
    
    inline bool insert(ssize_t i, const void* x)
    {
        return InsertElementIntoReflectedVector(rv.rbcElement, data, i, x);
    }

    inline void* GetElement(ssize_t i)
    {
        ssize_t s = data->size();
        cxAssert(s % rv.elementSize == 0);
        ssize_t n = s / rv.elementSize;
        if (0 <= i && i < n)
        {
            return &(*data)[i * rv.elementSize];
        }
        else
        {
            return nullptr;
        }

        // Much slower because the elementSize is calculated from the byte code every time
        //return GetElementOfReflectedVector(rv.rbcElement, data, i);
    }
    inline const void* GetElement(ssize_t i) const
    {
        return GetElementOfReflectedVector(rv.rbcElement, data, i);
    }

    inline void* PushBackDefaultConstructedElement()
    {
        return PushBackDefaultConstructedElementOntoReflectedVector(rv.rbcElement, data);
    }
    
    inline void AppendDefaultConstructed(ssize_t count)
    {
        for (int i=0 ; i < count ; ++i)
        {
            PushBackDefaultConstructedElement();
        }
    }

    inline void ScanOver(InputArchive& ar) const { rv.ScanOver(ar); }

    const ReflectedVectorBC& rv;
    VectorOfByte* data = nullptr;
};

} // namespace ceda