1+ #pragma once
2+
3+ #include " ../utility/assert.h"
4+ #include " ../utility/empty_base.h"
5+ #include " ../utility/meta.h"
6+ #include " ../utility/source_location.h"
7+ #include " debug_fwd.h"
8+ #include " type_allocator.h"
9+
10+ #include < cstring>
11+ #include < memory>
12+ #include < ostream>
13+ #include < type_traits>
14+
15+ namespace ktl
16+ {
17+ template <typename Alloc, typename Container>
18+ class debug
19+ {
20+ private:
21+ static_assert (detail::has_no_value_type_v<Alloc>, " Building on top of typed allocators is not allowed. Use allocators without a type" );
22+
23+ public:
24+ typedef typename detail::get_size_type_t <Alloc> size_type;
25+
26+ public:
27+ /* *
28+ * @brief Construct the allocator with a reference to a container object
29+ * @param container The container to use for populating statistics
30+ */
31+ explicit debug (Container& container)
32+ noexcept (std::is_nothrow_default_constructible_v<Alloc>) :
33+ m_Container(container),
34+ m_Alloc() {}
35+
36+ /* *
37+ * @brief Constructor for forwarding any arguments to the underlying allocator
38+ */
39+ template <typename ... Args,
40+ typename = std::enable_if_t <
41+ std::is_constructible_v<Alloc, Args...>>>
42+ explicit debug (Container& container, Args&&... args)
43+ noexcept (std::is_nothrow_constructible_v<Alloc, Args...>) :
44+ m_Container(container),
45+ m_Alloc(std::forward<Args>(args)...) {}
46+
47+ debug (const debug&) = default ;
48+
49+ debug (debug&&) = default ;
50+
51+ debug& operator =(const debug&) = default ;
52+
53+ debug& operator =(debug&&) = default ;
54+
55+ bool operator ==(const debug& rhs) const
56+ noexcept (detail::has_nothrow_equal_v<Alloc>)
57+ {
58+ return m_Alloc == rhs.m_Alloc ;
59+ }
60+
61+ bool operator !=(const debug& rhs) const
62+ noexcept (detail::has_nothrow_not_equal_v<Alloc>)
63+ {
64+ return m_Alloc != rhs.m_Alloc ;
65+ }
66+
67+ #pragma region Allocation
68+ /* *
69+ * @brief Attempts to allocate a chunk of memory defined by @p n
70+ * @param n The amount of bytes to allocate memory for
71+ * @return A location in memory that is at least @p n bytes big or nullptr if it could not be allocated
72+ */
73+ void * allocate (size_type n, const source_location& source = KTL_SOURCE())
74+ noexcept (detail::has_nothrow_allocate_v<Alloc>)
75+ {
76+ #ifdef KTL_SOURCE_LOCATION
77+ m_Container.push_back ({ source.file_name (), source.line (), n });
78+ #endif
79+
80+ return detail::allocate (m_Alloc, n, source);
81+ }
82+
83+ /* *
84+ * @brief Attempts to deallocate the memory at location @p p
85+ * @param p The location in memory to deallocate
86+ * @param n The size that was initially allocated
87+ */
88+ void deallocate (void * p, size_type n)
89+ noexcept (detail::has_nothrow_deallocate_v<Alloc>)
90+ {
91+ m_Alloc.deallocate (p, n);
92+ }
93+ #pragma endregion
94+
95+ #pragma region Construction
96+ /* *
97+ * @brief Constructs an object of T with the given @p ...args at the given location
98+ * @note Only defined if the underlying allocator defines it
99+ * @tparam ...Args The types of the arguments
100+ * @param p The location of the object in memory
101+ * @param ...args A range of arguments to use to construct the object
102+ */
103+ template <typename T, typename ... Args>
104+ typename std::enable_if<detail::has_construct_v<Alloc, T*, Args...>, void >::type
105+ construct (T* p, Args&&... args)
106+ noexcept (detail::has_nothrow_construct_v<Alloc, T*, Args...>)
107+ {
108+ m_Alloc.construct (p, std::forward<Args>(args)...);
109+ }
110+
111+ /* *
112+ * @brief Destructs an object of T at the given location
113+ * @note Only defined if the underlying allocator defines it
114+ * @param p The location of the object in memory
115+ */
116+ template <typename T>
117+ typename std::enable_if<detail::has_destroy_v<Alloc, T*>, void >::type
118+ destroy (T* p)
119+ noexcept (detail::has_nothrow_destroy_v<Alloc, T*>)
120+ {
121+ m_Alloc.destroy (p);
122+ }
123+ #pragma endregion
124+
125+ #pragma region Utility
126+ /* *
127+ * @brief Returns the maximum size that an allocation can be
128+ * @note Only defined if the underlying allocator defines it
129+ * @return The maximum size an allocation may be
130+ */
131+ template <typename A = Alloc>
132+ typename std::enable_if<detail::has_max_size_v<A>, size_type>::type
133+ max_size () const
134+ noexcept (detail::has_nothrow_max_size_v<A>)
135+ {
136+ return m_Alloc.max_size ();
137+ }
138+
139+ /* *
140+ * @brief Returns whether or not the allocator owns the given location in memory
141+ * @note Only defined if the underlying allocator defines it
142+ * @param p The location of the object in memory
143+ * @return Whether the allocator owns @p p
144+ */
145+ template <typename A = Alloc>
146+ typename std::enable_if<detail::has_owns_v<A>, bool >::type
147+ owns (void * p) const
148+ noexcept (detail::has_nothrow_owns_v<A>)
149+ {
150+ return m_Alloc.owns (p);
151+ }
152+ #pragma endregion
153+
154+ /* *
155+ * @brief Returns a reference to the underlying allocator
156+ * @return The allocator
157+ */
158+ Alloc& get_allocator () noexcept
159+ {
160+ return m_Alloc;
161+ }
162+
163+ /* *
164+ * @brief Returns a const reference to the underlying allocator
165+ * @return The allocator
166+ */
167+ const Alloc& get_allocator () const noexcept
168+ {
169+ return m_Alloc;
170+ }
171+
172+ /* *
173+ * @brief Return a reference to the container that will be used to accumulate statistics
174+ * @return The stream
175+ */
176+ Container& get_container () noexcept
177+ {
178+ return m_Container;
179+ }
180+
181+ /* *
182+ * @brief Return a const reference to the container that will be used to accumulate statistics
183+ * @return The stream
184+ */
185+ const Container& get_container () const noexcept
186+ {
187+ return m_Container;
188+ }
189+
190+ private:
191+ Container& m_Container;
192+ KTL_EMPTY_BASE Alloc m_Alloc;
193+ };
194+ }
0 commit comments