Boost logo

Boost :

Subject: Re: [boost] Proposal: Monotonic Containers - Comparison with boost::pool, boost::fast_pool and TBB
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2009-06-22 19:27:37


David Bergman wrote:
> Great input, Luke. The wild ideas and over-simplified implementations
> of Christian's might crystallize with the help of people like you. I
> think I would prefer a solid non-chained realization first, though. If
> that proves stable and intriguing enough, we can consider "chains"?
> Or, is it totally meaningless without chained blocks?

Let's keep things technical and not apply qualitative value judgements in a ways that might upset people. It is not totally meaningless without chained blocks, but it is hard to know how much memory your program will need ahead of time in all cases, and chained blocks provides some safety that I'm willing to pay for in added implementation complexity assuming it is properly tested. In particular, though, I would want the chaining feature to be performance neutral when not needed. Thread safety is a little tougher to prove correct implementation, and I'd want that to be closely inspected in a review by people more qualified than I am to judge whether we can trust it.

Below is a code sketch of my idea for class design of the allocator and scoped buffer objects. I don't know if it is a good design, but there you have it.

template <std::size_t block_size = DEFAULT_SIZE, bool auto_extend = true, bool thread_safe = true>
class scratch_pad {
public:
        scratch_pad(); //allocate initial buffer on the heap
        //use user provided buffer for initial buffer (does not transfer ownership)
        //buffer can come from the heap, stack or thread local storage of some kind
        scratch_pad(void* address, std::size_t byte_size);
        //free up any buffers allocated by scratch_pad on the heap
        ~scratch_pad();
        
        //get a pointer to byte_count contiguous free bytes
        void* allocate(std::size_t byte_count);
private:
        ...
};

template <class unique_id, std::size_t block_size, bool auto_extend = true, bool thread_safe = true>
class scratch_allocator {
        static scratch_pad<block_size, auto_exend, thread_safe>* buffer;
public:
        static use_scratch_pad(scratch_pad& input_buffer) { buffer = &input_buffer; }
        //required interfaces for stdandard allocator
        ...
}

Usage:

{
 class A {};
 scratch_pad<A> spA;
 scratch_allocator<A>::use_scratch_pad(spA);
 std::vector<int, scratch_allocator<A> > vecA;
 do_something_performance_critical(vecA);
}
{
 int buff[1024];
 scratch_pad<A> spA2(buff, 1024*size_of(int));
 scratch_allocator<A>::use_scratch_pad(spA2);
 std::vector<int, scratch_allocator<A> > vecA2;
 do_something_performance_critical(vecA2);
}

These two uses of scratch_allocator<A> use different scratch pads which each go out of scope at the end of their block. One uses scratch buffer from the heap, the other from the stack. The typename A is just there to prevent anyone elses use of scratch_allocator elsewhere from clobbering this code. Another scratch_allocator<A> in the application would imply a syntax (or linktime) error for repeat definition of A.

Regards,
Luke


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk