From e8bf8610833020367c7a0a2d9cedb62fabb48d15 Mon Sep 17 00:00:00 2001 From: PhilipDeegan Date: Sun, 8 Dec 2024 16:06:38 +0100 Subject: [PATCH] ++ --- .github/workflows/build_nix.yml | 6 +- .github/workflows/build_osx.yml | 6 +- .github/workflows/build_win.yml | 6 +- README.md | 2 +- inc/mkn/kul/alloc.hpp | 180 +------------------------------ inc/mkn/kul/alloc/aligned.hpp | 92 ++++++++++++++++ inc/mkn/kul/alloc/base.hpp | 103 ++++++++++++++++++ inc/mkn/kul/alloc/huge.hpp | 125 +++++++++++++++++++++ inc/mkn/kul/vector.hpp | 19 ++-- mkn.yaml | 2 +- test/test/no_construct_alloc.cpp | 5 +- 11 files changed, 356 insertions(+), 190 deletions(-) create mode 100644 inc/mkn/kul/alloc/aligned.hpp create mode 100644 inc/mkn/kul/alloc/base.hpp create mode 100644 inc/mkn/kul/alloc/huge.hpp diff --git a/.github/workflows/build_nix.yml b/.github/workflows/build_nix.yml index 982c9b0..9d33ef6 100644 --- a/.github/workflows/build_nix.yml +++ b/.github/workflows/build_nix.yml @@ -1,5 +1,9 @@ name: ubuntu-latest +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + on: push: branches: [ master ] @@ -16,4 +20,4 @@ jobs: run: | curl -Lo mkn https://github.com/mkn/mkn/releases/download/latest/mkn_nix chmod +x mkn - KLOG=3 ./mkn clean build run -dtOp test -a "-std=c++17 -fPIC" + KLOG=3 ./mkn clean build run -dtOp test -a "-std=c++20 -fPIC" diff --git a/.github/workflows/build_osx.yml b/.github/workflows/build_osx.yml index ae6fc96..693c394 100644 --- a/.github/workflows/build_osx.yml +++ b/.github/workflows/build_osx.yml @@ -1,5 +1,9 @@ name: macos-latest +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + on: push: branches: [ master ] @@ -16,4 +20,4 @@ jobs: run: | curl -Lo mkn https://github.com/mkn/mkn/releases/download/latest/mkn_arm_osx chmod +x mkn - KLOG=3 ./mkn clean build run -dtOp test -a "-std=c++17 -fPIC" + KLOG=3 ./mkn clean build run -dtOp test -a "-std=c++20 -fPIC" diff --git a/.github/workflows/build_win.yml b/.github/workflows/build_win.yml index 67bc061..6b025a1 100644 --- a/.github/workflows/build_win.yml +++ b/.github/workflows/build_win.yml @@ -1,5 +1,9 @@ name: windows-latest +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + on: push: branches: [ master ] @@ -23,4 +27,4 @@ jobs: run: | # /bin/link interferes with cl/link.exe bash -c "rm /bin/link" bash -c "curl -Lo mkn.exe https://github.com/mkn/mkn/releases/download/latest/mkn.exe" - bash -c 'KLOG=3 ./mkn clean build run -dtKOp test -a "-EHsc -std:c++17"' + bash -c 'KLOG=3 ./mkn clean build run -dtKOp test -a "-EHsc -std:c++20"' diff --git a/README.md b/README.md index 1fd50ee..aa48d22 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # mkn.kul -**Cross platform C++ wrapper for threading/process management/io/logging/signal handling and stack walking.** +**Cross platform C++20 wrapper for threading/process management/io/logging/signal handling and stack walking.** Supported Architectures/Operating Systems: diff --git a/inc/mkn/kul/alloc.hpp b/inc/mkn/kul/alloc.hpp index 239f7ca..2ab3a89 100644 --- a/inc/mkn/kul/alloc.hpp +++ b/inc/mkn/kul/alloc.hpp @@ -31,182 +31,8 @@ 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/aligned.hpp" // active if available +#include "mkn/kul/alloc/huge.hpp" // active if available #endif /*_MKN_KUL_ALLOC_HPP_*/ diff --git a/inc/mkn/kul/alloc/aligned.hpp b/inc/mkn/kul/alloc/aligned.hpp new file mode 100644 index 0000000..3116a9a --- /dev/null +++ b/inc/mkn/kul/alloc/aligned.hpp @@ -0,0 +1,92 @@ +/** +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_ALIGNED_HPP_ +#define _MKN_KUL_ALLOC_ALIGNED_HPP_ + +#if __has_include() + +#include "mkn/kul/alloc/base.hpp" + +#include +#include +#include +#include + +namespace mkn::kul { + +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 + } +}; + +} // namespace mkn::kul + +#endif // __has_include() + +#endif /*_MKN_KUL_ALLOC_ALIGNED_HPP_*/ diff --git a/inc/mkn/kul/alloc/base.hpp b/inc/mkn/kul/alloc/base.hpp new file mode 100644 index 0000000..643a718 --- /dev/null +++ b/inc/mkn/kul/alloc/base.hpp @@ -0,0 +1,103 @@ +/** +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 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..c774e26 --- /dev/null +++ b/inc/mkn/kul/alloc/huge.hpp @@ -0,0 +1,125 @@ +/** +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)); +#ifdef MADV_HUGEPAGE + madvise(p, n * sizeof(T), MADV_HUGEPAGE); +#endif // 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)); +#ifdef MADV_HUGEPAGE + madvise(p, n * sizeof(T), MADV_HUGEPAGE); +#endif // 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..c7288be 100644 --- a/inc/mkn/kul/vector.hpp +++ b/inc/mkn/kul/vector.hpp @@ -31,7 +31,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef _MKN_KUL_VECTOR_HPP_ #define _MKN_KUL_VECTOR_HPP_ -#include "alloc.hpp" #include "mkn/kul/alloc.hpp" #include @@ -45,11 +44,13 @@ using Vector = std::vector>; template // A ignored but there for std::vector interop using NonConstructingVector = std::vector>; +#if __has_include() template using NonConstructingHugePageVector = std::vector>; template using HugePageVector = std::vector>; +#endif // __has_include() template std::vector>& as_super(std::vector>& v) { @@ -71,19 +72,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/mkn.yaml b/mkn.yaml index 56594de..ac4472b 100644 --- a/mkn.yaml +++ b/mkn.yaml @@ -2,7 +2,7 @@ # mkn.kul - Kommon Usage Library # Cross platform wrapper for systems operations / IO / threads / processes -# Default profile "lib" is header only, use "-compiled" for library options +# Default profile "lib" is header only, use "*-compiled" for library options # name: mkn.kul 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);