0

I came across this problem this morning:

I want to build a generic class FrontBackBuffer which I can use as the following (some examples).

EDIT Removed some confusing part!

int bb=10;
int fb=3;
FrontBackBuffer< const int*, int & > buf(&fb, &bb);
buf.getBack() = 4; // change from 10 to 4
// buf.getFront() = 5; NO! is const!

buf.swap();
//NOW getFront() and getBack() should return  4 and 3!

FrontBackBuffer< int, const & int > buf(14, bb);
buf.getBack() = 5; // change from 4 to 5
// buf.getFront() = 5; NO! is const!

buf.swap();   
//NOW getFront() and getBack() should return  5 and 14!

It stores two buffers, should be of the same underlying type (see the static_assert). These buffers can be of pointer type or reference type and also const or non const. It has two functions getFront()and getBack(). These functions always return a reference to the underlying buffer, either const or non-const. That is why there are all sorts of MyRefTypes traits spezialization.

The class which works so far is as the following:

template< typename TBufferTypeFront, typename TBufferTypeBack = TBufferTypeFront>
class FrontBackBuffer {

// If <const * int , int&> --> this result in is_same< int , int > 
// STATIC_ASSERT( std::is_same< RemoveModifiers<TBufferTypeFront>::type, typename RemoveModifiers<TBufferTypeFront>::type>::result )

public:

    template <typename T>
    struct MyRefTypes {
        typedef const T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static Ref getRef(T& v) {
            return v;
        }
    };

//Specialization for Reference
    template <typename T>
    struct MyRefTypes<T&> {
        typedef T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static inline Ref getRef(T& v) {
            return v;
        }
    };

//Specialization for const Reference
    template <typename T>
    struct MyRefTypes<const T&> {
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ref getRef(const T& v) {
            return v;
        }
    };

//Specialization for const
    template <typename T>
    struct MyRefTypes<const T> {
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ref getRef(const T& v) {
            return v;
        }
    };

//Specialization for pointers
    template <typename T>
    struct MyRefTypes<T*> {
        typedef T* Con;
        typedef T& Ref;
        typedef T* const CRef;  //! note this is a pointer....
        static inline Ref getRef(T* v) {
            return *v;
        }
    };

//Specialization for const pointers
    template <typename T>
    struct MyRefTypes<const T*> {
        typedef const T* Con;
        typedef const T& Ref;
        typedef const T* const CRef; //! note this is a pointer....
        static inline Ref getRef(const T* v) {
            return *v;
        }
    };


    typedef typename MyRefTypes<TBufferTypeFront>::Ref TBufferTypeFrontRef;
    typedef typename MyRefTypes<TBufferTypeFront>::CRef TBufferTypeFrontCRef;
    typedef typename MyRefTypes<TBufferTypeFront>::Con TBufferTypeFrontCon;

    typedef typename MyRefTypes<TBufferTypeBack >::Ref TBufferTypeBackRef;
    typedef typename MyRefTypes<TBufferTypeBack >::CRef TBufferTypeBackCRef;
    typedef typename MyRefTypes<TBufferTypeBack >::Con TBufferTypeBackCon;

    explicit FrontBackBuffer(
        TBufferTypeFrontCon  front,
        TBufferTypeBackCon   back):
        m_Front(front),
        m_Back(back)
    {
             m_pBack = (void*)&m_Back;
             m_pFront = (void*)&m_Front;

    };


    ~FrontBackBuffer()
    {};

    TBufferTypeFrontRef getFront() {
        return MyRefTypes<TBufferTypeFront>::getRef(m_Front);
    }
    TBufferTypeBackRef getBack() {
        return MyRefTypes<TBufferTypeBack>::getRef(m_Back);
    }
    private:

    void swap(){
         void * temp = m_pFront;
         m_pFront = m_pBack;
         m_pBack = temp;
    }

    TBufferTypeFront * m_pFront;       ///< The pointer to front buffer
    TBufferTypeBack * m_pBack;         ///< The pointer to back buffer

    TBufferTypeFront m_Front;       ///< The front buffer
    TBufferTypeBack m_Back;         ///< The back buffer

};

The question is now (which I can not solve completely right): How can I add a generic function swap() which swaps the buffers, but no copy should be made. I thought about two pointers void * m_pFrontand void *m_pBackwhich I should use to do the job, and assigned correct (see constructor).

But how do I now write these getter functions is a mystery to me:

    TBufferTypeFrontRef getFront() {
        return MyRefTypes<TBufferTypeFront>::getRef(m_Front);
    }
    TBufferTypeBackRef getBack() {
        return MyRefTypes<TBufferTypeBack>::getRef(m_Back);
    }

At the end of the day it should just work :-) Thanks for any help and trying to solve this puzzle :-)!

5
  • 2
    You can only swap front and back when they are the same or their pointers convertible to each other. Be aware that swap has a very specific meaning in the standard library and it is different from your meaning. Besides that, what you are trying to achieve doesn't look very useful to me, but I'm probably lacking context. Commented Nov 8, 2012 at 23:20
  • swap should do the same thing, internally it should switch the buffers, thas all, but an efficient one... Commented Nov 8, 2012 at 23:35
  • 2
    I too am very confused as to what you are trying to accomplish. I'm assuming that you know that you can't swap the buffers if they aren't of the same types? And if that's right, why don't you just store a variable about whether or not they are swapped or something. Commented Nov 8, 2012 at 23:36
  • Yea it is a bit confusing, but if one looks at the behaviour how the class should be used it should become clear, below is just an implmenetation trying to achieve this. It works with out the swap function... The thing is that this buffer can basically hold its own memory or refere to some other memory (pointers or references), for both front and back, And thats exactly the nice thing, you can use it very generic and it still does the thing! But the swap function is a hard problem. This class is only for template pleasure and maybe a bit overkill, but isnt it nice? Commented Nov 9, 2012 at 9:54
  • This feels like a wrong design. Plainly speaking, your class is not a buffer, rather a pointer/reference container. Perhaps it would be better to explain what task are you trying to accomplish and why can't you do it using a std::pair of pointers where swap is achieved by std::swap(p.first, p.second)? It is very efficient (moves 24B) and apparently also does what you want. Why are the types of buffers so important? Why is this worth writing a whole new container template? Commented May 9, 2014 at 7:42

2 Answers 2

0

I must admit I don't really understand why you need all the code you posted in order to accomplish the task you described, but I may be missing something. However considering you just want to swap two buffers of the same type in a generic but efficient way I would suggest the following:

template<typename BufferType>
class FrontBackBuffer
{
private:
    BufferType buffers[2];
    int _back,_front;
public:
/*
omitting copy constructors, operators etc for brevity
*/
    FrontBackBuffer()
        : _front(0), _back(1)
    {
         /*
           You can also start with front and back pointing to the same memory it is of no  importance if you remember to swap them once or if you just set the back buffer and never the front
         */
    }
    BufferType & getFront()
    {
        return buffers[_front];
    }
    BufferType & getBack()
    {
        return buffers[_back];
    }
    void swap()
    {
        _front = _back;
        _back = (_front + 1) % 2;
    }
};

And you can use it like this:

int intArray[] = {1,2,3,4};

FrontBackBuffer<int*> intPtrBuffers;
intPtrBuffers.getBack() = new int[4];
intPtrBuffers.getFront() = new int[4];

memcpy(intPtrBuffers.getBack(), intArray, sizeof(intArray));
intPtrBuffer.swap();
Sign up to request clarification or add additional context in comments.

2 Comments

This is another way, but doesn not let me define the back and front individualy, what do you do if you would like to have the front buffer somewhere else :-)? not a member instance in your FrontBackBuffer :-)
@Gabriel Thank you for your comment. As I wrote - I probably don't understand your real needs. You wrote the buffers are of the same type so for me using two types: one for the back and one for the front may be very general but just makes unclear code. If you want to keep them somewhere else then you can always use pointers. I like to keep things simple. However your real needs may indeed require something more complicated. (As a side note: I would really like to know what kind of implementation requires a back and front buffers of different types?)
0

This is the full answer!

The code works and the buffer is generic as hell :-) --> http://ideone.com/m3kFmo

And the swap function is also efficient and works as desired!

Of course this class is only usefull when the underlying type is the same like: FrontBackBuffer< int *, int &> --> OK

FrontBackBuffer< int *, const double &> --> is ok, but swap function makes no sense then!

Here the code! :-)

template< typename TBufferTypeFront, typename TBufferTypeBack = TBufferTypeFront>
class FrontBackBuffer {

    // If <const * int , int&> --> this result in is_same< int , int > 
    // STATIC_ASSERT( std::is_same< RemoveModifiers<TBufferTypeFront>::type, typename RemoveModifiers<TBufferTypeFront>::type>::result )

public:

    template <typename T>
    struct MyRefTypes {
        typedef T Org;
        typedef T* Ptr;
        typedef const T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(T& v) {
            return &v;
        }
        static Ref getRef(T& v) {
            return v;
        }
    };

    //Specialization for Reference
    template <typename T>
    struct MyRefTypes<T&> {
        typedef T Org;
        typedef T* Ptr;
        typedef T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(T& v) {
            return &v;
        }
        static inline Ref getRef(T& v) {
            return v;
        }
    };

    //Specialization for const Reference
    template <typename T>
    struct MyRefTypes<const T&> {
        typedef T Org;
        typedef T* Ptr;
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(const T& v) {
            return &const_cast<T&>(v);
        }
        static inline Ref getRef(const T& v) {
            return v;
        }
    };

    //Specialization for const
    template <typename T>
    struct MyRefTypes<const T> {
        typedef T Org;
        typedef T* Ptr;
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(const T& v) {
            return &const_cast<T&>(v);
        }
        static inline Ref getRef(const T& v) {
            return v;
        }
    };

    //Specialization for pointers
    template <typename T>
    struct MyRefTypes<T*> {
        typedef T* Ptr;
        typedef T Org;
        typedef T* Con;
        typedef T& Ref;
        typedef T* const CRef;  //! note this is a pointer....
        static inline Ptr getUnderlyingPtr(T* v) {
            return v;
        }
        static inline Ref getRef(T* v) {
            return *v;
        }
    };

    //Specialization for const pointers
    template <typename T>
    struct MyRefTypes<const T*> {
        typedef T Org;
        typedef T* Ptr;
        typedef const T* Con;
        typedef const T& Ref;
        typedef const T* const CRef; //! note this is a pointer....
        static inline Ptr getUnderlyingPtr(const T* v) {
            return const_cast<T*>(v);
        }
        static inline Ref getRef(const T* v) {
            return *v;
        }
    };


    typedef typename MyRefTypes<TBufferTypeFront>::Ref TBufferTypeFrontRef;
    typedef typename MyRefTypes<TBufferTypeFront>::CRef TBufferTypeFrontCRef;
    typedef typename MyRefTypes<TBufferTypeFront>::Con TBufferTypeFrontCon;
    typedef typename MyRefTypes<TBufferTypeFront>::Org TBufferTypeFrontOrg;
    typedef typename MyRefTypes<TBufferTypeFront>::Ptr TBufferTypeFrontPtr;

    typedef typename MyRefTypes<TBufferTypeBack >::Ref TBufferTypeBackRef;
    typedef typename MyRefTypes<TBufferTypeBack >::CRef TBufferTypeBackCRef;
    typedef typename MyRefTypes<TBufferTypeBack >::Con TBufferTypeBackCon;
    typedef typename MyRefTypes<TBufferTypeBack >::Org TBufferTypeBackOrg;
    typedef typename MyRefTypes<TBufferTypeBack >::Ptr TBufferTypeBackPtr;

    explicit FrontBackBuffer(
                             TBufferTypeFrontCon  front,
                             TBufferTypeBackCon   back):
    m_Front(front),
    m_Back(back)
    {
        m_pBack = MyRefTypes<TBufferTypeBack>::getUnderlyingPtr(m_Back);
        m_pFront = MyRefTypes<TBufferTypeFront>::getUnderlyingPtr(m_Front);

    };


    ~FrontBackBuffer()
    {};

    TBufferTypeFrontRef getFront() {
        return *m_pFront;
    }
    TBufferTypeBackRef getBack() {
        return *m_pBack;
    }

    void swap(){
        TBufferTypeFrontPtr temp = m_pFront;
        m_pFront = m_pBack;
        m_pBack = temp;
    }

private:



    TBufferTypeFrontPtr m_pFront;       ///< The pointer to front buffer
    TBufferTypeBackPtr  m_pBack;         ///< The pointer to back buffer

    TBufferTypeFront m_Front;       ///< The front buffer
    TBufferTypeBack m_Back;         ///< The back buffer

};

We are able to use it in this way now:

int main() {
        int front=10;
    int back=3;
    FrontBackBuffer< const int*, int & > buf1(&front, back);
    buf1.getBack() = 4; // change from 3 to 4
    // buf.getFront() = 5; NO! is const!
    buf1.swap();
        std::cout << buf1.getFront() << buf1.getBack() << std::endl;
    //NOW getBack() and getFront() should return  4 and 10!

        front = 1;
        back= -1;
    FrontBackBuffer<int &, int > buf2(front, back);
    buf2.getBack() = 2; 
    buf2.getFront() = 3; 

    buf2.swap();   
    //NOW getBack() and getFront() should return  2 and 3!
    std::cout << buf2.getFront() << buf2.getBack() << std::endl;

        front = 1;
        back= -1;
    FrontBackBuffer<int, const int &> buf3(front, back);
    //buf3.getBack() = 2; // IS CONST!!
    buf3.getFront() = 3; 

    buf3.swap();   
    //NOW getBack() and getFront() should return  -1 and 3!
    std::cout << buf3.getFront() << buf3.getBack() << std::endl;

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.