libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
memory_buffer.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_CORE_MEMORY_BUFFER_HPP
2 #define LIBJMMCG_CORE_MEMORY_BUFFER_HPP
3 /******************************************************************************
4 ** Copyright © 2004 by J.M.McGuiness, coder@hussar.me.uk
5 **
6 ** This library is free software; you can redistribute it and/or
7 ** modify it under the terms of the GNU Lesser General Public
8 ** License as published by the Free Software Foundation; either
9 ** version 2.1 of the License, or (at your option) any later version.
10 **
11 ** This library is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** Lesser General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public
17 ** License along with this library; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 
21 #include "exception.hpp"
22 
23 #include <boost/mpl/assert.hpp>
24 #include <boost/mpl/comparison.hpp>
25 #include <boost/mpl/greater.hpp>
26 #include <boost/mpl/int.hpp>
27 
28 #include <memory>
29 #include <type_traits>
30 
31 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
32 
33 namespace heap {
34 
35 /// A very simple custom allocator that allocates a contiguous block of *uninitialised* items on the heap.
36 /**
37  Note that the items allocated are guaranteed not to be initialised.
38 */
39 template<
40  class OST,
41  class El
42 >
44 public:
45  typedef OST os_traits;
47  typedef El element_type; ///< The type of items to allocate, but not initialise.
48 
49 private:
50  typedef std::pair<element_type*, std::ptrdiff_t> buff_info_t;
51 
52 public:
53  typedef typename buff_info_t::second_type size_type;
54  typedef unsigned char const * const_iterator;
55  typedef unsigned char * iterator;
56 
57  enum {
58  stride=sizeof(element_type) ///< The sizeof(element_type) each item, specifically in bytes.
59  };
60 
61  BOOST_MPL_ASSERT((boost::mpl::greater<boost::mpl::int_<stride>, boost::mpl::int_<0>>));
62 
63  /**
64  \param num_objs The number of the items to be allocated.
65  */
66  explicit memory_buffer(size_type const num_objs) noexcept(false) FORCE_INLINE
67  : buff_info(std::get_temporary_buffer<element_type>(num_objs)) {
68  if (!buff_info.first || buff_info.second<num_objs) {
69  info::function fun(__LINE__, __PRETTY_FUNCTION__, typeid(*this), info::function::argument(_T("size_type const num_objs"), num_objs));
70  fun.add_args(
71  info::function::argument(_T("allocated buffer address"), buff_info.first),
72  info::function::argument(_T("allocated buffer size"), buff_info.second),
73  info::function::argument(_T("stride"), stride)
74  );
75  throw exception_type(_T("Failed to allocate custom memory-buffer for the internal operation of the parallel algorithm."), std::move(fun), JMMCG_REVISION_HDR(_T(LIBJMMCG_VERSION_NUMBER)));
76  }
77  assert(data()!=0);
78  assert(stride>0);
79  assert(std::fill_n(data(), stride*max_size(), static_cast<unsigned char>(0)));
80  }
81  ~memory_buffer() noexcept(true) FORCE_INLINE {
82  std::return_temporary_buffer(buff_info.first);
83  }
84 
85  memory_buffer(memory_buffer const &)=delete;
87  void operator=(memory_buffer const &)=delete;
88  void operator=(memory_buffer &&)=delete;
89 
90  /**
91  \return Note the iterator returned is a byte-pointer.
92  */
93  const_iterator data() const noexcept(true) FORCE_INLINE {
94  return reinterpret_cast<const_iterator const>(buff_info.first);
95  }
96  /**
97  \return Note the iterator returned is a byte-pointer.
98  */
99  iterator data() noexcept(true) FORCE_INLINE {
100  return reinterpret_cast<iterator>(buff_info.first);
101  }
102 
103  /**
104  \return The size of the buffer in number of items.
105  */
106  size_type __fastcall max_size() const noexcept(true) FORCE_INLINE {
107  return buff_info.second;
108  }
109 
110  /**
111  \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170.
112  */
113  friend inline tostream &__fastcall
114  operator<<(tostream &os, memory_buffer const &t) noexcept(false) {
115  os
116  <<_T("buffer address=0x")<<std::hex<<t.data()
117  <<_T(", size=")<<std::dec<<t.max_size()
118  <<_T(", stride=")<<memory_buffer::stride;
119  return os;
120  }
121 
122 private:
123  const buff_info_t buff_info;
124 };
125 
126 }
127 
128 namespace stack {
129 
130 /// A very simple custom allocator that allocates a contiguous block of *uninitialised* items on the stack.
131 /**
132  A simple char[] does not respect alignment, whereas this class ensures that the objects are suitably aligned.
133  Note that the items allocated are guaranteed not to be initialised, which is how this differs from std::array, which, as I understand it, must default-initialise each std::array::value_type member according to 8.5.1p7 of the ISO Standard.
134 
135  \see std::array
136 */
137 template<
138  class El,
139  std::size_t num_objs ///< The number of the items to be allocated.
140 >
142 public:
143  typedef El element_type; ///< The type of items to allocate, but not initialise.
144 
145 private:
146  typedef typename std::aligned_storage<sizeof(element_type), std::alignment_of<element_type>::value>::type aligned_type;
147  typedef aligned_type buff_info_t[num_objs];
148 
149 public:
150  enum : std::size_t {
151  stride=sizeof(element_type), ///< The sizeof(element_type) each item, specifically in bytes.
152  max_size_=num_objs ///< The size of the buffer in number of items.
153  };
154 
155  BOOST_MPL_ASSERT((boost::mpl::greater<boost::mpl::int_<num_objs>, boost::mpl::int_<0>>));
156  BOOST_MPL_ASSERT((boost::mpl::greater<boost::mpl::int_<stride>, boost::mpl::int_<0>>));
157  BOOST_MPL_ASSERT((boost::mpl::greater<boost::mpl::int_<max_size_>, boost::mpl::int_<0>>));
158 
159 public:
160  typedef typename std::size_t size_type;
161  typedef unsigned char const * const_iterator;
162  typedef unsigned char * iterator;
163 
164  memory_buffer() noexcept(true) FORCE_INLINE {
165  assert(std::fill_n(data(), stride*max_size(), static_cast<unsigned char>(0)));
166  }
167  ~memory_buffer() noexcept(true) FORCE_INLINE {}
168 
169  const_iterator data() const noexcept(true) FORCE_INLINE {
170  return reinterpret_cast<const_iterator>(buff_info);
171  }
172  iterator data() noexcept(true) FORCE_INLINE {
173  return reinterpret_cast<iterator>(buff_info);
174  }
175 
176  /**
177  \return The size of the buffer in number of items.
178  */
179  static constexpr size_type max_size() noexcept(true) FORCE_INLINE {
180  return max_size_;
181  }
182 
183  /**
184  \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170.
185  */
186  friend inline tostream &
187  operator<<(tostream &os, memory_buffer const &t) noexcept(false) {
188  os
189  <<_T("buffer address=0x")<<std::hex<<t.data()
190  <<_T(", size=")<<std::dec<<t.max_size()
191  <<_T(", stride=")<<memory_buffer::stride;
192  return os;
193  }
194 
195 private:
196  buff_info_t buff_info;
197 
198  memory_buffer(memory_buffer const &)=delete;
199  memory_buffer(memory_buffer &&)=delete;
200  void operator=(memory_buffer const &)=delete;
201  void operator=(memory_buffer &&)=delete;
202 };
203 
204 } } }
205 
206 #endif