2025-01-12 20:42:42 +08:00

127 lines
3.5 KiB
C++

/*
* 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 <unifex/any_unique.hpp>
#include <unifex/type_traits.hpp>
#include <unifex/memory_resource.hpp>
#include <unifex/type_index.hpp>
#include <string>
#include <typeindex>
#include <atomic>
template <typename T>
using is_type_index = std::is_same<std::type_index, T>;
inline constexpr struct get_typeid_cpo {
using type_erased_signature_t =
unifex::type_index(const unifex::this_&) noexcept;
template <typename T>
friend unifex::type_index tag_invoke(get_typeid_cpo, const T&) {
return unifex::type_id<T>();
}
template <typename T>
auto operator()(const T& x) const noexcept ->
unifex::tag_invoke_result_t<get_typeid_cpo, const T&> {
static_assert(
std::is_same_v<
unifex::type_index,
unifex::tag_invoke_result_t<get_typeid_cpo, const T&>>);
return tag_invoke(get_typeid_cpo{}, x);
}
} get_typeid;
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<std::size_t> allocated_ = 0;
};
#endif
int main() {
using A = unifex::any_unique_t<get_typeid>;
using B = unifex::any_unique_t<>;
{
const A a = std::string{"hello"};
[[maybe_unused]] auto id = get_typeid(a);
UNIFEX_ASSERT(id == unifex::type_id<std::string>());
}
{
const B b = std::string{"hello"};
[[maybe_unused]] auto id = get_typeid(b);
UNIFEX_ASSERT(id == unifex::type_id<B>());
}
{
bool hasDestructorRun = false;
{
const A a{std::in_place_type<destructor>, hasDestructorRun};
UNIFEX_ASSERT(get_typeid(a) == unifex::type_id<destructor>());
UNIFEX_ASSERT(!hasDestructorRun);
}
UNIFEX_ASSERT(hasDestructorRun);
}
#if !UNIFEX_NO_MEMORY_RESOURCE
{
counting_memory_resource res{new_delete_resource()};
polymorphic_allocator<char> alloc{&res};
{
A a1{std::string("hello"), alloc};
UNIFEX_ASSERT(res.total_allocated_bytes() >= sizeof(std::string));
A a2{std::allocator_arg, alloc, std::in_place_type<std::string>, "hello"};
UNIFEX_ASSERT(res.total_allocated_bytes() >= 2 * sizeof(std::string));
}
UNIFEX_ASSERT(res.total_allocated_bytes() == 0);
}
#endif
return 0;
}