1 #ifdef COMPILATION// -*-indent-tabs-mode:t;c-basic-offset:4;tab-width:4;-*-
2 $CXXX $CXXFLAGS $0 -o $0x -lboost_unit_test_framework&&$0x&&rm $0x;exit
3 #endif
4 // © Alfredo A. Correa 2019-2020
5 
6 #ifndef BOOST_MULTI_MEMORY_STACK_HPP
7 #define BOOST_MULTI_MEMORY_STACK_HPP
8 
9 #include "../memory/monotonic.hpp"
10 #include "../memory/allocator.hpp"
11 
12 #include<cstddef> // max_align_t
13 #include<stack>
14 #include<cassert>
15 
16 namespace boost{
17 namespace multi{
18 namespace memory{
19 
20 template<typename Ptr = byte*, std::size_t Align = alignof(std::max_align_t)>
21 class stack : protected monotonic<Ptr, Align>{
22 private:
23 	std::stack<typename stack::void_pointer> positions_ = {};
24 	typename stack::size_type total_requested_ = 0;
25 	typename stack::size_type total_discarded_ = 0;
26 	typename stack::size_type max_needed_ = 0;
27 	long hits_ = 0;
28 public:
hits() const29 	long hits() const{return hits_;}
reset()30 	void reset(){monotonic<Ptr, Align>::reset(); positions_.clear();}
max_needed() const31 	typename stack::size_type max_needed() const{return max_needed_;}
32 	using monotonic<Ptr, Align>::monotonic;
33 	template<std::size_t AA = Align>
allocate(typename stack::size_type required_bytes,typename stack::size_type align=AA)34 	typename stack::void_pointer allocate(
35 		typename stack::size_type required_bytes,
36 		typename stack::size_type align = AA
37 	){
38 		total_requested_ += required_bytes;
39 		max_needed_ = std::max(max_needed_, total_requested_ - total_discarded_);
40 		positions_.push(monotonic<Ptr, Align>::template allocate<AA>(required_bytes, align));
41 		++hits_;
42 		return positions_.top();
43 	}
deallocate(typename stack::void_pointer p,typename stack::size_type discarded_bytes)44 	void deallocate(
45 		typename stack::void_pointer p,
46 		typename stack::size_type discarded_bytes
47 	){
48 		total_discarded_ += discarded_bytes;
49 		monotonic<Ptr, Align>::deallocate(p, discarded_bytes);//positions_.top(), discarded_bytes);
50 		assert( p == positions_.top() && "stack violation" );
51 		this->position_ -= discarded_bytes;
52 		positions_.pop();
53 	}
54 };
55 
56 template<class T>
57 using stack_allocator = multi::memory::allocator<T, stack<char*>>;//, alignof(T)>>;
58 
59 }}}
60 
61 #if not __INCLUDE_LEVEL__
62 #define BOOST_TEST_MODULE "C++ Unit Tests for Multi stack memory resource"
63 #define BOOST_TEST_DYN_LINK
64 #include<boost/test/unit_test.hpp>
65 
66 #include "../../multi/array.hpp"
67 #include<vector>
68 
69 namespace multi = boost::multi;
70 namespace memory = multi::memory;
71 
BOOST_AUTO_TEST_CASE(multi_memory_allocator)72 BOOST_AUTO_TEST_CASE(multi_memory_allocator){
73 {
74 	alignas(double) char buffer[256*sizeof(double)];
75 	memory::stack<char*> stck(buffer);
76 	auto p1 = stck.allocate(1*sizeof(double), alignof(double));
77 	BOOST_REQUIRE( stck.max_needed() == 1*sizeof(double) );
78 
79 	auto p2 = stck.allocate(255*sizeof(double), alignof(double));
80 	BOOST_REQUIRE( stck.max_needed() == 256*sizeof(double) );
81 
82 	stck.deallocate(p2, 255*sizeof(double));
83 	BOOST_REQUIRE( stck.max_needed() == 256*sizeof(double) );
84 
85 	stck.deallocate(p1, 1*sizeof(double));
86 	BOOST_REQUIRE( stck.max_needed() == 256*sizeof(double) );
87 
88 	auto p3 = stck.allocate(100*sizeof(double)); (void)p3;
89 }
90 {
91 	alignas(double) char buffer[256*sizeof(double)];
92 	multi::memory::stack<char*> sm(buffer);
93 	{
94 		std::vector<double, multi::memory::stack_allocator<double>> v(10, &sm);
95 		std::vector<double, multi::memory::stack_allocator<double>> w(10, &sm);
96 	}
97 	std::vector<double, multi::memory::stack_allocator<double>> w(5, &sm);
98 	BOOST_REQUIRE( sm.max_needed()/sizeof(double) == 20 );
99 }
100 }
101 #endif
102 #endif
103 
104