/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#ifndef TRINITY_MEMORY_H
#define TRINITY_MEMORY_H
#include "CompilerDefs.h"
#include
#include
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-attributes"
#endif
namespace Trinity
{
namespace Impl
{
template
struct stateful_unique_ptr_deleter
{
using pointer = T;
explicit(false) stateful_unique_ptr_deleter(Del deleter) : _deleter(std::move(deleter)) { }
void operator()(pointer ptr) const { (void)_deleter(ptr); }
private:
Del _deleter;
};
template
struct stateless_unique_ptr_deleter
{
using pointer = T;
void operator()(pointer ptr) const
{
if constexpr (std::is_member_function_pointer_v)
(void)(ptr->*Del)();
else
(void)Del(ptr);
}
};
}
/**
* Convenience function to construct type aliases for std::unique_ptr stateful deleters (such as lambda with captures)
* @tparam Ptr Type of the pointer
* @tparam Del Type of object freeing function (deduced from argument)
* @param deleter Object deleter
*
* Example use
* @code
* void FreeV1(Resource*);
* void FreeV2(Resource*);
*
* using ResourceDeleter = decltype(Trinity::unique_ptr_deleter(&FreeV1));
*
* std::unique_ptr resource = Trinity::make_unique_ptr_with_deleter(GetResourceV1(), &FreeV1);
* // do stuff ...
* // ... later get new resource
* resource = Trinity::make_unique_ptr_with_deleter(GetResourceV2(), &FreeV2);
* @endcode
*/
template requires std::invocable && std::is_pointer_v
Impl::stateful_unique_ptr_deleter unique_ptr_deleter(Del deleter)
{
return Impl::stateful_unique_ptr_deleter(std::move(deleter));
}
/**
* Convenience function to construct type aliases for std::unique_ptr stateful deleters (such as lambda with captures)
*
* Main use is for forming struct/class members without the call to make_unique_ptr_with_deleter
* @tparam Ptr Type of the pointer
* @tparam Del The freeing function. This can be either a free function pointer that accepts T* as argument, pointer to a member function of T that accepts no arguments or a lambda with no captures
*
* Example use
* @code
* using FileDeleter = decltype(Trinity::unique_ptr_deleter());
*
* class Resource
* {
* std::unique_ptr File;
* };
* @endcode
*/
template requires std::invocable && std::is_pointer_v
Impl::stateless_unique_ptr_deleter unique_ptr_deleter()
{
return Impl::stateless_unique_ptr_deleter();
}
/**
* Utility function to construct a std::unique_ptr object with custom stateful deleter (such as lambda with captures)
* @tparam Ptr Type of the pointer
* @tparam T Type of the pointed-to object (defaults to std::remove_pointer_t)
* @tparam Del Type of object freeing function (deduced from second argument)
* @param ptr Raw pointer to owned object
* @param deleter Object deleter
*
* Example use
* @code
* class Resource
* {
* };
* class ResourceService
* {
* Resource* Create();
* void Destroy(Resource*);
* };
*
* ResourceService* service = GetResourceService();
*
* // Lambda that captures all required variables for destruction
* auto resource = Trinity::make_unique_ptr_with_deleter(service->Create(), [service](Resource* res){ service->Destroy(res); });
* @endcode
*/
template, typename Del> requires std::invocable && std::is_pointer_v
std::unique_ptr> make_unique_ptr_with_deleter(Ptr ptr, Del deleter)
{
return std::unique_ptr>(ptr, std::move(deleter));
}
/**
* Utility function to construct a std::unique_ptr object with custom stateless deleter (function pointer, captureless lambda)
* @tparam Del The freeing function. This can be either a free function pointer that accepts T* as argument, pointer to a member function of T that accepts no arguments or a lambda with no captures
* @tparam Ptr Type of the pointer
* @tparam T Type of the pointed-to object (defaults to std::remove_pointer_t)
* @param ptr Raw pointer to owned object
*
* Example uses
* @code
* void DestroyResource(Resource*);
* class Resource
* {
* void Destroy();
* };
*
* // Free function
* auto free = Trinity::make_unique_ptr_with_deleter<&DestroyResource>(new Resource());
*
* // Member function
* auto member = Trinity::make_unique_ptr_with_deleter<&Resource::Destroy>(new Resource());
*
* // Lambda
* auto lambda = Trinity::make_unique_ptr_with_deleter<[](Resource* res){ res->Destroy(); }>(new Resource());
* @endcode
*/
template> requires std::invocable && std::is_pointer_v
std::unique_ptr> make_unique_ptr_with_deleter(Ptr ptr)
{
return std::unique_ptr>(ptr);
}
}
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
#pragma GCC diagnostic pop
#endif
#endif // TRINITY_MEMORY_H