diff --git a/inc/mkn/kul/alloc.hpp b/inc/mkn/kul/alloc.hpp index 10b89e4..e9be656 100644 --- a/inc/mkn/kul/alloc.hpp +++ b/inc/mkn/kul/alloc.hpp @@ -35,6 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include namespace mkn::kul { @@ -81,6 +82,55 @@ class AlignedAllocator { } }; +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 { + if (n == 0) return nullptr; + void* p = ::operator new(n * sizeof(T)); + if (!p) throw std::bad_alloc(); + return static_cast(p); + } + + 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 { + public: + template + struct rebind { + using other = NonConstructingAllocator; + }; + + template + void construct(U* /*ptr*/, Args&&... /*args*/) {} // nothing + template + void construct(U* /*ptr*/) noexcept(std::is_nothrow_default_constructible::value) {} +}; + } // namespace mkn::kul #endif /*_MKN_KUL_ALLOC_HPP_*/ diff --git a/inc/mkn/kul/vector.hpp b/inc/mkn/kul/vector.hpp new file mode 100644 index 0000000..21cc2fe --- /dev/null +++ b/inc/mkn/kul/vector.hpp @@ -0,0 +1,63 @@ +/** +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_VECTOR_HPP_ +#define _MKN_KUL_VECTOR_HPP_ + +#include "mkn/kul/alloc.hpp" + +#include + +namespace mkn::kul { + +template // A ignored but there for std::vector interop +using NonConstructingVector = std::vector>; + +template +std::vector>& as_super(std::vector>& v) { + return *reinterpret_cast>*>(&v); +} + +} // namespace mkn::kul + +template +bool operator==(std::vector const& v0, mkn::kul::NonConstructingVector 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==(mkn::kul::NonConstructingVector const& v0, std::vector const& 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 new file mode 100644 index 0000000..39a7e1a --- /dev/null +++ b/test/test/no_construct_alloc.cpp @@ -0,0 +1,85 @@ + + +#include "test_common.hpp" + +#include "mkn/kul/dbg.hpp" +#include "mkn/kul/alloc.hpp" +#include "mkn/kul/vector.hpp" + +#include +#include +#include + +template +struct S { + S() { + for (std::uint8_t i = 0; i < size; i++) vars[i] = i; + } + + bool operator==(S const& that) const { + for (std::size_t i = 0; i < size; i++) + if (vars[i] != that.vars[i]) return false; + + return true; + } + + std::array vars; +}; + +template +auto copy_construct(V const& v) { + KUL_DBG_FUNC_ENTER; + V out{v}; + return out; +} + +template +auto copy_operator_equal(V const& v) { + KUL_DBG_FUNC_ENTER; + V out; + out.reserve(v.capacity()); + out = v; + return out; +} + +template +auto copy_manual(V const& v) { + KUL_DBG_FUNC_ENTER; + V out; + out.reserve(v.capacity()); + out.resize(v.size()); + std::copy(v.begin(), v.end(), out.begin()); + return out; +} + +template +auto make_vector(std::size_t const& size) { + KUL_DBG_FUNC_ENTER; + return V{size}; +} +template +auto make_vector_from(V1 const& v1) { + KUL_DBG_FUNC_ENTER; + V0 v(v1.size()); + std::copy(v1.begin(), v1.end(), v.begin()); + return v; +} + +template +void do_compare() { + constexpr static std::size_t N = 2e6; + auto const std_vec = make_vector>(N); + auto const no_construct_vec = make_vector_from>(std_vec); + if (std_vec != no_construct_vec) throw std::runtime_error("FAIL"); + auto const v0 = copy_construct(std_vec); + auto const v1 = copy_construct(no_construct_vec); + auto const v2 = copy_manual(std_vec); + auto const v3 = copy_manual(no_construct_vec); + + if (v0 != std_vec) throw std::runtime_error("FAIL 0"); + if (v0 == v1) throw std::runtime_error("FAIL 1"); // :( + if (v0 != v2) throw std::runtime_error("FAIL 2"); + if (v0 != v3) throw std::runtime_error("FAIL 3"); +} + +TEST(NoConstructAllocator, copies) { do_compare>(); }