Skip to content

Commit

Permalink
Squashed 'externals/coda-oss/' changes from 710754a00..5f1e5d353
Browse files Browse the repository at this point in the history
5f1e5d353 Merge branch 'main' into cpp17
034d52c86 overloads to byte-swap type::Complex are too much trouble (#707)

git-subtree-dir: externals/coda-oss
git-subtree-split: 5f1e5d3537f7faeb92b3ca1b6849aa0d4d9e400d
  • Loading branch information
J. Daniel Smith committed Jul 24, 2023
1 parent 629dc82 commit 42d858e
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 183 deletions.
145 changes: 26 additions & 119 deletions modules/c++/sys/include/sys/ByteSwap.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#include <complex>

#include "config/Exports.h"
#include "types/Complex.h"

#include "ByteSwapValue.h"
#include "Runnable.h"
Expand Down Expand Up @@ -89,48 +88,25 @@ inline void check_elemSize(size_t elemSize)

// Repackage into a span<T>; the size is 2* because for byte-swapping
// we want to look at this as an array of `T`, not `std::complex<T>`.
template <typename TComplex>
inline auto make_cx_span(coda_oss::span<const TComplex> s)
{
using value_type = typename TComplex::value_type; // i.e., T from std::complex<T>
const void* const p_ = s.data();
auto const p = static_cast<const value_type*>(p_);
const auto sz = s.size() * 2; // real and imag
return sys::make_span(p, sz);
}
template <typename TComplex>
inline auto make_cx_span(coda_oss::span<TComplex> s)
{
using value_type = typename TComplex::value_type; // i.e., T from std::complex<T>
void* const p_ = s.data();
auto const p = static_cast<value_type*>(p_);
const auto sz = s.size() * 2; // real and imag
return sys::make_span(p, sz);
}

template <typename T>
inline auto make_span(coda_oss::span<const std::complex<T>> s)
{
static_assert(std::is_floating_point<T>::value, "std::complex<T> should use floating-point");
return make_cx_span(s);

const void* const p_ = s.data();
auto const p = static_cast<const T*>(p_);
const auto sz = s.size() * 2; // real and imag
return sys::make_span(p, sz);
}
template<typename T>
inline auto make_span(coda_oss::span<std::complex<T>> s)
{
static_assert(std::is_floating_point<T>::value, "std::complex<T> should use floating-point");
return make_cx_span(s);
}

// Support our own complex type too :-(; it's used (too much) in SIX.
template <typename T>
inline auto make_span(coda_oss::span<const types::Complex<T>> s)
{
return make_cx_span(s);
}
template<typename T>
inline auto make_span(coda_oss::span<types::Complex<T>> s)
{
return make_cx_span(s);
void* const p_ = s.data();
auto const p = static_cast<T*>(p_);
const auto sz = s.size() * 2; // real and imag
return sys::make_span(p, sz);
}

}
Expand All @@ -143,27 +119,14 @@ inline void byteSwap(T* buffer, size_t elemSize, size_t numElems)
void* const buffer_ = buffer;
byteSwap(buffer_, elemSize, numElems);
}
namespace details
{
template <typename TComplex>
inline void byteSwapCx(TComplex* buffer, size_t elemSize, size_t numElems) // dont't want `T` as `std::complex<...>`
{
using value_type = typename TComplex::value_type; // i.e., T from std::complex<T>
check_elemSize<value_type>(elemSize);
void* const buffer_ = buffer;
byteSwap(buffer_, elemSize, numElems);
}
}
template <typename T>
inline void byteSwap(std::complex<T>* buffer, size_t elemSize, size_t numElems) // dont't want `T` as `std::complex<...>`
{
static_assert(std::is_floating_point<T>::value, "std::complex<T> should use floating-point");
details::byteSwapCx(buffer, elemSize, numElems);
}
template <typename T>
inline void byteSwap(types::Complex<T>* buffer, size_t elemSize, size_t numElems) // dont't want `T` as `std::complex<...>`
{
details::byteSwapCx(buffer, elemSize, numElems);

details::check_elemSize<T>(elemSize);
void* const buffer_ = buffer;
byteSwap(buffer_, elemSize, numElems);
}

template <typename T>
Expand All @@ -180,11 +143,6 @@ inline auto byteSwap(coda_oss::span<std::complex<T>> buffer)
{
return byteSwap(details::make_span(buffer));
}
template <typename T>
inline auto byteSwap(coda_oss::span<types::Complex<T>> buffer)
{
return byteSwap(details::make_span(buffer));
}

/*!
* Swap bytes into output buffer. Note that a complex pixel
Expand Down Expand Up @@ -233,28 +191,15 @@ inline void byteSwap(const T* buffer, size_t elemSize, size_t numElems, U* outpu
void* const outputBuffer_ = outputBuffer;
byteSwap(buffer_, elemSize, numElems, outputBuffer_);
}
namespace details
{
template <typename TComplex, typename U>
inline void byteSwapCx(const TComplex* buffer, size_t elemSize, size_t numElems, U* outputBuffer) // dont't want `T` as `std::complex<...>`
{
using value_type = typename TComplex::value_type; // i.e., T from std::complex<T>
check_elemSize<value_type>(elemSize);
const void* const buffer_ = buffer;
void* const outputBuffer_ = outputBuffer;
byteSwap(buffer_, elemSize, numElems, outputBuffer_);
}
}
template <typename T, typename U>
inline void byteSwap(const std::complex<T>* buffer, size_t elemSize, size_t numElems, U* outputBuffer) // dont't want `T` as `std::complex<...>`
{
static_assert(std::is_floating_point<T>::value, "std::complex<T> should use floating-point");
details::byteSwapCx(buffer, elemSize, numElems, outputBuffer);
}
template <typename T, typename U>
inline void byteSwap(const types::Complex<T>* buffer, size_t elemSize, size_t numElems, U* outputBuffer) // dont't want `T` as `std::complex<...>`
{
details::byteSwapCx(buffer, elemSize, numElems, outputBuffer);

details::check_elemSize<T>(elemSize);
const void* const buffer_ = buffer;
void* const outputBuffer_ = outputBuffer;
byteSwap(buffer_, elemSize, numElems, outputBuffer_);
}

template <typename T>
Expand All @@ -269,11 +214,6 @@ inline auto byteSwap(coda_oss::span<const std::complex<T>> buffer, coda_oss::spa
{
return byteSwap(details::make_span(buffer), outputBuffer);
}
template <typename T>
inline auto byteSwap(coda_oss::span<const types::Complex<T>> buffer, coda_oss::span<coda_oss::byte> outputBuffer)
{
return byteSwap(details::make_span(buffer), outputBuffer);
}

template <typename T>
inline auto byteSwap(coda_oss::span<const T> buffer)
Expand All @@ -288,62 +228,29 @@ inline auto byteSwap(coda_oss::span<const std::complex<T>> buffer)
{
return byteSwap(details::make_span(buffer));
}
template <typename T>
inline auto byteSwap(coda_oss::span<const types::Complex<T>> buffer)
{
return byteSwap(details::make_span(buffer));
}

// With buffer byte-swap now in place, we can safely byte-swap std::complex<T>.
// This signature is from ByteSwapValue.h
namespace details
{
template <typename TComplex>
inline auto byteSwapCxValue(TComplex z)
{
using value_type = typename TComplex::value_type; // i.e., T from std::complex<T>

// C++ mandates that `std::complex<T>` be the same as `T cx[2]`; that is
// the structure is contiguous. https://en.cppreference.com/w/cpp/numeric/complex
const auto& z_ = reinterpret_cast<value_type(&)[2]>(z);
return byteSwap(sys::make_span(z_));
}
}
template <typename T>
inline auto byteSwapValue(std::complex<T> z)
{
static_assert(std::is_floating_point<T>::value, "std::complex<T> should use floating-point");
return details::byteSwapCxValue(z);
}
template <typename T>
inline auto byteSwapValue(types::Complex<T> z)
{
return details::byteSwapCxValue(z);

// C++ mandates that `std::complex<T>` be the same as `T cx[2]`; that is
// the structure is contiguous. https://en.cppreference.com/w/cpp/numeric/complex
const auto& z_ = reinterpret_cast<T(&)[2]>(z);
return byteSwap(make_span(z_));
}
namespace details
{
template <typename TComplex>
inline auto byteSwapCx(TComplex val)
template<typename T>
inline auto byteSwap(std::complex<T> val)
{
const auto bytes = byteSwapValue(val);
assert(bytes.size() == sizeof(val));

const void* const pBytes = bytes.data();
auto const pRetVal = static_cast<const TComplex*>(pBytes);
auto const pRetVal = static_cast<const std::complex<T>*>(pBytes);
return *pRetVal;
}
}
template<typename T>
inline auto byteSwap(std::complex<T> val)
{
return details::byteSwapCx(val);
}
template <typename T>
inline auto byteSwap(types::Complex<T> val)
{
return details::byteSwapCx(val);
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Expand Down
42 changes: 7 additions & 35 deletions modules/c++/sys/unittests/test_byte_swap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,43 +245,15 @@ TEST_CASE(testByteSwapValues)

TEST_CASE(testByteSwapCxValue)
{
{
using value_type = std::complex<float>;
const value_type cx{3.14f, -31.4f}; // using raw bytes can lean to `nan`s
auto const pValue = &cx;
using value_type = std::complex<float>;
const value_type cx{3.14f, -31.4f}; // using raw bytes can lean to `nan`s
auto const pValue = &cx;

auto swap = sys::byteSwap(*pValue);
TEST_ASSERT_NOT_EQ(*pValue, swap); // technically a bit goofy as the bits may not represent `T`s
auto swap = sys::byteSwap(*pValue);
TEST_ASSERT_NOT_EQ(*pValue, swap); // technically a bit goofy as the bits may not represent `T`s

swap = sys::byteSwap(swap); // swap back
TEST_ASSERT_EQ(*pValue, swap);
}
{
using value_type = types::Complex<int16_t>;
const void* const pValue_ = four_bytes; // two int16_t
auto const pValue = static_cast<const value_type*>(pValue_);

auto swap = sys::byteSwap(*pValue);
TEST_ASSERT_NOT_EQ(*pValue, swap);

// .real() and .imag() are swapped individually
const void* const pSwap_ = &swap;
auto pSwapBytes = static_cast<const std::byte*>(pSwap_);
TEST_ASSERT(four_bytes[0] == pSwapBytes[1]);
TEST_ASSERT(four_bytes[1] == pSwapBytes[0]);
TEST_ASSERT(four_bytes[2] == pSwapBytes[3]);
TEST_ASSERT(four_bytes[3] == pSwapBytes[2]);

swap = sys::byteSwap(swap); // swap back
TEST_ASSERT_EQ(*pValue, swap);

auto buffer = std::as_writable_bytes(sys::make_span(&swap, 1));
sys::byteSwap(sys::make_span(pValue, 1), buffer);
TEST_ASSERT(four_bytes[0] == buffer[1]);
TEST_ASSERT(four_bytes[1] == buffer[0]);
TEST_ASSERT(four_bytes[2] == buffer[3]);
TEST_ASSERT(four_bytes[3] == buffer[2]);
}
swap = sys::byteSwap(swap); // swap back
TEST_ASSERT_EQ(*pValue, swap);
}

TEST_CASE(testByteSwap12)
Expand Down
29 changes: 0 additions & 29 deletions modules/c++/types/include/types/Complex.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,37 +165,8 @@ inline auto abs(const Complex<T>& z) // https://en.cppreference.com/w/cpp/numeri
return abs(details::cast(z));
}

// Control whether ComplexInteger is std::complex or Complex.
// If it is std::complex, then a types::ComplexInteger overload normally can't be
// used as it will be the same as std::complex
#ifdef CODA_OSS_types_FORCE_unique_ComplexInteger // bypass checks below
#define CODA_OSS_types_unique_ComplexInteger 1
#endif
#ifdef CODA_OSS_types_NO_unique_ComplexInteger
#ifdef CODA_OSS_types_unique_ComplexInteger
#error "CODA_OSS_types_unique_ComplexInteger already #define'd"
#endif
#define CODA_OSS_types_unique_ComplexInteger 0
#endif

#ifndef CODA_OSS_types_unique_ComplexInteger
// If the warning about using std::complex<short> has been turned off, we might
// as well use std:complex<short>.
#ifdef _SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING
#define CODA_OSS_types_unique_ComplexInteger 0
#endif
#endif

#ifndef CODA_OSS_types_unique_ComplexInteger
#define CODA_OSS_types_unique_ComplexInteger 1
#endif

template<typename T>
#if CODA_OSS_types_unique_ComplexInteger
using ComplexInteger = Complex<T>;
#else
using ComplexInteger = std::complex<T>;
#endif

namespace details
{
Expand Down

0 comments on commit 42d858e

Please sign in to comment.