diff --git a/six/modules/c++/six.sicd/include/six/sicd/ComplexData.h b/six/modules/c++/six.sicd/include/six/sicd/ComplexData.h index 48565a4af..7b4b322be 100644 --- a/six/modules/c++/six.sicd/include/six/sicd/ComplexData.h +++ b/six/modules/c++/six.sicd/include/six/sicd/ComplexData.h @@ -162,7 +162,7 @@ struct ComplexData: public Data { imageData->pixelType = pixelType; } - bool convertPixels_(std::span, std::span) const override; + bool convertPixels_(std::span, std::vector&) const override; /*! * Maps to: /SICD/ImageData/NumRows, diff --git a/six/modules/c++/six.sicd/include/six/sicd/ImageData.h b/six/modules/c++/six.sicd/include/six/sicd/ImageData.h index 13af4affd..9d3b3c068 100644 --- a/six/modules/c++/six.sicd/include/six/sicd/ImageData.h +++ b/six/modules/c++/six.sicd/include/six/sicd/ImageData.h @@ -99,11 +99,10 @@ struct ImageData bool validate(const GeoData& geoData, logging::Logger& log) const; - static void testing_fromComplex_(std::span, std::span); // for unit-tests - static void toComplex(const six::Amp8iPhs8iLookup_t& lookup, std::span, std::span); - void toComplex(std::span, std::span) const; - void fromComplex(std::span, std::span) const; + std::vector toComplex(std::span) const; + std::vector fromComplex(std::span) const; + static std::vector testing_fromComplex_(std::span); // for unit-tests /*! * Create a lookup table for converting from AMP8I_PHS8I to complex. diff --git a/six/modules/c++/six.sicd/source/ComplexData.cpp b/six/modules/c++/six.sicd/source/ComplexData.cpp index 12d47d350..0e6fdf6a6 100644 --- a/six/modules/c++/six.sicd/source/ComplexData.cpp +++ b/six/modules/c++/six.sicd/source/ComplexData.cpp @@ -358,10 +358,6 @@ inline const void* cast_to_pvoid(std::span bytes) { return bytes.data(); } -inline void* cast_to_pvoid(std::span bytes) -{ - return bytes.data(); -} template inline std::span make_span(std::span bytes) { @@ -369,7 +365,7 @@ inline std::span make_span(std::span bytes) return std::span(static_cast(cast_to_pvoid(bytes)), size); } -bool six::sicd::ComplexData::convertPixels_(std::span from_, std::span to_) const +bool six::sicd::ComplexData::convertPixels_(std::span from_, std::vector& to) const { if (getPixelType() != PixelType::AMP8I_PHS8I) { @@ -378,7 +374,6 @@ bool six::sicd::ComplexData::convertPixels_(std::span from_, st // Convert the pixels from a complex to AMP8I_PHS8I. const auto from = make_span(from_); - const auto to = make_span(to_); - imageData->fromComplex(from, to); + to = imageData->fromComplex(from); return true; // converted } diff --git a/six/modules/c++/six.sicd/source/ComplexToAMP8IPHS8I.cpp b/six/modules/c++/six.sicd/source/ComplexToAMP8IPHS8I.cpp index a289d8fab..a24390a32 100644 --- a/six/modules/c++/six.sicd/source/ComplexToAMP8IPHS8I.cpp +++ b/six/modules/c++/six.sicd/source/ComplexToAMP8IPHS8I.cpp @@ -219,7 +219,7 @@ template static inline void transform(std::span inputs, std::span results, TFunc f) { #if SIX_six_sicd_ComplexToAMP8IPHS8I_has_execution - std::ignore = std::transform(std::execution::par, inputs.begin(), inputs.end(), results.begin(), f); + std::ignore = std::transform(std::execution::par_unseq, inputs.begin(), inputs.end(), results.begin(), f); #else constexpr ptrdiff_t cutoff_ = 0; // too slow w/o multi-threading // The value of "default_cutoff" was determined by testing; there is nothing special about it, feel free to change it. @@ -230,16 +230,23 @@ static inline void transform(std::span inputs, std::span inputs, std::span results, - const six::AmplitudeTable* pAmplitudeTable) +std::vector six::sicd::details::ComplexToAMP8IPHS8I::nearest_neighbors(std::span inputs) const { - // make a structure to quickly find the nearest neighbor - auto& converter = make(pAmplitudeTable); - const auto fromComplex_ = [&converter](const auto& v) + const auto nearest_neighbor_ = [&](const auto& v) { - return converter.nearest_neighbor(v); + return this->nearest_neighbor(v); }; - transform(inputs, results, fromComplex_); + + std::vector retval(inputs.size()); + transform(sys::make_const_span(inputs), sys::make_span(retval), nearest_neighbor_); + return retval; +} +std::vector six::sicd::details::ComplexToAMP8IPHS8I::nearest_neighbors( + std::span inputs, const six::AmplitudeTable* pAmplitudeTable) +{ + // make a structure to quickly find the nearest neighbor + const auto& converter = make(pAmplitudeTable); + return converter.nearest_neighbors(inputs); } const six::sicd::details::ComplexToAMP8IPHS8I& six::sicd::details::ComplexToAMP8IPHS8I::make(const six::AmplitudeTable* pAmplitudeTable) diff --git a/six/modules/c++/six.sicd/source/ImageData.cpp b/six/modules/c++/six.sicd/source/ImageData.cpp index 147383a97..4b7092608 100644 --- a/six/modules/c++/six.sicd/source/ImageData.cpp +++ b/six/modules/c++/six.sicd/source/ImageData.cpp @@ -39,6 +39,7 @@ #define SIX_six_sicd_ImageData_has_execution 1 #endif #endif +#include #include "six/AmplitudeTable.h" #include "six/sicd/GeoData.h" @@ -255,7 +256,7 @@ void ImageData::toComplex(const six::Amp8iPhs8iLookup_t& values, std::span inputs, std::span results) const +std::vector ImageData::toComplex(std::span inputs) const { if (pixelType != PixelType::AMP8I_PHS8I) { @@ -263,16 +264,20 @@ void ImageData::toComplex(std::span inputs, std::span retval(inputs.size()); + toComplex(values, inputs, sys::make_span(retval)); + return retval; } -void ImageData::fromComplex(std::span inputs, std::span results) const +std::vector ImageData::fromComplex(std::span inputs) const { - six::sicd::details::ComplexToAMP8IPHS8I::nearest_neighbors(inputs, results, amplitudeTable.get()); + return six::sicd::details::ComplexToAMP8IPHS8I::nearest_neighbors(inputs, amplitudeTable.get()); } -void ImageData::testing_fromComplex_(std::span inputs, std::span results) + +std::vector ImageData::testing_fromComplex_(std::span inputs) { static const ImageData imageData; assert(imageData.amplitudeTable.get() == nullptr); - imageData.fromComplex(inputs, results); + return imageData.fromComplex(inputs); } diff --git a/six/modules/c++/six.sicd/source/Utilities.cpp b/six/modules/c++/six.sicd/source/Utilities.cpp index 9ffa49c4f..c02fdb5ea 100644 --- a/six/modules/c++/six.sicd/source/Utilities.cpp +++ b/six/modules/c++/six.sicd/source/Utilities.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -1679,8 +1680,11 @@ std::vector six::sicd::testing::toBytes(const ComplexImageResult& res const auto& data = *(result.pComplexData); if (data.getPixelType() == six::PixelType::AMP8I_PHS8I) { - retval.resize(image.size() * data.getNumBytesPerPixel()); - data.convertPixels(bytes, sys::make_span(retval)); + std::vector results; + std::ignore = data.convertPixels(bytes, results); + + const auto result_bytes = std::as_bytes(sys::make_span(results)); + retval.assign(result_bytes.begin(), result_bytes.end()); } else { diff --git a/six/modules/c++/six.sicd/unittests/test_AMP8I_PHS8I.cpp b/six/modules/c++/six.sicd/unittests/test_AMP8I_PHS8I.cpp index 8a45d4830..fb26e7076 100644 --- a/six/modules/c++/six.sicd/unittests/test_AMP8I_PHS8I.cpp +++ b/six/modules/c++/six.sicd/unittests/test_AMP8I_PHS8I.cpp @@ -140,20 +140,16 @@ static void test_assert_eq(const std::string& testName, } } -static void from_AMP8I_PHS8I(const six::sicd::ImageData& imageData, - const std::vector& inputs_, std::vector& results_) +inline static auto from_AMP8I_PHS8I(const six::sicd::ImageData& imageData, + const std::vector& inputs) { - const std::span inputs(inputs_.data(), inputs_.size()); - const std::span results(results_.data(), results_.size()); - imageData.toComplex(inputs, results); + return imageData.toComplex(sys::make_span(inputs)); } -static void to_AMP8I_PHS8I(const six::sicd::ImageData& imageData, - const std::vector& inputs_, std::vector& results_) +inline static void to_AMP8I_PHS8I(const six::sicd::ImageData& imageData, + const std::vector& inputs, std::vector& results) { - const std::span inputs(inputs_.data(), inputs_.size()); - const std::span results(results_.data(), results_.size()); - imageData.fromComplex(inputs, results); + results = imageData.fromComplex(sys::make_span(inputs)); } TEST_CASE(test_8bit_ampphs) @@ -175,8 +171,7 @@ TEST_CASE(test_8bit_ampphs) } } - std::vector actuals(inputs.size()); - from_AMP8I_PHS8I(imageData, inputs, actuals); + const auto actuals = from_AMP8I_PHS8I(imageData, inputs); TEST_ASSERT(actuals == expecteds); @@ -244,8 +239,7 @@ static Pair to_AMP8I_PHS8I(const six::sicd::ImageData& imageData, cons // image is far too big to call to_AMP8I_PHS8I() with DEBUG code const auto size = sys::debug ? widebandData.size() / 200 : widebandData.size(); const std::span widebandData_(widebandData.data(), size); - std::vector results(widebandData_.size()); - imageData.fromComplex(widebandData_, std::span< AMP8I_PHS8I_t>(results.data(), results.size())); + const auto results = imageData.fromComplex(widebandData_); Pair retval{ 0, 0 }; for (const auto& r : results) @@ -396,12 +390,10 @@ static std::vector adjust_image(const six::sicd::ComplexData& compl // Convert from AMP8I_PHS8I to that when we convert to AMP8I_PHS8I for writing // we'll end up with the "[***...***]" in the file void* image_data = image.data(); - std::span from_(static_cast(image_data), getExtent(complexData).area()); - adjust_image(from_); + std::span from(static_cast(image_data), getExtent(complexData).area()); + adjust_image(from); - std::span from(from_.data(), from_.size()); - std::vector retval(from.size()); - complexData.imageData->toComplex(from, std::span(retval.data(), retval.size())); + const auto retval = complexData.imageData->toComplex(sys::make_const_span(from)); return retval; } static std::vector make_complex_image(const six::sicd::ComplexData& complexData, const types::RowCol& dims) @@ -505,10 +497,7 @@ static void test_assert_image_(const std::string& testName, TEST_ASSERT_ALMOST_EQ(image[i].imag(), expected_cxfloat[i].imag()); } - const std::span input(image.data(), image.size()); - std::vector result(input.size()); - std::span< AMP8I_PHS8I_t> result_(result.data(), result.size()); - complexData.imageData->fromComplex(input, result_); + const auto result = complexData.imageData->fromComplex(sys::make_span(image)); static const std::vector expected_amp8i_phs8i{ AMP8I_PHS8I_t{91, 42}, AMP8I_PHS8I_t{42, 42}, AMP8I_PHS8I_t{42, 42}, AMP8I_PHS8I_t{42, 93} }; // "[******]" @@ -561,10 +550,8 @@ static void test_adjusted_values(const std::string& testName, const std::vector< { v += delta; } - std::vector actual(expected.size()); - std::span actual_(actual.data(), actual.size()); std::span values_(adjusted_values.data(), adjusted_values.size()); - six::sicd::ImageData::testing_fromComplex_(values_, actual_); + const auto actual = six::sicd::ImageData::testing_fromComplex_(values_); for (size_t i = 0; i < expected.size(); i++) { TEST_ASSERT_EQ(expected[i].amplitude, actual[i].amplitude); @@ -584,11 +571,7 @@ TEST_CASE(test_nearest_neighbor) {static_cast(141), static_cast(96)}, {static_cast(255), static_cast(160)} }; - std::vector actual(expected.size()); - std::span actual_(actual.data(), actual.size()); - std::span values_(values.data(), values.size()); - six::sicd::ImageData::testing_fromComplex_(values_, actual_); - + const auto actual = six::sicd::ImageData::testing_fromComplex_(sys::make_span(values)); for (size_t i = 0; i < expected.size(); i++) { TEST_ASSERT_EQ(expected[i].amplitude, actual[i].amplitude); diff --git a/six/modules/c++/six/include/six/Adapters.h b/six/modules/c++/six/include/six/Adapters.h index 3ee921b20..774b169bc 100644 --- a/six/modules/c++/six/include/six/Adapters.h +++ b/six/modules/c++/six/include/six/Adapters.h @@ -172,7 +172,7 @@ class NewMemoryWriteHandler final : public nitf::WriteHandler // all of our code std::span buffer, size_t firstRow, const Data& data, bool doByteSwap); NewMemoryWriteHandler(const NITFSegmentInfo& info, - std::span> buffer, + std::span buffer, size_t firstRow, const Data& data, bool doByteSwap); }; diff --git a/six/modules/c++/six/include/six/AmplitudeTable.h b/six/modules/c++/six/include/six/AmplitudeTable.h index 6724cd114..e303c7b68 100644 --- a/six/modules/c++/six/include/six/AmplitudeTable.h +++ b/six/modules/c++/six/include/six/AmplitudeTable.h @@ -203,9 +203,11 @@ class ComplexToAMP8IPHS8I final * @return nearest amplitude and phase value */ AMP8I_PHS8I_t nearest_neighbor(const six::zfloat& v) const; - static void nearest_neighbors(std::span inputs, std::span results, const six::AmplitudeTable*); + static std::vector nearest_neighbors(std::span inputs, const six::AmplitudeTable*); private: + std::vector nearest_neighbors(std::span inputs) const; + //! The sorted set of possible magnitudes order from small to large. std::vector uncached_magnitudes; // Order is important! This must be ... const std::vector& magnitudes; // ... before this. diff --git a/six/modules/c++/six/include/six/Data.h b/six/modules/c++/six/include/six/Data.h index 5f23fe820..6230d7a66 100644 --- a/six/modules/c++/six/include/six/Data.h +++ b/six/modules/c++/six/include/six/Data.h @@ -80,26 +80,13 @@ struct Data */ virtual PixelType getPixelType() const = 0; virtual void setPixelType(PixelType pixelType) = 0; - virtual bool convertPixels_(std::span, std::span) const { return false; } - template - bool convertPixels(std::span from, std::span to) const - { - // coda-oss checks to be sure T and U are trivially_copyable. While this is - // correct (converting something else to bytes doesn't make sense), existing - // code didn't have that check. - // - // TODO: use std::as_bytes() directly - - const void* const pFrom = from.data(); - auto const pFromBytes = static_cast(pFrom); - const std::span fromBytes(pFromBytes, from.size_bytes()); - - void* const pTo = to.data(); - auto const pToBytes = static_cast(pTo); - const std::span toBytes(pToBytes, to.size_bytes()); - return convertPixels_(fromBytes, toBytes); - } + virtual bool convertPixels_(std::span, std::vector&) const { return false; } + template + bool convertPixels(std::span from, std::vector& to) const + { + return convertPixels_(std::as_bytes(from), to); + } /*! * Maps to: /SICD/ImageData/NumRows,/SICD/ImageData/FullImage/Row diff --git a/six/modules/c++/six/include/six/NITFWriteControl.h b/six/modules/c++/six/include/six/NITFWriteControl.h index 499e49da6..75affea35 100644 --- a/six/modules/c++/six/include/six/NITFWriteControl.h +++ b/six/modules/c++/six/include/six/NITFWriteControl.h @@ -301,7 +301,7 @@ class NITFWriteControl : public WriteControl // Be explicit about the types of images that can be saved; templates are provided below. void save_image(std::span, nitf::IOInterface&, const std::vector&); void save_image(std::span, nitf::IOInterface&, const std::vector&); - void save_image(std::span>, nitf::IOInterface&, const std::vector&); + void save_image(std::span, nitf::IOInterface&, const std::vector&); void save_image(std::span, nitf::IOInterface&, const std::vector&); void save_image(std::span, nitf::IOInterface&, const std::vector&); diff --git a/six/modules/c++/six/include/six/Types.h b/six/modules/c++/six/include/six/Types.h index 08b0ecf74..84cd4ab85 100644 --- a/six/modules/c++/six/include/six/Types.h +++ b/six/modules/c++/six/include/six/Types.h @@ -201,7 +201,7 @@ struct Constants // Each pixel is stored as a pair of numbers that represent the amplitude and phase // components. Each component is stored in an 8-bit unsigned integer (1 byte per // component, 2 bytes per pixel). - static_assert(sizeof(std::pair) == 2, "AMP8I_PHS8I should be two 8-bit integers"); + static_assert(sizeof(AMP8I_PHS8I_t) == 2, "AMP8I_PHS8I should be two 8-bit integers"); return 2; } diff --git a/six/modules/c++/six/source/Adapters.cpp b/six/modules/c++/six/source/Adapters.cpp index f1693a494..8955c838f 100644 --- a/six/modules/c++/six/source/Adapters.cpp +++ b/six/modules/c++/six/source/Adapters.cpp @@ -29,6 +29,8 @@ #include #include +#include + using namespace six; template @@ -195,16 +197,15 @@ inline void validate_buffer(std::span buffer, const NITFSegmentInfo& info, co struct NewMemoryWriteHandler::Impl final { // This needs to persist beyhond the constructor - std::vector> ampi8i_phs8i; + std::vector ampi8i_phs8i; void convertPixels(NewMemoryWriteHandler& instance, const NITFSegmentInfo& info, std::span buffer, const Data& data) { - ampi8i_phs8i.resize(buffer.size()); - const std::span> ampi8i_phs8i_(ampi8i_phs8i.data(), ampi8i_phs8i.size()); - if (!data.convertPixels(buffer, ampi8i_phs8i_)) + if (!data.convertPixels(buffer, ampi8i_phs8i)) { throw std::runtime_error("Unable to convert pixels."); } + const auto ampi8i_phs8i_ = sys::make_span(ampi8i_phs8i); validate_buffer(ampi8i_phs8i_, info, data); // Everything is kosher, point to the converted data @@ -253,7 +254,7 @@ NewMemoryWriteHandler::NewMemoryWriteHandler(const NITFSegmentInfo& info, if (data.getPixelType() == six::PixelType::AMP8I_PHS8I) { // Assume that buffer is really six::zfloat. If it is something else - // (e.g., std::pair -- already converted) a different + // (e.g., AMP8I_PHS8I_t -- already converted) a different // overload should be used. Since we've lost the actual buffer type, // there not much else to do except hope for the best. const void* pBuffer_ = buffer.data(); @@ -282,7 +283,7 @@ NewMemoryWriteHandler::NewMemoryWriteHandler(const NITFSegmentInfo& info, } NewMemoryWriteHandler::NewMemoryWriteHandler(const NITFSegmentInfo& info, - std::span> buffer, size_t firstRow, const Data& data, bool doByteSwap) + std::span buffer, size_t firstRow, const Data& data, bool doByteSwap) : NewMemoryWriteHandler(info, cast(buffer), firstRow, data, doByteSwap) { // This is for the uncommon case where the data is already in this format; normally, it is six::zfloat. diff --git a/six/modules/c++/six/source/NITFWriteControl.cpp b/six/modules/c++/six/source/NITFWriteControl.cpp index f3ffa98fd..64f73b3a0 100644 --- a/six/modules/c++/six/source/NITFWriteControl.cpp +++ b/six/modules/c++/six/source/NITFWriteControl.cpp @@ -208,7 +208,7 @@ static auto asBytes(BufferList::value_type pImageData, // At this point, we've lost information about the ACTUAL size of the buffer. Normally, the computation above will be correct. // But in the case of AMP8I_PHS8I (now supported), the buffer is actually RE32F_IM32F as the data is converted to - // six::zfloat when read-in, and converted to std::pair when written-out. + // six::zfloat when read-in, and converted to AMP8I_PHS8I_t when written-out. if (data.getPixelType() == six::PixelType::AMP8I_PHS8I) { size_in_bytes *= sizeof(float);