From 01e02019ab4d6381245cb650bfdf53bda417ec1d Mon Sep 17 00:00:00 2001 From: Niels Dekker Date: Tue, 30 Aug 2022 13:12:11 +0200 Subject: [PATCH] ENH: Mimic C++20 `std::make_unique_for_overwrite` for dynamic arrays Allows creating a dynamically allocated array that is automatically deleted, by calling `make_unique_for_overwrite(numberOfElements)`. --- .../include/itkMakeUniqueForOverwrite.h | 81 +++++++++++++++++++ Modules/Core/Common/test/CMakeLists.txt | 1 + .../test/itkMakeUniqueForOverwriteGTest.cxx | 43 ++++++++++ 3 files changed, 125 insertions(+) create mode 100644 Modules/Core/Common/include/itkMakeUniqueForOverwrite.h create mode 100644 Modules/Core/Common/test/itkMakeUniqueForOverwriteGTest.cxx diff --git a/Modules/Core/Common/include/itkMakeUniqueForOverwrite.h b/Modules/Core/Common/include/itkMakeUniqueForOverwrite.h new file mode 100644 index 00000000000..9ff68cdb90d --- /dev/null +++ b/Modules/Core/Common/include/itkMakeUniqueForOverwrite.h @@ -0,0 +1,81 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * 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 + * + * https://www.apache.org/licenses/LICENSE-2.0.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. + * + *=========================================================================*/ + +#ifndef itkMakeUniqueForOverwrite_h +#define itkMakeUniqueForOverwrite_h + +#include // For unique_ptr. + +#if __cplusplus < 202002L + +# include // For remove_extent_t, false_type, etc. + +namespace itk +{ + +// Namespace of implementation details (not part of the public ITK interface). +namespace MakeUniqueForOverwriteImplDetail +{ + +// `is_unbounded_array` implementation for C++14/C++17. From C++20, `std::is_unbounded_array` is preferred. +template +struct is_unbounded_array : std::false_type +{}; + +template +struct is_unbounded_array : std::true_type +{}; + +} // namespace MakeUniqueForOverwriteImplDetail + + +/** `make_unique_for_overwrite` implementation for C++14/C++17, specifically for dynamically sized ("unbounded") + * arrays. From C++20, `std::make_unique_for_overwrite` is preferred. + * + * Example (mind the square brackets): + \code + using ElementType = int; + size_t numberOfElements{ 42 }; + + // Create a buffer that may be used to store the specified number of elements. + auto buffer = make_unique_for_overwrite(numberOfElements); + \endcode + * + */ +template +auto +make_unique_for_overwrite(const size_t numberOfElements) +{ + // The template argument must be something like `ElementType[]`, having an empty pair of square brackets. + static_assert(MakeUniqueForOverwriteImplDetail::is_unbounded_array::value, + "The specified template argument must be an unbounded array type!"); + return std::unique_ptr(new std::remove_extent_t[numberOfElements]); +} + +} // namespace itk + +#else + +namespace itk +{ +using ::std::make_unique_for_overwrite; +} + +#endif + +#endif // itkMakeUniqueForOverwrite_h diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt index a56212e4b60..0611d1cb694 100644 --- a/Modules/Core/Common/test/CMakeLists.txt +++ b/Modules/Core/Common/test/CMakeLists.txt @@ -638,6 +638,7 @@ set(ITKCommonGTests itkImageRegionGTest.cxx itkIndexGTest.cxx itkIndexRangeGTest.cxx + itkMakeUniqueForOverwriteGTest.cxx itkMatrixGTest.cxx itkMersenneTwisterRandomVariateGeneratorGTest.cxx itkNeighborhoodAllocatorGTest.cxx diff --git a/Modules/Core/Common/test/itkMakeUniqueForOverwriteGTest.cxx b/Modules/Core/Common/test/itkMakeUniqueForOverwriteGTest.cxx new file mode 100644 index 00000000000..96de252d9ed --- /dev/null +++ b/Modules/Core/Common/test/itkMakeUniqueForOverwriteGTest.cxx @@ -0,0 +1,43 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * 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 + * + * https://www.apache.org/licenses/LICENSE-2.0.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. + * + *=========================================================================*/ + +// First include the header file to be tested: +#include "itkMakeUniqueForOverwrite.h" +#include +#include // For iota. + + +// Tests that `make_unique_for_overwrite` creates an array of the specified dynamic size, whose elements can all be +// written to. +TEST(MakeUniqueForOverwrite, CreatesAnArrayThatCanBeWrittenTo) +{ + for (std::size_t numberOfElements = 1; numberOfElements < 4; ++numberOfElements) + { + const auto data = itk::make_unique_for_overwrite(numberOfElements); + ASSERT_NE(data, nullptr); + + // Write the values { 0, 1, ... , N-1 }. + std::iota(data.get(), data.get() + numberOfElements, 0); + + // Check that each value is correctly written to the corresponding element. + for (std::size_t i = 0; i < numberOfElements; ++i) + { + EXPECT_EQ(data[i], i); + } + } +}