|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r53864 - in sandbox/monotonic/libs/monotonic: doc test
From: christian.schladetsch_at_[hidden]
Date: 2009-06-13 07:56:15
Author: cschladetsch
Date: 2009-06-13 07:56:14 EDT (Sat, 13 Jun 2009)
New Revision: 53864
URL: http://svn.boost.org/trac/boost/changeset/53864
Log:
typos to docs, added tests for swap
Text files modified:
sandbox/monotonic/libs/monotonic/doc/index.html | 74 +++++++++++++++++++++++++++++----------
sandbox/monotonic/libs/monotonic/test/main.cpp | 48 +++++++++++++++++++++++++
2 files changed, 102 insertions(+), 20 deletions(-)
Modified: sandbox/monotonic/libs/monotonic/doc/index.html
==============================================================================
--- sandbox/monotonic/libs/monotonic/doc/index.html (original)
+++ sandbox/monotonic/libs/monotonic/doc/index.html 2009-06-13 07:56:14 EDT (Sat, 13 Jun 2009)
@@ -41,42 +41,71 @@
Boost.Monotonic is an implementation of an allocator that use a given,
fixed-size storage buffer. This buffer can be on the heap, or the stack, and may
be shared by multiple containers.</p>
+ <p>
+ The name 'monotonic' has been criticised as being too general and not really
+ indicative of the scope and purpose of the library. All alternative suggestions
+ gratefully considered!</p>
<h2 id="Motivation">
Motivation
</h2>
<p>
We would like to use STL containers which take their storage from the stack. In
this way, for example a std::map<K,T> can use storage from the stack rather than
- fragmenting the heap. </p>
+ fragmenting the heap. Also, it would be great if the same storage
+ could be used by different containers, and even better if we could chose to use
+ the stack or the heap.</p>
<p>
There are many uses for such a system, including per-frame containers,
efficient use containers for use in recursion, and reducing or removing heap
fragmentation. </p>
<p>
- It is a fast allocation system, with the downside
- that the resident set size can only grow in size. Hence the proposed name of a
+ This is part of what this library does, all in one little allocator and storage
+ type.
+ It is a fast allocation system, O(1) to allocate and zero-cost to deallocate; hence the proposed name of a
"monotonic" allocator.
</p>
<h2 id="Proposal">
+ Quick Example</h2>
+ <pre>void shared()<br />
+ {
+ // declare the storage that will be shared by the containers
+ // it is on the stack here, but can be put on the heap with `new`
+ boost::monotonic::inline_storage<10000> storage;<br /> { boost::monotonic::map<int, int> map(storage);
+ map[1] = 2;
+ map[2] = 4;
+
+ boost::monotonic::vector<char> vec(storage);
+ vec.assign('x', 4);
+
+ boost::monotonic::list<char> list(storage);
+ std::copy(vec.begin(), vec.end(), std::back_inserter(list));
+
+ boost::monotonic::set<std::pair<const int, int> set(storage);
+ std::copy(map.begin(), map.end(), std::inserter(set));
+ }
+}</pre>
+ <h2>
Proposal
</h2>
<p>
- The source code resides in the boost sandbox.</p>
+ The f="https://svn.boost.org/svn/boost/sandbox/monotonic">source code</a> resides in the boost sandbox.</p>
<p>
- This is a constant-time, stack-based STL-compliant[1] allocator with the following
+ This is This is a constant-time, stack-based STL-compliant[1] allocator and storage
+ system with the following
properties: </p>
<ul>
- <li>Space for objects is pre-allocated. This can be on the heap <strong>or</strong>
+ <li>Space for objects is pre-allocated. This can be on the heap or</strong>
on the stack. </li>
<li>Objects are initialised only as required. </li>
- <li>De-allocating an object calls its destructor. </li>
+ <li>De-allocDe-allocating an object calls its destructor iff it has one.</li>
<li>Object storage is not reclaimed until the underlying storage goes out of scope.
</li>
+ <li>Multiple different containers of any type can share the same storage via
+ different allocators.</li>
</ul>
<p>
The benefits of using a monotonic::allocator over other allocators are:
- </p>
- <ul>
+ <ul>
<li>All storage is pre-allocated, similar to a pool </li>
<li>Storage can be on the stack: <ul>
<li>Heap is not even used, let alone fragmented </li>
@@ -139,13 +168,16 @@
<p>
boost::unordered can have a similar treatment.</p>
<p>
- It has been strongly suggested that these convenience structures be removed from
+ It has IIt has been strongly suggested that these convenience structures be removed from
the proposal. For comparison, the following are two exactly equivalent types:</p>
+ <pre>typedef boost::monotonic::vector<int> Vector;
+typedef std::vector<int, boost::monotonic::allocator<int> > Vector;</pre>
<pre>typedef boost::monotonic::map<int, boost::monotonic::list<int> > Map;
typedef std::map<int, std::list<int, boost::monotonic::allocator<int> >, std::less<int>, boost::monotonic::allocator<int> > Map;</pre>
<p>
- The matter can be argued either way. The container-wrappers currently remain
- part of the proposal, but this may change.</p>
+ The matter can be argued either way. The container-wrappers currently remain
+ part of the proposal, but this may well change. In the meantime, the user is
+ quite capable of using either method:</p>
<h2 id="Architecture">
Architecture
</h2>
@@ -155,8 +187,7 @@
and is on the stack or the heap. The allocator is stored in the
container, which is initialised with either an allocator or storage, as shown
for example with monotonic::map:
- </p>
- <div class="code">
+ <div class="code">
<pre>/// A std::map<K,T,P> that uses a monotonic allocator
template <class K, class T, class P = std::less<K> >
struct map : std::map<K,T,P, allocator<K> >
@@ -307,13 +338,16 @@
<h2>
Notes</h2>
<p>
- [1] It can be argued that the proposed allocator is not in fact "STL-compliant",
- as it includes a pointer to storage used by the allocator. This can be addressed
- either by changing the standard to allow an allocator to store a pointer, or by
- removing this pointer and using a global pointer-to-storage.</p>
+ [1] It ca[1] It can be argued that the proposed allocator is not in fact "STL-compliant",
+ as it includes a pointer to storage used by the allocator. In truth, the
+ Standard doesn't state that allocators may not have any local data, only that
+ STL implementations are free to treat allocators of the same type as having the
+ same behavior. In practise, the distinction is largely academic and has had no
+ seen impact on this library. All modern STL implementation check for allocators
+ to do things like speed up swap methods etc. These all work with monotonic
+ allocator as well.</p>
<h2>
- References</h2>
- <ul class="simple">
+ References <ul class="simple">
<li>Boost.AlignedMemory</li>
<li>Boost.AutoBuffer. A related service. Attempts to integrate this with STL has so
far been unsuccessful. See libs/monotonic/test/main.cpp#test_auto_buffer</li>
Modified: sandbox/monotonic/libs/monotonic/test/main.cpp
==============================================================================
--- sandbox/monotonic/libs/monotonic/test/main.cpp (original)
+++ sandbox/monotonic/libs/monotonic/test/main.cpp 2009-06-13 07:56:14 EDT (Sat, 13 Jun 2009)
@@ -10,6 +10,11 @@
#include <boost/foreach.hpp>
#include <iostream>
+#include <boost/range.hpp>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/array.hpp>
+#include <boost/scoped_ptr.hpp>
+
using namespace std;
using namespace boost;
@@ -260,6 +265,7 @@
P = storage.allocate(11, 16);
assert(P == storage.begin() + 32);
+
typedef boost::array<char, 3> c0;
typedef boost::array<char, 6> c1;
typedef boost::array<char, 11> c2;
@@ -434,8 +440,50 @@
cout << "test_map_list: std: " << e1 << endl;
}
+template <class T>
+pair<boost::counting_iterator<T>, boost::counting_iterator<T> > range(T start, T end)
+{
+ typedef boost::counting_iterator<T> cit;
+ return std::make_pair(cit(start), cit(end));
+}
+
+
+void test_shared_allocators()
+{
+ monotonic::inline_storage<500> sa, sb;
+ typedef monotonic::allocator<int> Al;
+ {
+ std::vector<int, Al> v0(sa), v1(sa);
+ std::vector<int, Al> v2(sb), v3(sb);
+ std::list<int, Al> l0(sa), l1(sb);
+
+ assert(v0.get_allocator() == v1.get_allocator());
+ assert(v2.get_allocator() == v3.get_allocator());
+ assert(v0.get_allocator() != v2.get_allocator());
+ assert(v3.get_allocator() != v1.get_allocator());
+
+ for (int n = 0; n < 10; ++n)
+ v0.push_back(n);
+
+ v1 = v0;
+ v1.swap(v2); // swap from different allocators means they are copied
+ assert(v1.empty() && v3.empty() && v1 == v3);
+
+ assert(v2 == v0); // both are now [0..9]
+
+ v1.swap(v0); // swap from same allocators means no copying
+ assert(v2 == v1);
+ assert(v0 == v3);
+
+ l0.assign(v0.begin(), v0.end());
+ l1 = l0;
+ assert(l0 == l1);
+ }
+}
+
int main()
{
+ test_shared_allocators();
test_alignment();
test_auto_buffer();
test_speed();
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk