FilteredListUpdaterOnReflectedVector.h

// FilteredListUpdaterOnReflectedVector.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2021

@import "ReflectedVectorBC.h"
@import "ConstructDestructCopyAssignReflectedVariable.h"
#include "Ceda/cxUtils/CedaAssert.h"

namespace ceda
{
    /*
    Provides an efficient mechanism to erase some subset of the elements of a reflected vector,
    using calls to drop/keep in a single pass over the vector.

    During the single pass, elements to be kept are moved and elements to be dropped are 
    destructed.  The vector is only resized at the end.
    */

    class FilteredListUpdaterOnReflectedVector
    {
    public:
        FilteredListUpdaterOnReflectedVector(const ReflectedVectorBC& rv, VectorOfByte& vf) :
            rv(rv),
            vf(vf)
        {
            keepPos = dropPos = vf.data();
        }
        ~FilteredListUpdaterOnReflectedVector()
        {
            cxAssert(dropPos == vf.data() + vf.size());
            vf.resize(keepPos - vf.data());
        }

        // Drop the next n elements
        void Drop(ssize_t n)
        {
            cxAssert(n >= 0);
            cxAssert(dropPos + n*rv.elementSize <= vf.data() + vf.size());

            if (!rv.isPOD)
            {
                DestructReflectedArrayVariable(rv.rbcElement, n, dropPos);
            }
            dropPos += n*rv.elementSize;
        }

        // Keep the next n elements
        void Keep(ssize_t n)
        {
            cxAssert(n >= 0);
            cxAssert(dropPos + n*rv.elementSize <= vf.data() + vf.size());

            ssize_t numBytes = n*rv.elementSize;
            std::memmove(keepPos, dropPos, numBytes);
            keepPos += numBytes;
            dropPos += numBytes;
        }

    private:
        const ReflectedVectorBC& rv;
        VectorOfByte& vf;
        octet_t* keepPos;
        octet_t* dropPos;
    };

    class FilteredListUpdaterOnReflectedVector2
    {
    public:
        FilteredListUpdaterOnReflectedVector2(const ReflectedVector& rv, VectorOfByte& vf) :
            elementOps(*rv.element.ops),
            vf(vf)
        {
            keepPos = dropPos = vf.data();
        }
        ~FilteredListUpdaterOnReflectedVector2()
        {
            cxAssert(dropPos == vf.data() + vf.size());
            vf.resize(keepPos - vf.data());
        }

        // Drop the next n elements
        void Drop(ssize_t n)
        {
            cxAssert(n >= 0);
            cxAssert(dropPos + n * elementOps.GetSize() <= vf.data() + vf.size());

            elementOps.DestructArray(dropPos,n);
            dropPos += n * elementOps.GetSize();
        }

        // Keep the next n elements
        void Keep(ssize_t n)
        {
            cxAssert(n >= 0);
            cxAssert(dropPos + n * elementOps.GetSize() <= vf.data() + vf.size());

            ssize_t numBytes = n * elementOps.GetSize();
            std::memmove(keepPos, dropPos, numBytes);
            keepPos += numBytes;
            dropPos += numBytes;
        }

    private:
        const TypeOps& elementOps;
        VectorOfByte& vf;
        octet_t* keepPos;
        octet_t* dropPos;
    };
} // namespace ceda