diff --git a/inc/mkn/kul/alloc.hpp b/inc/mkn/kul/alloc.hpp index 239f7ca..89cc196 100644 --- a/inc/mkn/kul/alloc.hpp +++ b/inc/mkn/kul/alloc.hpp @@ -31,182 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef _MKN_KUL_ALLOC_HPP_ #define _MKN_KUL_ALLOC_HPP_ -#include -#include -#include -#include -#include - -#include -#include // posix_memalign -#include // madvise - -namespace mkn::kul { - -template -class AlignedAllocator { - using This = AlignedAllocator; - - public: - using pointer = T*; - using reference = T&; - using value_type = T; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - - template - struct rebind { - using other = AlignedAllocator; - }; - - T* allocate(std::size_t const n) const { - if (n == 0) return nullptr; - - auto size = n * sizeof(T); - std::uint32_t diff = size % alignment; - if (diff > 0) diff = alignment - diff; - - void* p = std::aligned_alloc(alignment, size + diff); - if (!p) throw std::bad_alloc(); - - return static_cast(p); - } - - void deallocate(T* const p) noexcept { - if (p) std::free(p); - } - void deallocate(T* const p, std::size_t /*n*/) noexcept { // needed from std:: - deallocate(p); - } - - bool operator!=(This const& that) const { return !(*this == that); } - - bool operator==(This const& /*that*/) const { - return true; // stateless - } -}; - -template -class Allocator { - using This = Allocator; - - public: - using pointer = T*; - using reference = T&; - using value_type = T; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - - template - struct rebind { - using other = Allocator; - }; - - T* allocate(std::size_t const n) const { return static_cast(::operator new(n * sizeof(T))); } - - void deallocate(T* const p) noexcept { - if (p) ::operator delete(p); - } - void deallocate(T* const p, std::size_t /*n*/) noexcept { // needed from std:: - if (p) ::operator delete(p); - } - bool operator!=(This const& that) const { return !(*this == that); } - bool operator==(This const& /*that*/) const { - return true; // stateless - } -}; - -template -class NonConstructingAllocator : public Allocator { - using This = NonConstructingAllocator; - - public: - template - struct rebind { - using other = NonConstructingAllocator; - }; - - T* allocate(std::size_t const n) const { - // if (n == 0) return nullptr; - return static_cast(malloc(n * sizeof(T))); - } - - template - void construct(U* /*ptr*/, Args&&... /*args*/) {} // nothing - template - void construct(U* /*ptr*/) noexcept(std::is_nothrow_default_constructible::value) {} - - bool operator!=(This const& that) const { return !(*this == that); } - bool operator==(This const& /*that*/) const { - return true; // stateless - } -}; - -template -class HugePageAllocator : public Allocator { - using This = HugePageAllocator; - - public: - template - struct rebind { - using other = HugePageAllocator; - }; - - HugePageAllocator() = default; - template - constexpr HugePageAllocator(HugePageAllocator const&) noexcept {} - - T* allocate(std::size_t n) { - if (n > std::numeric_limits::max() / sizeof(T)) throw std::bad_alloc(); - void* p = nullptr; - posix_memalign(&p, huge_page_size, n * sizeof(T)); - madvise(p, n * sizeof(T), MADV_HUGEPAGE); - if (p == nullptr) throw std::bad_alloc(); - return static_cast(p); - } - void deallocate(T* p, std::size_t n) { std::free(p); } - bool operator!=(This const& that) const { return !(*this == that); } - bool operator==(This const& /*that*/) const { - return true; // stateless - } -}; - -template -class NonConstructingHugePageAllocator : public NonConstructingAllocator { - using This = NonConstructingHugePageAllocator; - - public: - template - struct rebind { - using other = NonConstructingHugePageAllocator; - }; - - NonConstructingHugePageAllocator() = default; - template - constexpr NonConstructingHugePageAllocator(NonConstructingHugePageAllocator const&) noexcept {} - - T* allocate(std::size_t n) { - if (n > std::numeric_limits::max() / sizeof(T)) throw std::bad_alloc(); - void* p = nullptr; - posix_memalign(&p, huge_page_size, n * sizeof(T)); - madvise(p, n * sizeof(T), MADV_HUGEPAGE); - if (p == nullptr) throw std::bad_alloc(); - return static_cast(p); - } - - void deallocate(T* p, std::size_t n) { std::free(p); } - - template - void construct(U* /*ptr*/, Args&&... /*args*/) {} // nothing - template - void construct(U* /*ptr*/) noexcept(std::is_nothrow_default_constructible::value) {} - - bool operator!=(This const& that) const { return !(*this == that); } - bool operator==(This const& /*that*/) const { - return true; // stateless - } -}; - -} // namespace mkn::kul +#include "mkn/kul/alloc/base.hpp" +#include "mkn/kul/alloc/huge.hpp" // active if available #endif /*_MKN_KUL_ALLOC_HPP_*/ diff --git a/inc/mkn/kul/alloc/base.hpp b/inc/mkn/kul/alloc/base.hpp new file mode 100644 index 0000000..3f3c8dc --- /dev/null +++ b/inc/mkn/kul/alloc/base.hpp @@ -0,0 +1,146 @@ +/** +Copyright (c) 2022, Philip Deegan. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Philip Deegan nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _MKN_KUL_ALLOC_BASE_HPP_ +#define _MKN_KUL_ALLOC_BASE_HPP_ + +#include +#include +#include +#include +#include + +namespace mkn::kul { + +template +class Allocator { + using This = Allocator; + + public: + using pointer = T*; + using reference = T&; + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + template + struct rebind { + using other = Allocator; + }; + + T* allocate(std::size_t const n) const { return static_cast(::operator new(n * sizeof(T))); } + + void deallocate(T* const p) noexcept { + if (p) ::operator delete(p); + } + void deallocate(T* const p, std::size_t /*n*/) noexcept { // needed from std:: + if (p) ::operator delete(p); + } + bool operator!=(This const& that) const { return !(*this == that); } + bool operator==(This const& /*that*/) const { + return true; // stateless + } +}; + +template +class AlignedAllocator : public Allocator { + using This = AlignedAllocator; + + public: + using pointer = T*; + using reference = T&; + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + template + struct rebind { + using other = AlignedAllocator; + }; + + T* allocate(std::size_t const n) const { + if (n == 0) return nullptr; + + auto size = n * sizeof(T); + std::uint32_t diff = size % alignment; + if (diff > 0) diff = alignment - diff; + + void* p = std::aligned_alloc(alignment, size + diff); + if (!p) throw std::bad_alloc(); + + return static_cast(p); + } + + void deallocate(T* const p) noexcept { + if (p) std::free(p); + } + void deallocate(T* const p, std::size_t /*n*/) noexcept { // needed from std:: + deallocate(p); + } + + bool operator!=(This const& that) const { return !(*this == that); } + + bool operator==(This const& /*that*/) const { + return true; // stateless + } +}; + +template +class NonConstructingAllocator : public Allocator { + using This = NonConstructingAllocator; + + public: + template + struct rebind { + using other = NonConstructingAllocator; + }; + + T* allocate(std::size_t const n) const { + // if (n == 0) return nullptr; + return static_cast(malloc(n * sizeof(T))); + } + + template + void construct(U* ptr, Args&&... args) { + ::new ((void*)ptr) U(std::forward(args)...); + } + + template + void construct(U* /*ptr*/) noexcept(std::is_nothrow_default_constructible::value) {} + + bool operator!=(This const& that) const { return !(*this == that); } + bool operator==(This const& /*that*/) const { + return true; // stateless + } +}; + +} // namespace mkn::kul + +#endif /*_MKN_KUL_ALLOC_BASE_HPP_*/ diff --git a/inc/mkn/kul/alloc/huge.hpp b/inc/mkn/kul/alloc/huge.hpp new file mode 100644 index 0000000..08e2bda --- /dev/null +++ b/inc/mkn/kul/alloc/huge.hpp @@ -0,0 +1,120 @@ +/** +Copyright (c) 2022, Philip Deegan. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Philip Deegan nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef _MKN_KUL_ALLOC_HUGE_HPP_ +#define _MKN_KUL_ALLOC_HUGE_HPP_ + +#if __has_include() + +#include "mkn/kul/alloc/base.hpp" + +#include +#include +#include +#include + +#include +#include // posix_memalign +#include // madvise + +namespace mkn::kul { + +template +class HugePageAllocator : public Allocator { + using This = HugePageAllocator; + + public: + template + struct rebind { + using other = HugePageAllocator; + }; + + HugePageAllocator() = default; + template + constexpr HugePageAllocator(HugePageAllocator const&) noexcept {} + + T* allocate(std::size_t n) { + if (n > std::numeric_limits::max() / sizeof(T)) throw std::bad_alloc(); + void* p = nullptr; + posix_memalign(&p, huge_page_size, n * sizeof(T)); + madvise(p, n * sizeof(T), MADV_HUGEPAGE); + if (p == nullptr) throw std::bad_alloc(); + return static_cast(p); + } + void deallocate(T* p, std::size_t n) { std::free(p); } + bool operator!=(This const& that) const { return !(*this == that); } + bool operator==(This const& /*that*/) const { + return true; // stateless + } +}; + +template +class NonConstructingHugePageAllocator : public NonConstructingAllocator { + using This = NonConstructingHugePageAllocator; + + public: + template + struct rebind { + using other = NonConstructingHugePageAllocator; + }; + + NonConstructingHugePageAllocator() = default; + template + constexpr NonConstructingHugePageAllocator(NonConstructingHugePageAllocator const&) noexcept {} + + T* allocate(std::size_t n) { + if (n > std::numeric_limits::max() / sizeof(T)) throw std::bad_alloc(); + void* p = nullptr; + posix_memalign(&p, huge_page_size, n * sizeof(T)); + madvise(p, n * sizeof(T), MADV_HUGEPAGE); + if (p == nullptr) throw std::bad_alloc(); + return static_cast(p); + } + + void deallocate(T* p, std::size_t n) { std::free(p); } + + template + void construct(U* ptr, Args&&... args) { + ::new ((void*)ptr) U(std::forward(args)...); + } + + template + void construct(U* /*ptr*/) noexcept(std::is_nothrow_default_constructible::value) {} + + bool operator!=(This const& that) const { return !(*this == that); } + bool operator==(This const& /*that*/) const { + return true; // stateless + } +}; + +} // namespace mkn::kul + +#endif // __has_include() +#endif /*_MKN_KUL_ALLOC_HUGE_HPP_*/ diff --git a/inc/mkn/kul/vector.hpp b/inc/mkn/kul/vector.hpp index c1f81c3..d4013f4 100644 --- a/inc/mkn/kul/vector.hpp +++ b/inc/mkn/kul/vector.hpp @@ -71,19 +71,23 @@ bool operator==(std::vector const& v0, std::vector const& v1) { return true; } -template -bool operator==(mkn::kul::Vector const& v0, std::vector const& v1) { - return v1 == v0; +template , A1>, bool> = 0> +bool operator!=(std::vector const& v0, std::vector const& v1) { + if (v0.size() != v1.size()) return false; + for (std::size_t i = 0; i < v0.size(); i++) + if (v0[i] == v1[i]) return false; + return true; } template -bool operator!=(std::vector const& v0, mkn::kul::Vector const& v1) { - return !(v0 == v1); +bool operator==(mkn::kul::Vector const& v0, std::vector const& v1) { + return v1 == v0; } template bool operator!=(mkn::kul::Vector const& v0, std::vector const& v1) { - return !(v0 == v1); + return v1 != v0; } #endif /*_MKN_KUL_VECTOR_HPP_*/ diff --git a/test/test/no_construct_alloc.cpp b/test/test/no_construct_alloc.cpp index 62ff2e4..98a7b20 100644 --- a/test/test/no_construct_alloc.cpp +++ b/test/test/no_construct_alloc.cpp @@ -123,11 +123,14 @@ void do_compare() { using namespace mkn::kul; wash.template operator()>("std::vector"); wash.template operator()>("NonConstructingVector"); + +#if __has_include() wash.template operator()>("HugePageVector"); wash.template operator()>("NonConstructingHugePageVector"); +#endif // __has_include() } -TEST(NoConstructAllocator, copies) { do_compare(); } +TEST(NoConstructAllocator, copies) { do_compare>(); } // int main(int argc, char* argv[]) { // ::testing::InitGoogleTest(&argc, argv);