3

Does any library has a Circular buffer class that can be used with pre-allocated buffer? I looked at Boost::circular_buffer, but it seems all of its constructors require an allocator. I don't want to reinvent circular buffer class, but have to use pre-allocated buffer. I want something like:

char buffer[1000];  // pre-allocated buffer.
circular_buffer_class cb; // a class that provides the interface as a circular buffer.
cb.attach(buffer, 1000); // attaching the preallocated buffer to the circular buffer class.
cb.do_something();

Maybe is it doable with some special allocator? But how?

In addition, I am interested in other types of container classes, like fixed-size vector, that can be used with pre-allocated buffer.

user22097
  • 229
  • 3
  • 13
  • 3
    When you say "pre-allocated buffer", does it have to be one that you've allocated yourself, or would merely telling the container to pre-allocate its own buffer internally be enough? – Cameron Sep 21 '13 at 00:30
  • I mean the one I've allocated by myself. This is a software for embedded system. I am given a pointer to and size of the memory region that I am allowed to use. – user22097 Sep 21 '13 at 00:36
  • 4
    Then you are probably best off writing a [custom allocator](http://en.wikipedia.org/wiki/Allocator_(C%2B%2B)#Custom_allocators) class that uses that memory region internally. You can then use that allocator with any STL/Boost class that uses an allocator. – Remy Lebeau Sep 21 '13 at 00:43
  • I wonder there already exists such a custom allocator. My need should not be so rare. I'm not so familiar with allocator, want to find already proven one... – user22097 Sep 21 '13 at 01:09
  • You can use boost c++. http://www.boost.org/doc/libs/1_54_0/libs/circular_buffer/doc/circular_buffer.html There is also a bounded_buffer example – Elvis Dukaj Sep 24 '13 at 12:37

1 Answers1

1

Here are some links related simple custom allocators which you might find interesting:

Hinnant's short_alloc and alignment guarantees

http://howardhinnant.github.io/stack_alloc.html

You can use this custom allocator, which is a derivative work and probably pretty close to what you intend:

#pragma once
#include <memory>
#include <cstddef>
#include <cassert>

/**
 * @class fixed_allocator
 * @see https://en.cppreference.com/w/cpp/memory/allocator
 *
 * @tparam The data type which is to be allocated.
 * The type is important for correct data alignment.
 */
template<typename data_type>
class fixed_allocator: public std::allocator<data_type>
{
public:
    using value_type = data_type;

    /**
     * @struct rebind is essential for this class to work properly.
     * It tells std::allocator to use our implementation of allocate and
     * deallocate rather than the default operator new, delete.
     */
    template <class other_type> struct rebind
    {
        using other = fixed_allocator<other_type>;
    };

    ~fixed_allocator()                                  = default;
    fixed_allocator()                                   = delete;    
    fixed_allocator(fixed_allocator const&)             = default;  // Required by rebind.
    fixed_allocator(fixed_allocator &&)                 = default;
    fixed_allocator& operator=(fixed_allocator const&)  = default;
    fixed_allocator& operator=(fixed_allocator&&)       = default;

    /**
     * Create a fixed allocator for the specified data_type.
     *
     * @param buffer The fixed backing store buffer to use for allocation.
     * @param length The number of data_type units held in the
     *               backing store allocation.
     */
    fixed_allocator(value_type *buffer, std::size_t length)
        : buffer_(buffer), buffer_length_(length), in_use_(false)
    {}

    /**
     * Allocates n * sizeof(value_type) bytes of uninitialized storage by
     * calling ::operator new(std::size_t) or
     * ::operator new(std::size_t, std::align_val_t) (since C++17).
     *
     * @param length       The number of value_type elements to allocate.
     *                     Must be <= this->buffer_length_.
     *
     * @return value_type* The allocate data block.
     * @note               For this fixed allocation this function must only
     *                     be called once before deallocate is called.
     *
     * @throw std::bad_alloc If the allocation fails.
     */
    value_type* allocate(std::size_t length)
    {
        assert(length <= this->buffer_length_);
        assert(not this->in_use_);
        this->in_use_ = true;
        return this->buffer_;
    }

    /**
     * Releases the fixed allocation block from use.
     * @param buffer The memory block being freed.
     *               Must be the same as this->buffer_.
     * @param length The number of bytes freed. Unchecked.
     */
    void deallocate(value_type *buffer, std::size_t length)
    {
        (void) length;
        assert(buffer == this->buffer_);
        assert(this->in_use_);
        this->in_use_ = false;
    }

private:
    value_type* buffer_;
    std::size_t buffer_length_;
    bool        in_use_;
};

You can now pass a specialized instance of this allocator into the boost::circular_buffer constructor.

natersoz
  • 1,674
  • 2
  • 19
  • 29
  • I'm not totally convinced this allocator is 100% valid, as there's no way to allocate via a rebound allocator. But if it compiles and works, then good enough, I guess – Mooing Duck Jan 03 '23 at 16:56