diff options
Diffstat (limited to 'src/boost/libs/pool/test/test_pool_alloc.cpp')
-rw-r--r-- | src/boost/libs/pool/test/test_pool_alloc.cpp | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/src/boost/libs/pool/test/test_pool_alloc.cpp b/src/boost/libs/pool/test/test_pool_alloc.cpp new file mode 100644 index 00000000..b0b50eab --- /dev/null +++ b/src/boost/libs/pool/test/test_pool_alloc.cpp @@ -0,0 +1,291 @@ +/* Copyright (C) 2000, 2001 Stephen Cleary + * Copyright (C) 2011 Kwan Ting Chan + * + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + */ + +#include "random_shuffle.hpp" +#include <boost/pool/pool_alloc.hpp> +#include <boost/pool/object_pool.hpp> + +#include <boost/detail/lightweight_test.hpp> + +#include <algorithm> +#include <deque> +#include <list> +#include <set> +#include <stdexcept> +#include <vector> + +#include <cstdlib> +#include <ctime> + +// Each "tester" object below checks into and out of the "cdtor_checker", +// which will check for any problems related to the construction/destruction of +// "tester" objects. +class cdtor_checker +{ +private: + // Each constructed object registers its "this" pointer into "objs" + std::set<void*> objs; + +public: + // True iff all objects that have checked in have checked out + bool ok() const { return objs.empty(); } + + ~cdtor_checker() + { + BOOST_TEST(ok()); + } + + void check_in(void * const This) + { + BOOST_TEST(objs.find(This) == objs.end()); + objs.insert(This); + } + + void check_out(void * const This) + { + BOOST_TEST(objs.find(This) != objs.end()); + objs.erase(This); + } +}; +static cdtor_checker mem; + +struct tester +{ + tester(bool throw_except = false) + { + if(throw_except) + { + throw std::logic_error("Deliberate constructor exception"); + } + + mem.check_in(this); + } + + tester(const tester &) + { + mem.check_in(this); + } + + ~tester() + { + mem.check_out(this); + } +}; + +// This is a wrapper around a UserAllocator. It just registers alloc/dealloc +// to/from the system memory. It's used to make sure pool's are allocating +// and deallocating system memory properly. +// Do NOT use this class with static or singleton pools. +template <typename UserAllocator> +struct TrackAlloc +{ + typedef typename UserAllocator::size_type size_type; + typedef typename UserAllocator::difference_type difference_type; + + static std::set<char *> allocated_blocks; + + static char * malloc(const size_type bytes) + { + char * const ret = UserAllocator::malloc(bytes); + allocated_blocks.insert(ret); + return ret; + } + + static void free(char * const block) + { + BOOST_TEST(allocated_blocks.find(block) != allocated_blocks.end()); + allocated_blocks.erase(block); + UserAllocator::free(block); + } + + static bool ok() + { + return allocated_blocks.empty(); + } +}; +template <typename UserAllocator> +std::set<char *> TrackAlloc<UserAllocator>::allocated_blocks; + +typedef TrackAlloc<boost::default_user_allocator_new_delete> track_alloc; + +void test() +{ + { + // Do nothing pool + boost::object_pool<tester> pool; + } + + { + // Construct several tester objects. Don't delete them (i.e., + // test pool's garbage collection). + boost::object_pool<tester> pool; + for(int i=0; i < 10; ++i) + { + pool.construct(); + } + } + + { + // Construct several tester objects. Delete some of them. + boost::object_pool<tester> pool; + std::vector<tester *> v; + for(int i=0; i < 10; ++i) + { + v.push_back(pool.construct()); + } + pool_test_random_shuffle(v.begin(), v.end()); + for(int j=0; j < 5; ++j) + { + pool.destroy(v[j]); + } + } + + { + // Test how pool reacts with constructors that throw exceptions. + // Shouldn't have any memory leaks. + boost::object_pool<tester> pool; + for(int i=0; i < 5; ++i) + { + pool.construct(); + } + for(int j=0; j < 5; ++j) + { + try + { + // The following constructions will raise an exception. + pool.construct(true); + } + catch(const std::logic_error &) {} + } + } +} + +void test_alloc() +{ + { + // Allocate several tester objects. Delete one. + std::vector<tester, boost::pool_allocator<tester> > l; + for(int i=0; i < 10; ++i) + { + l.push_back(tester()); + } + l.pop_back(); + } + + { + // Allocate several tester objects. Delete two. + std::deque<tester, boost::pool_allocator<tester> > l; + for(int i=0; i < 10; ++i) + { + l.push_back(tester()); + } + l.pop_back(); + l.pop_front(); + } + + { + // Allocate several tester objects. Delete two. + std::list<tester, boost::fast_pool_allocator<tester> > l; + // lists rebind their allocators, so dumping is useless + for(int i=0; i < 10; ++i) + { + l.push_back(tester()); + } + l.pop_back(); + l.pop_front(); + } + + tester * tmp; + { + // Create a memory leak on purpose. (Allocator doesn't have + // garbage collection) + // (Note: memory leak) + boost::pool_allocator<tester> a; + tmp = a.allocate(1, 0); + new (tmp) tester(); + } + if(mem.ok()) + { + BOOST_ERROR("Pool allocator cleaned up itself"); + } + // Remove memory checker entry (to avoid error later) and + // clean up memory leak + tmp->~tester(); + boost::pool_allocator<tester>::deallocate(tmp, 1); + + // test allocating zero elements + { + boost::pool_allocator<tester> alloc; + tester* ip = alloc.allocate(0); + alloc.deallocate(ip, 0); + } +} + +void test_mem_usage() +{ + typedef boost::pool<track_alloc> pool_type; + + { + // Constructor should do nothing; no memory allocation + pool_type pool(sizeof(int)); + BOOST_TEST(track_alloc::ok()); + BOOST_TEST(!pool.release_memory()); + BOOST_TEST(!pool.purge_memory()); + + // Should allocate from system + pool.free(pool.malloc()); + BOOST_TEST(!track_alloc::ok()); + + // Ask pool to give up memory it's not using; this should succeed + BOOST_TEST(pool.release_memory()); + BOOST_TEST(track_alloc::ok()); + + // Should allocate from system again + pool.malloc(); // loses the pointer to the returned chunk (*A*) + + // Ask pool to give up memory it's not using; this should fail + BOOST_TEST(!pool.release_memory()); + + // Force pool to give up memory it's not using; this should succeed + // This will clean up the memory leak from (*A*) + BOOST_TEST(pool.purge_memory()); + BOOST_TEST(track_alloc::ok()); + + // Should allocate from system again + pool.malloc(); // loses the pointer to the returned chunk (*B*) + + // pool's destructor should purge the memory + // This will clean up the memory leak from (*B*) + } + + BOOST_TEST(track_alloc::ok()); +} + +void test_void() +{ + typedef boost::pool_allocator<void> void_allocator; + typedef boost::fast_pool_allocator<void> fast_void_allocator; + + typedef void_allocator::rebind<int>::other int_allocator; + typedef fast_void_allocator::rebind<int>::other fast_int_allocator; + + std::vector<int, int_allocator> v1; + std::vector<int, fast_int_allocator> v2; +} + +int main() +{ + std::srand(static_cast<unsigned>(std::time(0))); + + test(); + test_alloc(); + test_mem_usage(); + test_void(); + + return boost::report_errors(); +} |