.. _program_listing_file_nvcv_types_include_nvcv_alloc_Allocator.hpp: Program Listing for File Allocator.hpp ====================================== |exhale_lsh| :ref:`Return to documentation for file ` (``nvcv_types/include/nvcv/alloc/Allocator.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /* * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. */ #ifndef NVCV_ALLOC_ALLOCATOR_HPP #define NVCV_ALLOC_ALLOCATOR_HPP #include "../CoreResource.hpp" #include "../detail/Callback.hpp" #include "../detail/CompilerUtils.h" #include "../detail/TypeTraits.hpp" #include "Allocator.h" #include #include #include #include namespace nvcv { // Helper class to explicitly assign // address alignments. class MemAlignment { public: MemAlignment() = default; int32_t baseAddr() const { return m_baseAddrAlignment; } int32_t rowAddr() const { return m_rowAddrAlignment; } MemAlignment &baseAddr(int32_t alignment) { m_baseAddrAlignment = alignment; return *this; } MemAlignment &rowAddr(int32_t alignment) { m_rowAddrAlignment = alignment; return *this; } private: int32_t m_baseAddrAlignment = 0; int32_t m_rowAddrAlignment = 0; }; class ResourceAllocator { public: ResourceAllocator() = default; explicit ResourceAllocator(const NVCVResourceAllocator &alloc) : m_data(alloc) { } const NVCVResourceAllocator &cdata() const & { return m_data; } NVCVResourceAllocator cdata() && { return m_data; } template Derived cast() const { static_assert(std::is_base_of::value, "The requested type does not inherit from ResourceAllocator"); static_assert(std::is_constructible::value, "The requested type must be constructible from NVCVResourceAllocator"); return Derived(m_data); } static constexpr bool IsCompatibleKind(NVCVResourceType) { return true; } protected: NVCVResourceAllocator &data() & { return m_data; } NVCVResourceAllocator m_data{}; }; class MemAllocator : public ResourceAllocator { public: using ResourceAllocator::ResourceAllocator; static constexpr int DEFAULT_ALIGN = alignof(std::max_align_t); void *alloc(int64_t size, int32_t align = DEFAULT_ALIGN) { return m_data.res.mem.fnAlloc(m_data.ctx, size, align); } void free(void *ptr, int64_t size, int32_t align = DEFAULT_ALIGN) noexcept { m_data.res.mem.fnFree(m_data.ctx, ptr, size, align); } static constexpr bool IsCompatibleKind(NVCVResourceType resType) { return resType == NVCV_RESOURCE_MEM_HOST || resType == NVCV_RESOURCE_MEM_HOST_PINNED || resType == NVCV_RESOURCE_MEM_CUDA; } }; namespace detail { template class MemAllocatorWithKind : public MemAllocator { public: static constexpr NVCVResourceType kResourceType = KIND; MemAllocatorWithKind() = default; MemAllocatorWithKind(const NVCVResourceAllocator &data); static constexpr bool IsCompatibleKind(NVCVResourceType resType) { return resType == kResourceType; } }; } // namespace detail class HostMemAllocator : public detail::MemAllocatorWithKind { using Impl = detail::MemAllocatorWithKind; using Impl::Impl; }; class HostPinnedMemAllocator : public detail::MemAllocatorWithKind { using Impl = detail::MemAllocatorWithKind; using Impl::Impl; }; class CudaMemAllocator : public detail::MemAllocatorWithKind { using Impl = detail::MemAllocatorWithKind; using Impl::Impl; }; NVCV_IMPL_SHARED_HANDLE(Allocator); class Allocator : public CoreResource { public: using CoreResource::CoreResource; HostMemAllocator hostMem() const; HostPinnedMemAllocator hostPinnedMem() const; CudaMemAllocator cudaMem() const; ResourceAllocator get(NVCVResourceType resType) const; template ResAlloc get() const; }; // Custom allocators template class CustomMemAllocator { private: template struct has_trivial_copy_and_destruction : std::integral_constant::value && std::is_trivially_destructible::value> { }; template struct by_value : std::integral_constant::value && sizeof(Callable) <= sizeof(void *) && alignof(Callable) <= alignof(void *)> { }; template static constexpr size_t DataSize() { return std::is_empty::value ? 0 : sizeof(T); } public: template::value>, typename = detail::EnableIf_t::value>> CustomMemAllocator(AllocFunction &&alloc, FreeFunction &&free); // TODO(michalz): Add a way of constructing a custom allocator without using lambdas/captures, e.g. // from an object that matches the allocator concept. CustomMemAllocator(CustomMemAllocator &&other) { *this = std::move(other); } ~CustomMemAllocator() { reset(); } bool needsCleanup() const noexcept { return m_data.cleanup != nullptr; } const NVCVResourceAllocator &cdata() const &noexcept { return m_data; } NVCV_NODISCARD NVCVResourceAllocator release() noexcept { NVCVResourceAllocator ret = {}; std::swap(ret, m_data); return ret; } void reset(NVCVResourceAllocator &&alloc) noexcept { reset(); std::swap(m_data, alloc); } void reset() noexcept { if (m_data.cleanup) m_data.cleanup(m_data.ctx, &m_data); m_data = {}; } CustomMemAllocator &operator=(CustomMemAllocator &&other) noexcept { reset(other.release()); return *this; } private: template friend class CustomAllocator; template void Construct(AllocFunction &&alloc, FreeFunction &&free, std::true_type); template void Construct(AllocFunction &&alloc, FreeFunction &&free, std::false_type); template void ConstructFromDuplicateValues(AllocFunction &&alloc, FreeFunction &&free, std::true_type); #if __cplusplus < 201703L template void ConstructByOneValue(AllocFunction &&, FreeFunction &&, std::true_type, std::false_type) { assert(!"should never get here"); } #endif NVCVResourceAllocator m_data{}; }; using CustomHostMemAllocator = CustomMemAllocator; using CustomHostPinnedMemAllocator = CustomMemAllocator; using CustomCudaMemAllocator = CustomMemAllocator; template class CustomAllocator final : public Allocator { public: explicit CustomAllocator(ResourceAllocators &&...allocators); ~CustomAllocator() { preDestroy(); } private: static constexpr bool kHasReferences = detail::Disjunction>...>::value; template detail::EnableIf_t preDestroy() { if (this->reset() != 0) throw std::logic_error( "The allocator context contains references. The handle must not outlive the context."); } template detail::EnableIf_t preDestroy() noexcept { } }; template CustomAllocator CreateCustomAllocator(ResourceAllocators &&...allocators) { return CustomAllocator{std::move(allocators)...}; } } // namespace nvcv #include "AllocatorImpl.hpp" #endif // NVCV_ALLOC_ALLOCATOR_HPP