/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License Version 2.0 with LLVM Exceptions * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * https://llvm.org/LICENSE.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include namespace { inline constexpr struct get_typeid_cpo { using type_erased_signature_t = unifex::type_index(const unifex::this_&) noexcept; template friend unifex::type_index tag_invoke(get_typeid_cpo, const T&) { return unifex::type_id(); } template auto operator()(const T& x) const noexcept -> unifex::tag_invoke_result_t { static_assert( std::is_same_v>); return tag_invoke(get_typeid_cpo{}, x); } } get_typeid{}; inline constexpr struct to_string_cpo { using type_erased_signature_t = std::string(const unifex::this_&) noexcept; template friend std::string tag_invoke(to_string_cpo, const T& x) { std::stringstream sout; sout << x; return sout.str(); } template auto operator()(const T& x) const noexcept -> unifex::tag_invoke_result_t { static_assert( std::is_same_v>); return tag_invoke(to_string_cpo{}, x); } } to_string{}; struct destructor { explicit destructor(bool& x) : ref_(x) {} ~destructor() { ref_ = true; } bool& ref_; }; #if !UNIFEX_NO_MEMORY_RESOURCE using namespace unifex::pmr; class counting_memory_resource : public memory_resource { public: explicit counting_memory_resource(memory_resource* r) noexcept : inner_(r) {} std::size_t total_allocated_bytes() const { return allocated_.load(); } private: void* do_allocate(std::size_t bytes, std::size_t alignment) override { void* p = inner_->allocate(bytes, alignment); allocated_ += bytes; return p; } void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override { allocated_ -= bytes; inner_->deallocate(p, bytes, alignment); } bool do_is_equal(const memory_resource& other) const noexcept override { return &other == this; } memory_resource* inner_; std::atomic allocated_ = 0; }; #endif } // anonymous namespace using A = unifex::any_unique_t; using B = unifex::any_unique_t<>; static_assert(unifex::movable); TEST(AnyUniqueTest, WithTypeid) { const ::A a = std::string{"hello"}; auto id = get_typeid(a); EXPECT_EQ(id, unifex::type_id()); } TEST(AnyUniqueTest, WithoutTypeid) { const ::B b = std::string{"hello"}; auto id = get_typeid(b); EXPECT_EQ(id, unifex::type_id()); } TEST(AnyUniqueTest, TestDestructor) { bool hasDestructorRun = false; { const A a{std::in_place_type, hasDestructorRun}; EXPECT_EQ(get_typeid(a), unifex::type_id()); EXPECT_FALSE(hasDestructorRun); } EXPECT_TRUE(hasDestructorRun); } using Aref = unifex::any_ref_t; using Bref = unifex::any_ref_t<>; TEST(AnyRefTest, WithTypeid) { std::string hello{"hello"}; const ::Aref a = hello; auto id = get_typeid(a); EXPECT_EQ(id, unifex::type_id()); std::string str = to_string(a); EXPECT_EQ(str, "hello"); } TEST(AnyRefTest, WithoutTypeid) { std::string hello{"hello"}; const ::Bref b = hello; auto id = get_typeid(b); EXPECT_EQ(id, unifex::type_id()); } #if !UNIFEX_NO_MEMORY_RESOURCE TEST(AnyUniqueTest, WithCustomAllocator) { counting_memory_resource res{new_delete_resource()}; polymorphic_allocator alloc{&res}; { A a1{std::string("hello"), alloc}; EXPECT_GE(res.total_allocated_bytes(), sizeof(std::string)); A a2{std::allocator_arg, alloc, std::in_place_type, "hello"}; EXPECT_GE(res.total_allocated_bytes(), 2 * sizeof(std::string)); } EXPECT_EQ(res.total_allocated_bytes(), 0); } #endif