Skip to content

Commit

Permalink
Merge branch 'cpp17' into cpp20
Browse files Browse the repository at this point in the history
  • Loading branch information
J. Daniel Smith committed Jul 24, 2023
2 parents 0dbcd9d + 0674592 commit 64e5ec9
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 114 deletions.
6 changes: 6 additions & 0 deletions externals/coda-oss/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
```
# coda-oss Release Notes

## [Release 202?-??-??](https://github.com/mdaus/coda-oss/releases/tag/202?-??-??)
* New `sys::OS::getSIMDInstructionSet()` utility routine; SSE2 is required (default with 64-bit builds).
* `types::ComplexInteger` to work-around `std::complex<short>` no longer being [valid C++](https://en.cppreference.com/w/cpp/numeric/complex).
* Another round of reducing various compiler warnings (of note: `NULL` -> `nullptr`).
* Some suport for [`std::numbers`](https://en.cppreference.com/w/cpp/header/numbers) from C++20.

## [Release 2023-06-05](https://github.com/mdaus/coda-oss/releases/tag/2023-06-05)
* *zlib* updated to [1.2.13](https://github.com/madler/zlib/releases/tag/v1.2.13).
* new `mem::ComplexView` class to make it easier to process complex data stored in parallel.
Expand Down
141 changes: 122 additions & 19 deletions externals/coda-oss/modules/c++/sys/include/sys/ByteSwap.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <complex>

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

#include "ByteSwapValue.h"
#include "Runnable.h"
Expand Down Expand Up @@ -88,23 +89,50 @@ 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 T>
inline auto make_span(coda_oss::span<const std::complex<T>> s)
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 T*>(p_);
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 T>
inline auto make_span(coda_oss::span<std::complex<T>> s)
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<T*>(p_);
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);
}
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);
}

}

// Otherwise, we can sanity-check the `elemSize` parameter
Expand All @@ -115,13 +143,28 @@ inline void byteSwap(T* buffer, size_t elemSize, size_t numElems)
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<...>`
namespace details
{
details::check_elemSize<T>(elemSize);
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);
}

template <typename T>
inline auto byteSwap(coda_oss::span<T> buffer)
Expand All @@ -137,6 +180,11 @@ 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 @@ -185,14 +233,29 @@ inline void byteSwap(const T* buffer, size_t elemSize, size_t numElems, U* outpu
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<...>`
namespace details
{
details::check_elemSize<T>(elemSize);
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);
}

template <typename T>
inline auto byteSwap(coda_oss::span<const T> buffer, coda_oss::span<coda_oss::byte> outputBuffer)
Expand All @@ -206,6 +269,11 @@ 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 @@ -220,27 +288,62 @@ 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
template <typename T>
inline auto byteSwapValue(std::complex<T> z)
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<T(&)[2]>(z);
return byteSwap(make_span(z_));
const auto& z_ = reinterpret_cast<value_type(&)[2]>(z);
return byteSwap(sys::make_span(z_));
}
template<typename T>
inline auto byteSwap(std::complex<T> val)
}
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);
}
namespace details
{
template <typename TComplex>
inline auto byteSwapCx(TComplex val)
{
const auto bytes = byteSwapValue(val);
assert(bytes.size() == sizeof(val));

const void* const pBytes = bytes.data();
auto const pRetVal = static_cast<const std::complex<T>*>(pBytes);
auto const pRetVal = static_cast<const TComplex*>(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: 35 additions & 7 deletions externals/coda-oss/modules/c++/sys/unittests/test_byte_swap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,15 +245,43 @@ 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);
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]);
}
}

TEST_CASE(testByteSwap12)
Expand Down
4 changes: 1 addition & 3 deletions modules/c++/nitf/unittests/test_hash_table_1++.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,6 @@ TEST_CASE(test_hash_table_iterator)
}

TEST_MAIN(
(void)argc;
(void)argv;
TEST_CHECK(test_hash_table_1);
TEST_CHECK(test_hash_table_iterator);
)
)
Loading

0 comments on commit 64e5ec9

Please sign in to comment.