CompressionRegistrarImpl.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "CompressionRegistrarImpl.h"
  9. #include <AzCore/std/functional.h>
  10. #include <AzCore/std/parallel/scoped_lock.h>
  11. #include <AzCore/std/ranges/ranges_algorithm.h>
  12. #include <Compression/CompressionTypeIds.h>
  13. namespace Compression
  14. {
  15. AZ_TYPE_INFO_WITH_NAME_IMPL(CompressionRegistrarImpl, "CompressionRegistrarImpl",
  16. CompressionRegistrarImplTypeId);
  17. AZ_RTTI_NO_TYPE_INFO_IMPL(CompressionRegistrarImpl, CompressionRegistrarInterface);
  18. AZ_CLASS_ALLOCATOR_IMPL(CompressionRegistrarImpl, AZ::SystemAllocator);
  19. CompressionRegistrarImpl::CompressionInterfaceDeleter::CompressionInterfaceDeleter() = default;
  20. CompressionRegistrarImpl::CompressionInterfaceDeleter::CompressionInterfaceDeleter(bool shouldDelete)
  21. : m_delete(shouldDelete)
  22. {}
  23. void CompressionRegistrarImpl::CompressionInterfaceDeleter::operator()(ICompressionInterface* ptr) const
  24. {
  25. if (m_delete)
  26. {
  27. delete ptr;
  28. }
  29. }
  30. CompressionRegistrarImpl::CompressionRegistrarImpl() = default;
  31. CompressionRegistrarImpl::~CompressionRegistrarImpl() = default;
  32. void CompressionRegistrarImpl::VisitCompressionInterfaces(const VisitCompressionInterfaceCallback& callback) const
  33. {
  34. auto VisitInterface = [&callback](const CompressionIdIndexEntry& compressionInterfaceEntry)
  35. {
  36. return compressionInterfaceEntry.m_compressionInterface != nullptr ? callback(*compressionInterfaceEntry.m_compressionInterface) : true;
  37. };
  38. AZStd::scoped_lock lock(m_compressionInterfaceMutex);
  39. AZStd::ranges::all_of(m_compressionInterfaces, VisitInterface);
  40. }
  41. AZ::Outcome<void, AZStd::unique_ptr<ICompressionInterface>> CompressionRegistrarImpl::RegisterCompressionInterface(
  42. CompressionAlgorithmId compressionAlgorithmId, AZStd::unique_ptr<ICompressionInterface> compressionInterface)
  43. {
  44. // Transfer ownership to a temporary CompressionInterfacePtr which is supplied to the RegisterCompressionInterfaceImpl
  45. // If registration fails, the compression interface pointer is returned in the failure outcome
  46. if (auto registerResult = RegisterCompressionInterfaceImpl(compressionAlgorithmId, CompressionInterfacePtr{ compressionInterface.release() });
  47. !registerResult.IsSuccess())
  48. {
  49. return AZ::Failure(AZStd::unique_ptr<ICompressionInterface>(registerResult.TakeError().release()));
  50. }
  51. // registration succeeded, return a void success outcome
  52. return AZ::Success();
  53. }
  54. bool CompressionRegistrarImpl::RegisterCompressionInterface(CompressionAlgorithmId compressionAlgorithmId, ICompressionInterface& compressionInterface)
  55. {
  56. // Create a temporary CompressionInterfacePtr with a custom deleter that does NOT delete the compressionInterface reference
  57. // On success, the the CompressionInterfacePtr is stored in the compression interface array
  58. // and will not delete the reference to registered interface
  59. return RegisterCompressionInterfaceImpl(compressionAlgorithmId, CompressionInterfacePtr{ &compressionInterface, CompressionInterfaceDeleter{false} }).IsSuccess();
  60. }
  61. auto CompressionRegistrarImpl::RegisterCompressionInterfaceImpl(CompressionAlgorithmId compressionAlgorithmId, CompressionInterfacePtr compressionInterfacePtr)
  62. -> AZ::Outcome<void, CompressionInterfacePtr>
  63. {
  64. if (compressionInterfacePtr == nullptr)
  65. {
  66. return AZ::Failure(AZStd::move(compressionInterfacePtr));
  67. }
  68. AZStd::scoped_lock lock(m_compressionInterfaceMutex);
  69. auto compressionIter = FindCompressionInterfaceImpl(compressionAlgorithmId);
  70. if (compressionIter != m_compressionInterfaces.end())
  71. {
  72. // The compression interface has been found using the compression interface id,
  73. // so another registration cannot be done
  74. return AZ::Failure(AZStd::move(compressionInterfacePtr));
  75. }
  76. // Use UpperBound to find the insertion slot for the new entry
  77. auto ProjectionToCompressionAlgorithmId = [](const CompressionIdIndexEntry& entry) -> CompressionAlgorithmId
  78. {
  79. return entry.m_id;
  80. };
  81. m_compressionInterfaces.emplace(AZStd::ranges::upper_bound(m_compressionInterfaces, compressionAlgorithmId,
  82. AZStd::ranges::less{}, ProjectionToCompressionAlgorithmId),
  83. CompressionIdIndexEntry{ compressionAlgorithmId, AZStd::move(compressionInterfacePtr) });
  84. return AZ::Success();
  85. }
  86. bool CompressionRegistrarImpl::UnregisterCompressionInterface(CompressionAlgorithmId compressionAlgorithmId)
  87. {
  88. AZStd::scoped_lock lock(m_compressionInterfaceMutex);
  89. if (auto compressionIter = FindCompressionInterfaceImpl(compressionAlgorithmId);
  90. compressionIter != m_compressionInterfaces.end())
  91. {
  92. // Remove the compressionInterface
  93. m_compressionInterfaces.erase(compressionIter);
  94. return true;
  95. }
  96. return false;
  97. }
  98. ICompressionInterface* CompressionRegistrarImpl::FindCompressionInterface(CompressionAlgorithmId compressionAlgorithmId) const
  99. {
  100. AZStd::scoped_lock lock(m_compressionInterfaceMutex);
  101. auto compressionIter = FindCompressionInterfaceImpl(compressionAlgorithmId);
  102. return compressionIter != m_compressionInterfaces.end() ? compressionIter->m_compressionInterface.get() : nullptr;
  103. }
  104. ICompressionInterface* CompressionRegistrarImpl::FindCompressionInterface(AZStd::string_view algorithmName) const
  105. {
  106. // Potentially the entire vector is iterated over
  107. ICompressionInterface* resultInterface{};
  108. auto FindCompressionInterfaceByName = [algorithmName, &resultInterface](const ICompressionInterface& compressionInterface)
  109. {
  110. if (compressionInterface.GetCompressionAlgorithmName() == algorithmName)
  111. {
  112. // const_cast is being used here to avoid making a second visitor overload
  113. // NOTE: this is function is internal to the implementation of the Compression Registrar
  114. resultInterface = const_cast<ICompressionInterface*>(&compressionInterface);
  115. // The matching interface has been found, halt visitation.
  116. return false;
  117. }
  118. return true;
  119. };
  120. AZStd::scoped_lock lock(m_compressionInterfaceMutex);
  121. VisitCompressionInterfaces(FindCompressionInterfaceByName);
  122. return resultInterface;
  123. }
  124. bool CompressionRegistrarImpl::IsRegistered(CompressionAlgorithmId compressionAlgorithmId) const
  125. {
  126. AZStd::scoped_lock lock(m_compressionInterfaceMutex);
  127. auto compressionIter = FindCompressionInterfaceImpl(compressionAlgorithmId);
  128. return compressionIter != m_compressionInterfaces.end();
  129. }
  130. // NOTE: The caller should lock the mutex
  131. // returns iterator to the compression inteface with the specified compression algorithm id
  132. // otherwise a sentinel iterator is returned
  133. auto CompressionRegistrarImpl::FindCompressionInterfaceImpl(CompressionAlgorithmId compressionAlgorithmId) const
  134. -> typename IdToCompressionInterfaceMap::const_iterator
  135. {
  136. auto ProjectionToCompressionAlgorithmId = [](const CompressionIdIndexEntry& entry) -> CompressionAlgorithmId
  137. {
  138. return entry.m_id;
  139. };
  140. auto [firstFoundIter, lastFoundIter] = AZStd::ranges::equal_range(m_compressionInterfaces,
  141. compressionAlgorithmId, AZStd::ranges::less{}, ProjectionToCompressionAlgorithmId);
  142. return firstFoundIter != lastFoundIter ? firstFoundIter : m_compressionInterfaces.end();
  143. }
  144. }// namespace Compression