Audacity 3.2.0
PackedArray.h
Go to the documentation of this file.
1/*!********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file PackedArray.h
6
7 @brief Smart pointer for a header contiguous with an array holding a
8 dynamically determined number of elements
9
10 Paul Licameli
11
12 **********************************************************************/
13
14#ifndef __AUDACITY_PACKED_ARRAY__
15#define __AUDACITY_PACKED_ARRAY__
16
17#include <type_traits>
18
19namespace PackedArray {
20
21template<typename T> struct Traits;
22
23namespace detail {
24
26template<typename T, typename = void> struct ExtendedTraits : Traits<T> {
28 using iterated_type = T;
29 static iterated_type *begin(T *p) { return p; }
30 static element_type *element_ptr(T *p) { return p; }
31 static size_t element_offset() { return 0; }
32};
33
35template<typename T> struct ExtendedTraits<T, std::void_t<decltype(
36 std::declval<T>().*(Traits<T>::array_member)
37)>> : Traits<T> {
39 using member_type = std::remove_reference_t<decltype(
40 std::declval<T>().*(Traits<T>::array_member)
41 )>;
42 // Check restrictions on usage. The member is expected to have dimension 1
43 static_assert(std::extent_v<member_type> == 1);
44 using iterated_type = std::remove_extent_t<member_type>;
45 // Check that any overlay of a type with a destructor is sensible
46 static_assert(sizeof(iterated_type) == sizeof(element_type));
47
48 static iterated_type *begin(T *p) {
49 return &(p->*(Traits<T>::array_member))[0];
50 }
51 static element_type *element_ptr(T *p) {
52 return reinterpret_cast<element_type*>(begin(p));
53 }
54 static size_t element_offset() {
55 return reinterpret_cast<size_t>(begin(0));
56 }
57};
58
59}
60
62
66template<typename T> struct Traits{
67 // Default assumption is that there is no header and no need to overlay
68 // the element with a type that performs nontrivial destruction
69 struct header_type {};
70 using element_type = T;
71};
72
74
85template<typename Type,
86 template<typename> typename BaseDeleter = std::default_delete>
87struct Deleter : BaseDeleter<Type> {
88 using managed_type = Type;
89 using base_type = BaseDeleter<managed_type>;
93
96 Deleter(size_t size = 0) noexcept
97 : mCount{ size
99 : 0
100 }
101 {}
102
103 void operator()(Type *p) const noexcept(noexcept(
104 (void)std::declval<element_type>().~element_type(),
105 (void)std::declval<header_type>().~header_type(),
106 (void)std::declval<base_type>()(p)
107 )) {
108 if (!p)
109 return;
110 // Do nested deallocations for elements by decreasing subscript
111 auto pE = traits_type::element_ptr(p) + mCount;
112 for (auto count = mCount; count--;)
113 (--pE)->~element_type();
114 // Do nested deallocations for main structure
115 reinterpret_cast<const header_type*>(p)->~header_type();
116 // main deallocation
117 ((base_type&)*this)(p);
118 }
119
120 size_t GetCount() const { return mCount; }
121private:
122 size_t mCount = 0;
123};
124
126template<typename Type,
127 template<typename> typename BaseDeleter = std::default_delete>
128struct Ptr
129 : std::unique_ptr<Type, Deleter<Type, BaseDeleter>>
130{
131 using
132 std::unique_ptr<Type, Deleter<Type, BaseDeleter>>::unique_ptr;
133
135 auto &operator[](size_t ii) const
136 {
137 return *(begin(*this) + ii);
138 }
139};
140
142template<typename Type, template<typename> typename BaseDeleter>
143inline size_t Count(const Ptr<Type, BaseDeleter> &p)
144{
145 return p.get_deleter().GetCount();
146}
147
149template<typename Type, template<typename> typename BaseDeleter>
150inline auto begin(const Ptr<Type, BaseDeleter> &p)
151{
152 using traits_type = detail::ExtendedTraits<Type>;
153 auto ptr = p.get();
154 return ptr ? traits_type::begin(ptr) : nullptr;
155}
156
158template<typename Type, template<typename> typename BaseDeleter>
159inline auto end(const Ptr<Type, BaseDeleter> &p)
160{
161 auto result = begin(p);
162 if (result)
163 result += Count(p);
164 return result;
165}
166
167}
168
171static constexpr inline PackedArray_t PackedArrayArg;
172
175inline void *operator new(size_t size, PackedArray_t, size_t enlarged) {
176 return ::operator new(std::max(size, enlarged));
177}
178
180inline void operator delete(void *p, PackedArray_t, size_t) {
181 ::operator delete(p);
182}
183
184namespace PackedArray {
185
187
192template<typename Type> auto AllocateBytes(size_t enlarged)
193{
194 return [enlarged](auto &&...args) {
195 return Ptr<Type>{
196 safenew(PackedArrayArg, enlarged)
197 Type{ std::forward<decltype(args)>(args)... },
198 std::max(sizeof(Type), enlarged) // Deleter's constructor argument
199 };
200 };
201}
202
204
212template<typename Type> auto AllocateCount(size_t count)
213{
214 using traits_type = detail::ExtendedTraits<Type>;
215 const auto bytes = traits_type::element_offset()
216 + count * sizeof(typename traits_type::element_type);
217 return AllocateBytes<Type>(bytes);
218}
219
220}
221
222#endif
#define safenew
Definition: MemoryX.h:10
static constexpr PackedArray_t PackedArrayArg
Tag argument to distinguish an overload of operator new.
Definition: PackedArray.h:171
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
auto AllocateCount(size_t count)
Allocate a Ptr<Type> holding count elements.
Definition: PackedArray.h:212
auto AllocateBytes(size_t enlarged)
Allocate a Ptr<Type> holding at least enlarged bytes.
Definition: PackedArray.h:192
size_t Count(const Ptr< Type, BaseDeleter > &p)
Find out how many elements were allocated with a Ptr.
Definition: PackedArray.h:143
STL namespace.
Deleter for an array of elements and optional contiguous header structure.
Definition: PackedArray.h:87
typename traits_type::header_type header_type
Definition: PackedArray.h:91
typename traits_type::element_type element_type
Definition: PackedArray.h:92
void operator()(Type *p) const noexcept(noexcept((void) std::declval< element_type >().~element_type(),(void) std::declval< header_type >().~header_type(),(void) std::declval< base_type >()(p)))
Definition: PackedArray.h:103
size_t GetCount() const
Definition: PackedArray.h:120
BaseDeleter< managed_type > base_type
Definition: PackedArray.h:89
Deleter(size_t size=0) noexcept
Definition: PackedArray.h:96
Smart pointer type that deallocates with Deleter.
Definition: PackedArray.h:130
auto & operator[](size_t ii) const
Enables subscripting. Does not check for null!
Definition: PackedArray.h:135
Primary template used in Deleter that can be specialized.
Definition: PackedArray.h:66
std::remove_reference_t< decltype(std::declval< T >().*(Traits< T >::array_member))> member_type
Definition: PackedArray.h:41
Primary template of metafunction deducing other things from Traits<T>
Definition: PackedArray.h:26
static element_type * element_ptr(T *p)
Definition: PackedArray.h:30
static iterated_type * begin(T *p)
Definition: PackedArray.h:29
typename Traits< T >::element_type element_type
Definition: PackedArray.h:27