Logo ROOT  
Reference Guide
RAdoptAllocator.hxx
Go to the documentation of this file.
1 // Author: Enrico Guiraud, Enric Tejedor, Danilo Piparo CERN 01/2018
2 
3 /*************************************************************************
4  * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
5  * All rights reserved. *
6  * *
7  * For the licensing terms see $ROOTSYS/LICENSE. *
8  * For the list of contributors see $ROOTSYS/README/CREDITS. *
9  *************************************************************************/
10 
11 #ifndef ROOT_TADOPTALLOCATOR
12 #define ROOT_TADOPTALLOCATOR
13 
14 #include <iostream>
15 #include <memory>
16 
17 namespace ROOT {
18 namespace Detail {
19 namespace VecOps {
20 
21 /**
22 \class ROOT::Detail::VecOps::RAdoptAllocator
23 \ingroup vecops
24 \brief RAdoptAllocator can provide a view on already allocated memory.
25 
26 The RAdoptAllocator behaves like the standard allocator, and, as such, can be used to create
27 stl containers. In addition, it behaves as if it allocated a certain memory region which
28 is indeed not managed by it, but rather is "adopted".
29 This is most useful to take advantage of widely adopted entities such as std::vector in a
30 novel way, namely offering nice interfaces around an arbitrary memory region.
31 
32 If memory is adopted, the first allocation returns the address of this memory region. For
33 the subsequent allocations, the RAdoptAllocator behaves like a standard allocator.
34 
35 For example:
36 ~~~{.cpp}
37 std::vector<double> model {1, 2, 3};
38 unsigned int dummy;
39 RAdoptAllocator<double> alloc(model.data(), model.size());
40 std::vector<double, RAdoptAllocator<double>> v(model.size(), 0., alloc);
41 ~~~
42 Now the vector *v* is ready to be used, de facto proxying the memory of the vector *model*.
43 Upon a second allocation, the vector *v* ceases to be a proxy
44 ~~~{.cpp}
45 v.emplace_back(0.);
46 ~~~
47 now the vector *v* owns its memory as a regular vector.
48 **/
49 
50 template <typename T>
52 public:
53  friend class RAdoptAllocator<bool>;
54 
56  using propagate_on_container_swap = std::true_type;
57  using StdAlloc_t = std::allocator<T>;
58  using value_type = typename StdAlloc_t::value_type;
59  using pointer = typename StdAlloc_t::pointer;
60  using const_pointer = typename StdAlloc_t::const_pointer;
61  using reference = typename StdAlloc_t::reference;
62  using const_reference = typename StdAlloc_t::const_reference;
63  using size_type = typename StdAlloc_t::size_type;
64  using difference_type = typename StdAlloc_t::difference_type;
65  template <typename U>
66  struct rebind {
68  };
69 
70 private:
72  using StdAllocTraits_t = std::allocator_traits<StdAlloc_t>;
76 
77 public:
78  /// This is the constructor which allows the allocator to adopt a certain memory region.
79  RAdoptAllocator(pointer p) : fInitialAddress(p), fAllocType(EAllocType::kAdoptingNoAllocYet){};
80  RAdoptAllocator() = default;
81  RAdoptAllocator(const RAdoptAllocator &) = default;
86 
87  /// Construct an object at a certain memory address
88  /// \tparam U The type of the memory address at which the object needs to be constructed
89  /// \tparam Args The arguments' types necessary for the construction of the object
90  /// \param[in] p The memory address at which the object needs to be constructed
91  /// \param[in] args The arguments necessary for the construction of the object
92  /// This method is a no op if memory has been adopted.
93  template <class U, class... Args>
94  void construct(U *p, Args &&... args)
95  {
96  // We refuse to do anything since we assume the memory is already initialised
98  return;
99  fStdAllocator.construct(p, std::forward<Args>(args)...);
100  }
101 
102  /// \brief Allocate some memory
103  /// If an address has been adopted, at the first call, that address is returned.
104  /// Subsequent calls will make "decay" the allocator to a regular stl allocator.
105  pointer allocate(std::size_t n)
106  {
107  if (n > std::size_t(-1) / sizeof(T))
108  throw std::bad_alloc();
111  return fInitialAddress;
112  }
114  return StdAllocTraits_t::allocate(fStdAllocator, n);
115  }
116 
117  /// \brief Dellocate some memory if that had not been adopted.
118  void deallocate(pointer p, std::size_t n)
119  {
120  if (p != fInitialAddress)
121  StdAllocTraits_t::deallocate(fStdAllocator, p, n);
122  }
123 
124  template <class U>
125  void destroy(U *p)
126  {
128  fStdAllocator.destroy(p);
129  }
130  }
131 
132  bool operator==(const RAdoptAllocator<T> &other)
133  {
134  return fInitialAddress == other.fInitialAddress && fAllocType == other.fAllocType &&
135  fStdAllocator == other.fStdAllocator;
136  }
137 
138  bool operator!=(const RAdoptAllocator<T> &other) { return !(*this == other); }
139 
140  size_type max_size() const { return fStdAllocator.max_size(); };
141 };
142 
143 // The different semantics of std::vector<bool> make memory adoption through a
144 // custom allocator more complex -- namely, RAdoptAllocator<bool> must be rebindable
145 // to RAdoptAllocator<unsigned long>, but if adopted memory is really a buffer of
146 // bools reinterpretation of the buffer is not going to work. As a workaround,
147 // RAdoptAllocator<bool> is specialized to be a simple allocator that forwards calls
148 // to std::allocator and never adopts memory.
149 template <>
151  std::allocator<bool> fStdAllocator;
152 
153 public:
154  template <typename U>
155  struct rebind {
157  };
158 
159  template <typename T>
160  friend class RAdoptAllocator;
161 
162  using StdAlloc_t = std::allocator<bool>;
163  using value_type = typename StdAlloc_t::value_type;
164  using pointer = typename StdAlloc_t::pointer;
165  using const_pointer = typename StdAlloc_t::const_pointer;
166  using reference = typename StdAlloc_t::reference;
167  using const_reference = typename StdAlloc_t::const_reference;
168  using size_type = typename StdAlloc_t::size_type;
169  using difference_type = typename StdAlloc_t::difference_type;
170 
171  RAdoptAllocator() = default;
172  RAdoptAllocator(const RAdoptAllocator &) = default;
173 
174  template <typename U>
176  {
178  throw std::runtime_error("Cannot rebind owning RAdoptAllocator");
179  }
180 
181  bool *allocate(std::size_t n) { return fStdAllocator.allocate(n); }
182 
183  template <typename U, class... Args>
184  void construct(U *p, Args &&... args)
185  {
186  fStdAllocator.construct(p, std::forward<Args>(args)...);
187  }
188 
189  void deallocate(bool *p, std::size_t s) noexcept { fStdAllocator.deallocate(p, s); }
190 
191  template <class U>
192  void destroy(U *p)
193  {
194  fStdAllocator.destroy(p);
195  }
196 
197  bool operator==(const RAdoptAllocator &) { return true; }
198 
199  bool operator!=(const RAdoptAllocator &) { return false; }
200 };
201 
202 template <typename T>
203 RAdoptAllocator<T>::RAdoptAllocator(const RAdoptAllocator<bool> &o) : fStdAllocator(o.fStdAllocator) {}
204 
205 } // End NS VecOps
206 } // End NS Detail
207 } // End NS ROOT
208 
209 #endif
ROOT::Detail::VecOps::RAdoptAllocator::RAdoptAllocator
RAdoptAllocator(RAdoptAllocator &&)=default
ROOT::Detail::VecOps::RAdoptAllocator< bool >::reference
typename StdAlloc_t::reference reference
Definition: RAdoptAllocator.hxx:166
n
const Int_t n
Definition: legend1.C:16
ROOT::Detail::VecOps::RAdoptAllocator< bool >::const_pointer
typename StdAlloc_t::const_pointer const_pointer
Definition: RAdoptAllocator.hxx:165
ROOT::Detail::VecOps::RAdoptAllocator::max_size
size_type max_size() const
Definition: RAdoptAllocator.hxx:140
ROOT::Detail::VecOps::RAdoptAllocator::fInitialAddress
pointer fInitialAddress
Definition: RAdoptAllocator.hxx:73
ROOT::Detail::VecOps::RAdoptAllocator::EAllocType::kOwning
@ kOwning
ROOT::Detail::VecOps::RAdoptAllocator< bool >::value_type
typename StdAlloc_t::value_type value_type
Definition: RAdoptAllocator.hxx:163
ROOT::Detail::VecOps::RAdoptAllocator< bool >::difference_type
typename StdAlloc_t::difference_type difference_type
Definition: RAdoptAllocator.hxx:169
ROOT::Detail::VecOps::RAdoptAllocator::value_type
typename StdAlloc_t::value_type value_type
Definition: RAdoptAllocator.hxx:58
TGeant4Unit::s
static constexpr double s
Definition: TGeant4SystemOfUnits.h:162
ROOT::Detail::VecOps::RAdoptAllocator::fStdAllocator
StdAlloc_t fStdAllocator
Definition: RAdoptAllocator.hxx:75
ROOT::Detail::VecOps::RAdoptAllocator::RAdoptAllocator
RAdoptAllocator(const RAdoptAllocator &)=default
ROOT::Detail::VecOps::RAdoptAllocator::rebind
Definition: RAdoptAllocator.hxx:66
ROOT::Detail::VecOps::RAdoptAllocator< bool >::size_type
typename StdAlloc_t::size_type size_type
Definition: RAdoptAllocator.hxx:168
ROOT::Detail::VecOps::RAdoptAllocator::const_reference
typename StdAlloc_t::const_reference const_reference
Definition: RAdoptAllocator.hxx:62
bool
ROOT::Detail::VecOps::RAdoptAllocator< bool >::fStdAllocator
std::allocator< bool > fStdAllocator
Definition: RAdoptAllocator.hxx:151
ROOT::Detail::VecOps::RAdoptAllocator::size_type
typename StdAlloc_t::size_type size_type
Definition: RAdoptAllocator.hxx:63
ROOT::Detail::VecOps::RAdoptAllocator::reference
typename StdAlloc_t::reference reference
Definition: RAdoptAllocator.hxx:61
ROOT::Detail::VecOps::RAdoptAllocator< bool >::construct
void construct(U *p, Args &&... args)
Definition: RAdoptAllocator.hxx:184
ROOT::Detail::VecOps::RAdoptAllocator::EAllocType::kAdopting
@ kAdopting
ROOT::Detail::VecOps::RAdoptAllocator< bool >::deallocate
void deallocate(bool *p, std::size_t s) noexcept
Definition: RAdoptAllocator.hxx:189
ROOT::Detail::VecOps::RAdoptAllocator::RAdoptAllocator
RAdoptAllocator()=default
ROOT::Detail::VecOps::RAdoptAllocator::StdAllocTraits_t
std::allocator_traits< StdAlloc_t > StdAllocTraits_t
Definition: RAdoptAllocator.hxx:72
ROOT::Detail::VecOps::RAdoptAllocator::const_pointer
typename StdAlloc_t::const_pointer const_pointer
Definition: RAdoptAllocator.hxx:60
ROOT::Detail::VecOps::RAdoptAllocator::EAllocType::kAdoptingNoAllocYet
@ kAdoptingNoAllocYet
ROOT::Detail::VecOps::RAdoptAllocator::RAdoptAllocator
RAdoptAllocator(pointer p)
This is the constructor which allows the allocator to adopt a certain memory region.
Definition: RAdoptAllocator.hxx:79
ROOT::Detail::VecOps::RAdoptAllocator::difference_type
typename StdAlloc_t::difference_type difference_type
Definition: RAdoptAllocator.hxx:64
ROOT::Detail::VecOps::RAdoptAllocator::pointer
typename StdAlloc_t::pointer pointer
Definition: RAdoptAllocator.hxx:59
ROOT::Detail::VecOps::RAdoptAllocator::propagate_on_container_move_assignment
std::true_type propagate_on_container_move_assignment
Definition: RAdoptAllocator.hxx:55
ROOT::Detail::VecOps::RAdoptAllocator< bool >::pointer
typename StdAlloc_t::pointer pointer
Definition: RAdoptAllocator.hxx:164
ROOT::Detail::VecOps::RAdoptAllocator::construct
void construct(U *p, Args &&... args)
Construct an object at a certain memory address.
Definition: RAdoptAllocator.hxx:94
ROOT::Detail::VecOps::RAdoptAllocator< bool >
Definition: RAdoptAllocator.hxx:150
ROOT::Detail::VecOps::RAdoptAllocator::EAllocType
EAllocType
Definition: RAdoptAllocator.hxx:71
ROOT::Detail::VecOps::RAdoptAllocator< bool >::operator==
bool operator==(const RAdoptAllocator &)
Definition: RAdoptAllocator.hxx:197
ROOT::Detail::VecOps::RAdoptAllocator::propagate_on_container_swap
std::true_type propagate_on_container_swap
Definition: RAdoptAllocator.hxx:56
ROOT::Detail::VecOps::RAdoptAllocator::StdAlloc_t
std::allocator< T > StdAlloc_t
Definition: RAdoptAllocator.hxx:57
ROOT::Detail::VecOps::RAdoptAllocator::destroy
void destroy(U *p)
Definition: RAdoptAllocator.hxx:125
ROOT::Detail::VecOps::RAdoptAllocator::fAllocType
EAllocType fAllocType
Definition: RAdoptAllocator.hxx:74
ROOT::Detail::VecOps::RAdoptAllocator< bool >::StdAlloc_t
std::allocator< bool > StdAlloc_t
Definition: RAdoptAllocator.hxx:162
ROOT::Detail::VecOps::RAdoptAllocator< bool >::RAdoptAllocator
RAdoptAllocator(const RAdoptAllocator &)=default
ROOT::Detail::VecOps::RAdoptAllocator::operator==
bool operator==(const RAdoptAllocator< T > &other)
Definition: RAdoptAllocator.hxx:132
ROOT::Detail::VecOps::RAdoptAllocator< bool >::const_reference
typename StdAlloc_t::const_reference const_reference
Definition: RAdoptAllocator.hxx:167
ROOT::Detail::VecOps::RAdoptAllocator::allocate
pointer allocate(std::size_t n)
Allocate some memory If an address has been adopted, at the first call, that address is returned.
Definition: RAdoptAllocator.hxx:105
ROOT::Detail::VecOps::RAdoptAllocator< bool >::destroy
void destroy(U *p)
Definition: RAdoptAllocator.hxx:192
ROOT::Detail::VecOps::RAdoptAllocator
RAdoptAllocator can provide a view on already allocated memory.
Definition: RAdoptAllocator.hxx:51
ROOT::Detail::VecOps::RAdoptAllocator< bool >::operator!=
bool operator!=(const RAdoptAllocator &)
Definition: RAdoptAllocator.hxx:199
ROOT::Detail::VecOps::RAdoptAllocator< bool >::RAdoptAllocator
RAdoptAllocator()=default
ROOT::Detail::VecOps::RAdoptAllocator::operator!=
bool operator!=(const RAdoptAllocator< T > &other)
Definition: RAdoptAllocator.hxx:138
ROOT::Math::Chebyshev::T
double T(double x)
Definition: ChebyshevPol.h:34
ROOT::Detail::VecOps::RAdoptAllocator::operator=
RAdoptAllocator & operator=(const RAdoptAllocator &)=default
ROOT::Detail::VecOps::RAdoptAllocator::deallocate
void deallocate(pointer p, std::size_t n)
Dellocate some memory if that had not been adopted.
Definition: RAdoptAllocator.hxx:118
ROOT::Detail::VecOps::RAdoptAllocator< bool >::allocate
bool * allocate(std::size_t n)
Definition: RAdoptAllocator.hxx:181
ROOT::Detail::VecOps::RAdoptAllocator< bool >::RAdoptAllocator
RAdoptAllocator(const RAdoptAllocator< U > &o)
Definition: RAdoptAllocator.hxx:175
ROOT
VSD Structures.
Definition: StringConv.hxx:21
ROOT::Detail::VecOps::RAdoptAllocator::operator=
RAdoptAllocator & operator=(RAdoptAllocator &&)=default