NumericAL
A header-only C++20 lexer built on REAL
Loading...
Searching...
No Matches
buffer.hpp
Go to the documentation of this file.
1
6#ifndef NUMERICAL_BUFFER_HPP
7#define NUMERICAL_BUFFER_HPP
8
9#include <algorithm>
10#include <atomic>
11#include <cstddef>
12#include <cstring>
13#include <new>
14#include <memory>
15#include <type_traits>
16#include <utility>
17#include <vector>
18
19#if defined(__linux__)
20# include <sys/mman.h>
21#endif
22
23namespace numerical {
24
25 namespace detail {
26
34 template <typename T>
35 struct default_init_allocator : std::allocator<T>
36 {
37 using value_type = T;
38
40 template <typename U>
41 struct rebind
42 {
44 };
45
47
50 // NOLINTNEXTLINE(hicpp-explicit-conversions,google-explicit-constructor): the containers rebind an allocator by this conversion
53
55#if defined(__linux__)
57 static constexpr std::size_t huge_page {std::size_t {1} << 21U};
58
65 static constexpr std::size_t huge_least {std::size_t {1} << 24U};
66
70 static constexpr std::size_t huge_colours {64};
71
74 [[nodiscard]] static constexpr bool on_huge_pages(std::size_t n) noexcept
75 {
76 return n <= (static_cast<std::size_t>(-1) - huge_page) / sizeof(T) && n * sizeof(T) >= huge_least;
77 }
78
81 [[nodiscard]] T* allocate(std::size_t n)
82 {
83 if (!on_huge_pages(n)) {
84 return std::allocator<T>::allocate(n);
85 }
86 static std::atomic<std::size_t> colour {0};
87 const std::size_t offset {((colour.fetch_add(1) % huge_colours) * 4096) + alignof(std::max_align_t) * 4};
88 const std::size_t bytes {((offset + (n * sizeof(T))) + huge_page - 1) / huge_page * huge_page};
89 auto* const start {static_cast<std::byte*>(::operator new(bytes, std::align_val_t {huge_page}))};
90 (void)madvise(start, bytes, MADV_HUGEPAGE); // a hint: the pages stay 4 KiB where the system declines
91 std::byte* const data {start + offset};
92 std::memcpy(data - sizeof(std::size_t), &offset, sizeof(std::size_t)); // the start, as the data's distance from it
93 return reinterpret_cast<T*>(data); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): storage for T, aligned past max_align_t
94 }
95
97 void deallocate(T * at,
98 std::size_t n) noexcept
99 {
100 if (!on_huge_pages(n)) {
101 std::allocator<T>::deallocate(at, n);
102 return;
103 }
104 deallocate_huge(at);
105 }
106
112 [[gnu::noinline]] static void deallocate_huge(T* at) noexcept
113 {
114 auto* const data {reinterpret_cast<std::byte*>(at)}; // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast): the storage's bytes
115 std::size_t offset {};
116 std::memcpy(&offset, data - sizeof(std::size_t), sizeof(std::size_t));
117 ::operator delete(data - offset,
118 std::align_val_t {huge_page});
119 }
120
121#endif
122
123 template <typename U>
124 void construct(U* at) noexcept(std::is_nothrow_default_constructible_v<U>)
125 {
126 ::new (static_cast<void*>(at)) U;
127 }
128
130 template <typename U,
131 typename ... Args>
132 void construct(U * at,
133 Args&&... args)
134 {
135 ::new (static_cast<void*>(at)) U(std::forward<Args>(args)...);
136 }
137 };
138
143 template <typename T>
145 const std::vector<T>& other)
146 {
147 return std::equal(buffer.begin(), buffer.end(), other.begin(), other.end());
148 }
149 } // namespace detail
150
156 template <typename T>
157 using buffer = std::vector<T, detail::default_init_allocator<T>>;
158} // namespace numerical
159
160#endif // NUMERICAL_BUFFER_HPP
bool operator==(const std::vector< T, default_init_allocator< T > > &buffer, const std::vector< T > &other)
Element-wise equality of a numerical::buffer and a std::vector, found by argument-dependent lookup th...
Definition buffer.hpp:144
The NumericAL public API.
Definition amx.hpp:44
std::vector< T, detail::default_init_allocator< T > > buffer
The storage of vector, matrix and tensor, namely a std::vector whose buffer<T>(n) and resize(n) leave...
Definition buffer.hpp:157
The allocator of another element type, as std::allocator_traits rebinds it.
Definition buffer.hpp:42
The allocator of numerical::buffer. An element constructed with no value is default-initialised,...
Definition buffer.hpp:36
void construct(U *at, Args &&... args)
Constructs the element at at from args.
Definition buffer.hpp:132
void construct(U *at) noexcept(std::is_nothrow_default_constructible_v< U >)
Default-initialises the element at at.
Definition buffer.hpp:124