diff --git a/externals/coda-oss/UnitTest/UnitTest.vcxproj b/externals/coda-oss/UnitTest/UnitTest.vcxproj
index 5f55f6360..e6dd924ee 100644
--- a/externals/coda-oss/UnitTest/UnitTest.vcxproj
+++ b/externals/coda-oss/UnitTest/UnitTest.vcxproj
@@ -25,7 +25,6 @@
v143
false
Unicode
- true
DynamicLibrary
@@ -34,7 +33,6 @@
true
false
Unicode
- true
@@ -259,6 +257,10 @@
true
true
+
+ true
+ true
+
true
true
diff --git a/externals/coda-oss/UnitTest/UnitTest.vcxproj.filters b/externals/coda-oss/UnitTest/UnitTest.vcxproj.filters
index e85d2fcd0..37d7c36cf 100644
--- a/externals/coda-oss/UnitTest/UnitTest.vcxproj.filters
+++ b/externals/coda-oss/UnitTest/UnitTest.vcxproj.filters
@@ -219,6 +219,9 @@
re
+
+ mt
+
diff --git a/externals/coda-oss/UnitTest/mt.cpp b/externals/coda-oss/UnitTest/mt.cpp
index 2de6f17fd..6190f8aa4 100644
--- a/externals/coda-oss/UnitTest/mt.cpp
+++ b/externals/coda-oss/UnitTest/mt.cpp
@@ -24,4 +24,8 @@ TEST_CLASS(work_sharing_balanced_runnable_1d_test){ public:
#include "mt/unittests/work_sharing_balanced_runnable_1d_test.cpp"
};
+TEST_CLASS(test_mt_byte_swap){ public:
+#include "mt/unittests/test_mt_byte_swap.cpp"
+};
+
}
\ No newline at end of file
diff --git a/externals/coda-oss/UnitTest/pch.h b/externals/coda-oss/UnitTest/pch.h
index 8229e0b47..ecbdb7c88 100644
--- a/externals/coda-oss/UnitTest/pch.h
+++ b/externals/coda-oss/UnitTest/pch.h
@@ -75,6 +75,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -87,6 +88,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/externals/coda-oss/modules/c++/coda-oss-lite.vcxproj b/externals/coda-oss/modules/c++/coda-oss-lite.vcxproj
index f50ac4a19..d5e4e5cf8 100644
--- a/externals/coda-oss/modules/c++/coda-oss-lite.vcxproj
+++ b/externals/coda-oss/modules/c++/coda-oss-lite.vcxproj
@@ -149,6 +149,7 @@
+
@@ -191,6 +192,8 @@
+
+
@@ -228,6 +231,7 @@
+
@@ -421,14 +425,12 @@
DynamicLibrary
true
v143
- true
DynamicLibrary
false
v143
true
- true
diff --git a/externals/coda-oss/modules/c++/coda-oss-lite.vcxproj.filters b/externals/coda-oss/modules/c++/coda-oss-lite.vcxproj.filters
index 75b551471..a8119ff83 100644
--- a/externals/coda-oss/modules/c++/coda-oss-lite.vcxproj.filters
+++ b/externals/coda-oss/modules/c++/coda-oss-lite.vcxproj.filters
@@ -735,6 +735,18 @@
config
+
+ sys
+
+
+ sys
+
+
+ mt
+
+
+ sys
+
diff --git a/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/CPlusPlus.h b/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/CPlusPlus.h
index 018be14ae..8d5d6a0d3 100644
--- a/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/CPlusPlus.h
+++ b/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/CPlusPlus.h
@@ -63,11 +63,12 @@
#endif // CODA_OSS_cplusplus
// Define a few macros as that's less verbose than testing against a version number
+// https://en.cppreference.com/w/cpp/preprocessor/replace#Predefined_macros
#define CODA_OSS_cpp11 (CODA_OSS_cplusplus >= 201103L)
#define CODA_OSS_cpp14 (CODA_OSS_cplusplus >= 201402L)
#define CODA_OSS_cpp17 (CODA_OSS_cplusplus >= 201703L)
#define CODA_OSS_cpp20 (CODA_OSS_cplusplus >= 202002L)
-#define CODA_OSS_cpp23 0
+#define CODA_OSS_cpp23 (CODA_OSS_cplusplus >= 202302L)
#if !CODA_OSS_cpp17
#error "Must compile with C++17 or greater."
diff --git a/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/bit.h b/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/bit.h
index 99045bba1..32ef77862 100644
--- a/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/bit.h
+++ b/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/bit.h
@@ -22,6 +22,14 @@
#define CODA_OSS_coda_oss_bit_h_INCLUDED_
#pragma once
+#include
+#include
+#ifdef __GNUC__
+#include // "These functions are GNU extensions."
+#endif
+
+#include
+
#include "coda_oss/namespace_.h"
namespace coda_oss
{
@@ -38,6 +46,58 @@ namespace coda_oss
native = __BYTE_ORDER__
#endif
};
+
+ // https://en.cppreference.com/w/cpp/numeric/byteswap
+ namespace details
+ {
+ // Overloads for common types
+ inline constexpr uint8_t byteswap(uint8_t val) noexcept
+ {
+ return val; // no-op
+ }
+ #if defined(_MSC_VER)
+ // These routines should generate a single instruction; see
+ // https://devblogs.microsoft.com/cppblog/a-tour-of-4-msvc-backend-improvements/
+ inline uint16_t byteswap(uint16_t val)
+ {
+ return _byteswap_ushort(val);
+ }
+ inline uint32_t byteswap(uint32_t val)
+ {
+ return _byteswap_ulong(val);
+ }
+ inline uint64_t byteswap(uint64_t val)
+ {
+ return _byteswap_uint64(val);
+ }
+ #elif defined(__GNUC__)
+ inline uint16_t byteswap(uint16_t val)
+ {
+ return bswap_16(val);
+ }
+ inline uint32_t byteswap(uint32_t val)
+ {
+ return bswap_32(val);
+ }
+ inline uint64_t byteswap(uint64_t val)
+ {
+ return bswap_64(val);
+ }
+ #else
+ #error "No platform-specific byteswap()" // TODO: do something else?
+ #endif
+ }
+
+ template
+ inline T byteswap(T n) noexcept
+ {
+ // "std::byteswap participates in overload resolution only if T satisfies integral, i.e., T is an integer type. The program is
+ // ill-formed if T has padding bits."
+ static_assert(std::is_integral::value, "T must be integral");
+
+ using unsigned_t = std::make_unsigned_t; // "Since C++14" https://en.cppreference.com/w/cpp/types/make_unsigned
+ return details::byteswap(static_cast(n));
+ }
}
#endif // CODA_OSS_coda_oss_bit_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/cstddef.h b/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/cstddef.h
index 53eb7ac33..d9320e054 100644
--- a/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/cstddef.h
+++ b/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/cstddef.h
@@ -22,7 +22,10 @@
#define CODA_OSS_coda_oss_cstddef_h_INCLUDED_
#pragma once
+#include
+
#include
+#include
// Need a fairly decent C++ compiler to use the real GSL. This brings in more than
// we really need for span (e.g., gsl::narrow()), but it keeps things simple.
@@ -32,5 +35,6 @@ namespace coda_oss
{
using byte = std::byte;
}
+static_assert(!std::is_same::value, "'coda_oss::byte' should be a unique type.");
#endif // CODA_OSS_coda_oss_cstddef_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/span.h b/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/span.h
index c33375c3e..b225f35fe 100644
--- a/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/span.h
+++ b/externals/coda-oss/modules/c++/coda_oss/include/coda_oss/span.h
@@ -25,6 +25,7 @@
#include "coda_oss/namespace_.h"
#include "coda_oss/span_.h"
+#include "coda_oss/cstddef.h" // byte
// Need a fairly decent C++ compiler to use the real GSL. This brings in more than
// we really need for span (e.g., gsl::narrow()), but it keeps things simple.
@@ -37,6 +38,26 @@ namespace coda_oss
#else // no gsl::span, use our own
using details::span;
#endif // GSL_SPAN_H
+
+// https://en.cppreference.com/w/cpp/container/span/as_bytes
+template
+span as_bytes(span s) noexcept
+{
+ const void* const p = s.data();
+ return span(static_cast(p), s.size_bytes());
+}
+template
+span as_bytes(span s) noexcept
+{
+ return as_bytes(span(s.data(), s.size()));
+}
+template
+span as_writable_bytes(span s) noexcept
+{
+ void* const p = s.data();
+ return span(static_cast(p), s.size_bytes());
+}
+
}
#endif // CODA_OSS_coda_oss_span_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/mem/unittests/test_Span.cpp b/externals/coda-oss/modules/c++/mem/unittests/test_Span.cpp
index 472a87992..28a76ad20 100644
--- a/externals/coda-oss/modules/c++/mem/unittests/test_Span.cpp
+++ b/externals/coda-oss/modules/c++/mem/unittests/test_Span.cpp
@@ -26,6 +26,7 @@
#include
#include
+#include
#include "TestCase.h"
@@ -94,8 +95,43 @@ TEST_CASE(testGslNarrow)
TEST_THROWS(gsl::narrow(d));
}
+TEST_CASE(test_sys_make_span)
+{
+ int i = 314;
+ int* const p = &i;
+ auto s = sys::make_span(p, 1);
+ TEST_ASSERT(s.data() == p);
+ TEST_ASSERT_EQ(s[0], i);
+ s[0] = 123;
+ TEST_ASSERT_EQ(i, 123);
+ s[0] = 314;
+
+ const int* const q = &i;
+ auto cs = sys::make_span(q, 1);
+ TEST_ASSERT(cs.data() == q);
+ TEST_ASSERT_EQ(cs[0], i);
+ //cs[0] = 123; // cs = span
+ TEST_ASSERT_EQ(i, 314);
+
+ std::vector v{314};
+ s = sys::make_span(v);
+ TEST_ASSERT(s.data() == v.data());
+ TEST_ASSERT_EQ(s[0], v[0]);
+ s[0] = 123;
+ TEST_ASSERT_EQ(v[0], 123);
+ s[0] = 314;
+
+ const std::vector& u = v;
+ cs = sys::make_span(u);
+ TEST_ASSERT(cs.data() == u.data());
+ TEST_ASSERT_EQ(cs[0], u[0]);
+ // cs[0] = 123; // cs = span
+ TEST_ASSERT_EQ(u[0], 314);
+}
+
TEST_MAIN(
TEST_CHECK(testSpanBuffer);
TEST_CHECK(testSpanVector);
TEST_CHECK(testGslNarrow);
+ TEST_CHECK(test_sys_make_span);
)
diff --git a/externals/coda-oss/modules/c++/mt/include/mt/ThreadedByteSwap.h b/externals/coda-oss/modules/c++/mt/include/mt/ThreadedByteSwap.h
new file mode 100644
index 000000000..0b97e1171
--- /dev/null
+++ b/externals/coda-oss/modules/c++/mt/include/mt/ThreadedByteSwap.h
@@ -0,0 +1,90 @@
+#ifndef CODA_OSS_mt_ThreadedByteSwap_h_INCLUDED_
+#define CODA_OSS_mt_ThreadedByteSwap_h_INCLUDED_
+#pragma once
+
+#include
+
+#include "sys/ByteSwap.h"
+
+#include "ThreadPlanner.h"
+#include "ThreadGroup.h"
+
+namespace mt
+{
+/*
+ * Threaded byte-swapping
+ *
+ * \param buffer Buffer to swap (contents will be overridden)
+ * \param elemSize Size of each element in 'buffer'
+ * \param numElements Number of elements in 'buffer'
+ * \param numThreads Number of threads to use for byte-swapping
+ */
+inline void threadedByteSwap(void* buffer, size_t elemSize, size_t numElements, size_t numThreads)
+{
+ if (numThreads <= 1)
+ {
+ sys::byteSwap(buffer, elemSize, numElements);
+ }
+ else
+ {
+ mt::ThreadGroup threads;
+ const mt::ThreadPlanner planner(numElements, numThreads);
+
+ size_t threadNum(0);
+ size_t startElement(0);
+ size_t numElementsThisThread(0);
+ while (planner.getThreadInfo(threadNum++, startElement, numElementsThisThread))
+ {
+ auto thread = std::make_unique(
+ buffer,
+ elemSize,
+ startElement,
+ numElementsThisThread);
+
+ threads.createThread(thread.release());
+ }
+ threads.joinAll();
+ }
+}
+
+/*
+ * Threaded byte-swapping and copy
+ *
+ * \param buffer Buffer to swap
+ * \param elemSize Size of each element in 'buffer'
+ * \param numElements Number of elements in 'buffer'
+ * \param numThreads Number of threads to use for byte-swapping
+ * \param outputBuffer buffer to write into
+ */
+inline void threadedByteSwap(const void* buffer, size_t elemSize, size_t numElements, size_t numThreads, void* outputBuffer)
+{
+ if (numThreads <= 1)
+ {
+ sys::byteSwap(buffer, elemSize, numElements, outputBuffer);
+ }
+ else
+ {
+ mt::ThreadGroup threads;
+ const mt::ThreadPlanner planner(numElements, numThreads);
+
+ size_t threadNum(0);
+ size_t startElement(0);
+ size_t numElementsThisThread(0);
+ while (planner.getThreadInfo(threadNum++, startElement, numElementsThisThread))
+ {
+ auto thread = std::make_unique(
+ buffer,
+ elemSize,
+ startElement,
+ numElementsThisThread,
+ outputBuffer);
+
+ threads.createThread(thread.release());
+ }
+ threads.joinAll();
+
+ }
+}
+}
+
+#endif // CODA_OSS_mt_ThreadedByteSwap_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/mt/unittests/test_mt_byte_swap.cpp b/externals/coda-oss/modules/c++/mt/unittests/test_mt_byte_swap.cpp
new file mode 100644
index 000000000..d2099cf83
--- /dev/null
+++ b/externals/coda-oss/modules/c++/mt/unittests/test_mt_byte_swap.cpp
@@ -0,0 +1,72 @@
+/* =========================================================================
+ * This file is part of mt-c++
+ * =========================================================================
+ *
+ * (C) Copyright 2004 - 2017, MDA Information Systems LLC
+ *
+ * sys-c++ is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; If not,
+ * see .
+ *
+ */
+
+#include "TestCase.h"
+
+#include
+
+#include
+#include // std::byte
+#include
+
+#include
+
+static std::vector make_origValues(size_t NUM_PIXELS)
+{
+ ::srand(334);
+
+ std::vector retval(NUM_PIXELS);
+ for (size_t ii = 0; ii < NUM_PIXELS; ++ii)
+ {
+ const auto value = static_cast(::rand()) / RAND_MAX *
+ std::numeric_limits::max();
+ retval[ii] = static_cast(value);
+ }
+ return retval;
+}
+
+TEST_CASE(testThreadedByteSwap)
+{
+ constexpr size_t NUM_PIXELS = 10000;
+ const auto origValues = make_origValues(NUM_PIXELS);
+
+ constexpr size_t numThreads = 4;
+
+ // Byte swap the old-fashioned way
+ auto values1(origValues);
+ mt::threadedByteSwap(values1.data(), sizeof(values1[0]), NUM_PIXELS, numThreads);
+
+ // Byte swap into output buffer
+ std::vector swappedValues2(origValues.size());
+ mt::threadedByteSwap(origValues.data(), sizeof(origValues[0]), NUM_PIXELS, numThreads, swappedValues2.data());
+
+ // Everything should match
+ for (size_t ii = 0; ii < NUM_PIXELS; ++ii)
+ {
+ TEST_ASSERT_EQ(values1[ii], swappedValues2[ii]);
+ }
+}
+
+TEST_MAIN(
+ TEST_CHECK(testThreadedByteSwap);
+ )
+
\ No newline at end of file
diff --git a/externals/coda-oss/modules/c++/std/include/std/bit b/externals/coda-oss/modules/c++/std/include/std/bit
index d564c0020..dbcc0b6c5 100644
--- a/externals/coda-oss/modules/c++/std/include/std/bit
+++ b/externals/coda-oss/modules/c++/std/include/std/bit
@@ -28,7 +28,7 @@
// Make it (too?) easy for clients to get our various std:: implementations
#ifndef CODA_OSS_NO_std_endian
#if CODA_OSS_cpp20
- // Some implementations cliam to be C++20 w/o
+ // Some implementations claim to be C++20 w/o
#if __has_include() // __has_include is C++17
#include
#define CODA_OSS_NO_std_endian 1 // provided by implementation, probably C++20
@@ -47,4 +47,22 @@ namespace std // This is slightly uncouth: we're not supposed to augment "std".
}
#endif // CODA_OSS_NO_std_endian
+// Make it (too?) easy for clients to get our various std:: implementations
+#ifndef CODA_OSS_NO_std_byteswap
+ #if CODA_OSS_cpp23
+ #include
+ #define CODA_OSS_NO_std_byteswap 1 // provided by implementation, probably C++23
+ #endif
+ #ifndef CODA_OSS_NO_std_byteswap
+ #define CODA_OSS_NO_std_byteswap 0 // <= C++20, use our own
+ #endif
+#endif
+
+#if !CODA_OSS_NO_std_byteswap
+namespace std // This is slightly uncouth: we're not supposed to augment "std".
+{
+ using coda_oss::byteswap;
+}
+#endif // CODA_OSS_NO_std_byteswap
+
#endif // CODA_OSS_std_bit_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/std/include/std/span b/externals/coda-oss/modules/c++/std/include/std/span
index ffa0d1df9..819befe15 100644
--- a/externals/coda-oss/modules/c++/std/include/std/span
+++ b/externals/coda-oss/modules/c++/std/include/std/span
@@ -39,6 +39,9 @@
namespace std // This is slightly uncouth: we're not supposed to augment "std".
{
using coda_oss::span;
+
+ using coda_oss::as_bytes;
+ using coda_oss::as_writable_bytes;
}
#endif // CODA_OSS_DEFINE_std_span_
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/AbstractOS.h b/externals/coda-oss/modules/c++/sys/include/sys/AbstractOS.h
index 158bce489..3c8a6b0e6 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/AbstractOS.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/AbstractOS.h
@@ -99,6 +99,11 @@ struct CODA_OSS_API AbstractOS
const std::string& fragment = "",
const std::string& extension = "",
bool recursive = true) const;
+ std::vector search(
+ const std::vector& searchPaths,
+ const std::string& fragment = "",
+ const std::string& extension = "",
+ bool recursive = true) const;
/*!
* Does this path exist?
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/ByteSwap.h b/externals/coda-oss/modules/c++/sys/include/sys/ByteSwap.h
new file mode 100644
index 000000000..d8145dcce
--- /dev/null
+++ b/externals/coda-oss/modules/c++/sys/include/sys/ByteSwap.h
@@ -0,0 +1,118 @@
+/* =========================================================================
+ * This file is part of sys-c++
+ * =========================================================================
+ *
+ * (C) Copyright 2004 - 2014, MDA Information Systems LLC
+ * (C) Copyright 2023, Maxar Technologies, Inc.
+ *
+ * sys-c++ is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; If not,
+ * see .
+ *
+ */
+
+#ifndef CODA_OSS_sys_ByteSwap_h_INCLUDED_
+#define CODA_OSS_sys_ByteSwap_h_INCLUDED_
+#pragma once
+
+#include
+#include
+
+#include
+#include
+
+#include "config/Exports.h"
+
+#include "ByteSwapValue.h"
+#include "Runnable.h"
+
+namespace sys
+{
+/*!
+ * Swap bytes in-place. Note that a complex pixel
+ * is equivalent to two floats so elemSize and numElems
+ * must be adjusted accordingly.
+ *
+ * \param [inout] buffer to transform
+ * \param elemSize
+ * \param numElems
+ */
+coda_oss::span CODA_OSS_API byteSwap(coda_oss::spanbuffer, size_t elemSize);
+void CODA_OSS_API byteSwap(void* buffer, size_t elemSize, size_t numElems);
+
+/*!
+ * Swap bytes into output buffer. Note that a complex pixel
+ * is equivalent to two floats so elemSize and numElems
+ * must be adjusted accordingly.
+ *
+ * \param buffer to transform
+ * \param elemSize
+ * \param numElems
+ * \param[out] outputBuffer buffer to write swapped elements to
+ */
+coda_oss::span CODA_OSS_API byteSwap(coda_oss::span buffer,
+ size_t elemSize, coda_oss::span outputBuffer);
+void CODA_OSS_API byteSwap(const void* buffer, size_t elemSize, size_t numElems, void* outputBuffer);
+
+struct ByteSwapRunnable final : public sys::Runnable
+{
+ ByteSwapRunnable(void* buffer, size_t elemSize, size_t startElement, size_t numElements) :
+ mBuffer(static_cast(buffer) + startElement * elemSize),
+ mElemSize(elemSize), mNumElements(numElements)
+ {
+ }
+ void run() override
+ {
+ byteSwap(mBuffer, mElemSize, mNumElements);
+ }
+
+ virtual ~ByteSwapRunnable() = default;
+ ByteSwapRunnable(const ByteSwapRunnable&) = delete;
+ ByteSwapRunnable& operator=(const ByteSwapRunnable&) = delete;
+ ByteSwapRunnable(ByteSwapRunnable&&) = delete;
+ ByteSwapRunnable& operator=(ByteSwapRunnable&&) = delete;
+
+private:
+ void* const mBuffer;
+ const size_t mElemSize;
+ const size_t mNumElements;
+};
+
+struct ByteSwapCopyRunnable final : public sys::Runnable
+{
+ ByteSwapCopyRunnable(const void* buffer, size_t elemSize, size_t startElement, size_t numElements, void* outputBuffer) :
+ mBuffer(static_cast(buffer) + startElement * elemSize),
+ mElemSize(elemSize), mNumElements(numElements),
+ mOutputBuffer(static_cast(outputBuffer) + startElement * elemSize)
+ {
+ }
+ void run() override
+ {
+ byteSwap(mBuffer, mElemSize, mNumElements, mOutputBuffer);
+ }
+
+ virtual ~ByteSwapCopyRunnable() = default;
+ ByteSwapCopyRunnable(const ByteSwapCopyRunnable&) = delete;
+ ByteSwapCopyRunnable& operator=(const ByteSwapCopyRunnable&) = delete;
+ ByteSwapCopyRunnable(ByteSwapCopyRunnable&&) = delete;
+ ByteSwapCopyRunnable& operator=(ByteSwapCopyRunnable&&) = delete;
+
+private:
+ const void* const mBuffer;
+ const size_t mElemSize;
+ const size_t mNumElements;
+ void* const mOutputBuffer;
+};
+
+}
+#endif // CODA_OSS_sys_ByteSwap_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/ByteSwapValue.h b/externals/coda-oss/modules/c++/sys/include/sys/ByteSwapValue.h
new file mode 100644
index 000000000..57cffe3f3
--- /dev/null
+++ b/externals/coda-oss/modules/c++/sys/include/sys/ByteSwapValue.h
@@ -0,0 +1,196 @@
+/* =========================================================================
+ * This file is part of sys-c++
+ * =========================================================================
+ *
+ * (C) Copyright 2004 - 2014, MDA Information Systems LLC
+ * (C) Copyright 2021, Maxar Technologies, Inc.
+ *
+ * sys-c++ is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; If not,
+ * see .
+ *
+ */
+
+#ifndef CODA_OSS_sys_ByteSwapValue_h_INCLUDED_
+#define CODA_OSS_sys_ByteSwapValue_h_INCLUDED_
+#pragma once
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "config/Exports.h"
+
+#include "Span.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace sys
+{
+ /*!
+ * Swap bytes for a single value into output buffer. API is `span` rather than `void*` since
+ * for a single value we know the size. These "low level" routines may be less efficient than
+ * the templates since it's not possible to specialize on a specific size.
+ *
+ * \param buffer to transform
+ * \param[out] outputBuffer buffer to write swapped elements to
+ */
+ coda_oss::span CODA_OSS_API byteSwap(
+ coda_oss::span pIn, coda_oss::span outPtr);
+
+ namespace details
+ {
+ template
+ inline auto swapUIntBytes(coda_oss::span inBytes, coda_oss::span outBytes,
+ std::nothrow_t) noexcept
+ {
+ static_assert(std::is_unsigned::value, "TUInt must be 'unsigned'");
+ assert(sizeof(TUInt) == inBytes.size());
+ assert(inBytes.size() == outBytes.size());
+
+ const void* const pIn_ = inBytes.data();
+ auto const pIn = static_cast(pIn_);
+ void* const pOut_ = outBytes.data();
+ auto const pOut = static_cast(pOut_);
+
+ *pOut = coda_oss::byteswap(*pIn); // at long last, swap the bytes
+
+ // Give the raw byte-swapped bytes back to the caller for easy serialization
+ return as_bytes(pOut);
+ }
+ template
+ inline auto swapUIntBytes(coda_oss::span inBytes, coda_oss::span outBytes)
+ {
+ if (sizeof(TUInt) != inBytes.size())
+ {
+ throw std::invalid_argument("'inBytes.size() != sizeof(TUInt)");
+ }
+ if (inBytes.size() != outBytes.size())
+ {
+ throw std::invalid_argument("'inBytes.size() != outBytes.size()");
+ }
+ return swapUIntBytes(inBytes, outBytes, std::nothrow);
+ }
+
+ // This is a template so that we can have specializations for different sizes.
+ // By specializing on `size_t`, a `float` can be "cast" to `uint32_t` (via
+ // `std::byte`) for byte-swapping.
+ template
+ inline auto swapBytes(coda_oss::span inBytes, coda_oss::span outBytes)
+ {
+ if (elemSize != inBytes.size())
+ {
+ throw std::invalid_argument("'inBytes.size() != elemSize");
+ }
+ return sys::byteSwap(inBytes, outBytes); // size that wasn't specialized
+ }
+
+ // avoid copy-paste errors
+ #define CODA_OSS_define_swapBytes_specialization_(T) template <> inline auto swapBytes \
+ (coda_oss::span inBytes, coda_oss::span outBytes) { return swapUIntBytes(inBytes, outBytes); }
+ CODA_OSS_define_swapBytes_specialization_(uint8_t) // no `;`, it's not needed and generates a -Wpedantic warning
+ CODA_OSS_define_swapBytes_specialization_(uint16_t)
+ CODA_OSS_define_swapBytes_specialization_(uint32_t)
+ CODA_OSS_define_swapBytes_specialization_(uint64_t)
+ #undef CODA_OSS_define_swapBytes_specialization_
+
+ template
+ inline constexpr bool is_byte_swappable() noexcept
+ {
+ // Trying to byte-swap anything other than integers is likely to cause
+ // problems (or at least confusion):
+ // * `struct`s have padding that should be ignored.
+ // * each individual member of a `struct` should be byte-swaped
+ // * byte-swaped `float` or `double` bits are nonsense
+ return (std::is_integral::value || std::is_enum::value) || !std::is_compound::value;
+ }
+ }
+
+ /*!
+ * Function to swap one element irrespective of size.
+ * Returns the raw byte-swapped bytes for easy serialization.
+ */
+ template
+ inline auto swapBytes(coda_oss::span inBytes, coda_oss::span outBytes)
+ {
+ static_assert(details::is_byte_swappable(), "T should not be a 'struct'");
+ return details::swapBytes(inBytes, outBytes);
+ }
+ template
+ inline auto swapBytes(T in, coda_oss::span outBytes)
+ {
+ return swapBytes(as_bytes(in), outBytes);
+ }
+ template
+ inline auto swapBytes(T in)
+ {
+ std::vector retval;
+ retval.resize(sizeof(T));
+ std::ignore = swapBytes(in, make_span(retval));
+ return retval;
+ }
+
+ // Reverse the above: turn `span` back to T after byte-swapping
+ template
+ inline auto swapBytes(coda_oss::span in)
+ {
+ // Don't want to cast the swapped bytes in `in` to T* as they might not be valid;
+ // e.g., a byte-swapped `float` could be garbage.
+ T retval;
+ swapBytes(in, as_writable_bytes(retval));
+ return retval;
+ }
+
+ /*!
+ * Function to swap one element irrespective of size. The inplace
+ * buffer function should be preferred.
+ *
+ * To specialize complex float, first include the complex library
+ * \code
+ #include
+ * \endcode
+ *
+ * Then put an overload in as specified below:
+ * \code
+ template std::complex byteSwap(std::complex val)
+ {
+ std::complex out(byteSwap(val.real()),
+ byteSwap(val.imag()));
+ return out;
+ }
+ * \endcode
+ *
+ */
+ template inline T byteSwap(T val)
+ {
+ T out;
+ std::ignore = swapBytes(val, as_writable_bytes(out));
+ return out;
+ }
+}
+#endif // CODA_OSS_sys_ByteSwapValue_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/Conf.h b/externals/coda-oss/modules/c++/sys/include/sys/Conf.h
index 28d396c5c..df36708bb 100644
--- a/externals/coda-oss/modules/c++/sys/include/sys/Conf.h
+++ b/externals/coda-oss/modules/c++/sys/include/sys/Conf.h
@@ -66,23 +66,16 @@
#include
#include
#include
-#include
-#ifdef __GNUC__
-#include // "These functions are GNU extensions."
-#endif
#include
#include
#include
#include
#include
-#include
-#include
-#include "coda_oss/span.h"
-#include
#include "str/Format.h"
#include "sys/TimeStamp.h"
+#include "sys/ByteSwap.h"
/* Dance around the compiler to figure out */
@@ -205,205 +198,9 @@ namespace sys
* RISC architectures we are big-endian.
*/
bool CODA_OSS_API isBigEndianSystem();
+ bool CODA_OSS_API isLittleEndianSystem();
- /*!
- * Swap bytes in-place. Note that a complex pixel
- * is equivalent to two floats so elemSize and numElems
- * must be adjusted accordingly.
- *
- * \param [inout] buffer to transform
- * \param elemSize
- * \param numElems
- */
- void CODA_OSS_API byteSwap_(void* buffer, size_t elemSize, size_t numElems);
- template
- inline void byteSwap(T* buffer, size_t elemSize, size_t numElems)
- {
- // Trying to byte-swap structs can result in garbage because of padding.
- static_assert(std::is_arithmetic::value || std::is_enum::value, "can only byte-swap numbers.");
- if (elemSize != sizeof(T))
- {
- throw std::invalid_argument("sizeof(T) != elemSize");
- }
- byteSwap_(buffer, elemSize, numElems);
- }
- template
- inline void byteSwap(coda_oss::span buffer)
- {
- constexpr auto elemSize = sizeof(T);
- const auto numElems = buffer.size();
- byteSwap(buffer.data(), elemSize, numElems);
- }
- template
- inline void byteSwap(coda_oss::span> buffer)
- {
- void* pBuffer = buffer.data();
- const coda_oss::span buffer_(static_cast(pBuffer), buffer.size() * 2); // real and imag
- byteSwap(buffer_);
- }
-
- inline void byteSwapV(void* buffer, unsigned short elemSize, size_t numElems) // existing API
- {
- byteSwap_(buffer, elemSize, numElems);
- }
-
- /*!
- * Swap bytes into output buffer. Note that a complex pixel
- * is equivalent to two floats so elemSize and numElems
- * must be adjusted accordingly.
- *
- * \param buffer to transform
- * \param elemSize
- * \param numElems
- * \param[out] outputBuffer buffer to write swapped elements to
- */
- void CODA_OSS_API byteSwap_(const void* buffer, size_t elemSize, size_t numElems, void* outputBuffer);
- template
- inline void byteSwap(const T* buffer, size_t elemSize, size_t numElems,
- U* outputBuffer) // e.g., "unsigned int" && "int"
- {
- // Trying to byte-swap structs can result in garbage because of padding.
- static_assert(std::is_arithmetic::value || std::is_enum::value, "can only byte-swap numbers.");
- static_assert(std::is_arithmetic::value || std::is_enum::value, "can only byte-swap numbers.");
- static_assert(sizeof(T) > 1, "byte-swapping a single-byte value makes no sense.");
- //static_assert(sizeof(T) == sizeof(U), "sizeof(T) != sizeof(U)."); // outputBuffer could be std::byte
- if (elemSize != sizeof(T))
- {
- throw std::invalid_argument("sizeof(T) != elemSize");
- }
- byteSwap_(buffer, elemSize, numElems, outputBuffer);
- }
- template
- inline void byteSwap(coda_oss::span buffer, coda_oss::span outputBuffer) // e.g., "unsigned int" && "int"
- {
- const auto numElems = buffer.size();
- if (numElems != outputBuffer.size())
- {
- throw std::invalid_argument("buffer.size() != outputBuffer.size()");
- }
- constexpr auto elemSize = sizeof(T);
- byteSwap(buffer.data(), elemSize, numElems, outputBuffer.data());
- }
- template
- inline void byteSwap(coda_oss::span> buffer, coda_oss::span> outputBuffer)
- {
- const void* pBuffer = buffer.data();
- const coda_oss::span buffer_(static_cast(pBuffer), buffer.size() * 2); // real and imag
- void* pOutputBuffer = outputBuffer.data();
- const coda_oss::span outputBuffer_(static_cast(pOutputBuffer), outputBuffer.size() * 2); // real and imag
-
- byteSwap(buffer_, outputBuffer_);
- }
-
- inline void byteSwapV(const void* buffer, unsigned short elemSize, size_t numElems, void* outputBuffer) // existing API
- {
- byteSwap_(buffer, elemSize, numElems, outputBuffer);
- }
-
- /*!
- * Function to swap one element irrespective of size. The inplace
- * buffer function should be preferred.
- *
- * To specialize complex float, first include the complex library
- * \code
- #include
- * \endcode
- *
- * Then put an overload in as specified below:
- * \code
- template std::complex byteSwap(std::complex val)
- {
- std::complex out(byteSwap(val.real()),
- byteSwap(val.imag()));
- return out;
- }
- * \endcode
- *
- */
- template inline T byteSwap_(T val)
- {
- // Trying to byte-swap structs can result in garbage because of padding.
- static_assert(std::is_arithmetic::value || std::is_enum::value, "can only byte-swap numbers");
-
- constexpr auto size = sizeof(T);
- T out;
-
- unsigned char* cOut = reinterpret_cast(&out);
- unsigned char* cIn = reinterpret_cast(&val);
- for (size_t i = 0, j = size - 1; i < j; ++i, --j)
- {
- cOut[i] = cIn[j];
- cOut[j] = cIn[i];
- }
- return out;
- }
- template inline T byteSwap(T val)
- {
- return byteSwap_(val);
- }
- inline uint8_t byteSwap(uint8_t val)
- {
- return val; // no-op
- }
-#if defined(_MSC_VER)
- // These routines should geneerate a single instruction; see https://devblogs.microsoft.com/cppblog/a-tour-of-4-msvc-backend-improvements/
- inline uint16_t byteSwap(uint16_t val)
- {
- return _byteswap_ushort(val);
- }
- inline uint32_t byteSwap(uint32_t val)
- {
- return _byteswap_ulong(val);
- }
- inline uint64_t byteSwap(uint64_t val)
- {
- return _byteswap_uint64(val);
- }
-#elif defined(__GNUC__)
- inline uint16_t byteSwap(uint16_t val)
- {
- return bswap_16(val);
- }
- inline uint32_t byteSwap(uint32_t val)
- {
- return bswap_32(val);
- }
- inline uint64_t byteSwap(uint64_t val)
- {
- return bswap_64(val);
- }
-#endif
- template
- inline T byteSwapValue_(T val)
- {
- static_assert(sizeof(T) > 1, "byte-swapping a single-byte value makes no sense.");
- static_assert(sizeof(T) == sizeof(TUInt), "sizeof(T) != sizeof()");
- static_assert(std::is_unsigned::value, "TUInt must be 'unsigned'");
-
- const void* pVal = &val;
- const auto pUInt = static_cast(pVal);
- const auto result = byteSwap(*pUInt);
-
- const void* pResult = &result;
- const auto pRetval = static_cast(pResult);
- return *pRetval;
- }
- inline float byteSwap(float val)
- {
- return byteSwapValue_(val);
- }
- inline double byteSwap(double val)
- {
- return byteSwapValue_(val);
- }
- template
- inline std::complex byteSwap(std::complex v)
- {
- std::complex retval{byteSwap(v.real()), byteSwap(v.imag())};
- return retval;
- }
-
/*!
* Method to create a block of memory on an alignment
* boundary specified by the user.
@@ -459,7 +256,6 @@ namespace sys
#endif
}
-
}
// https://en.wikipedia.org/wiki/Year_2038_problem
diff --git a/externals/coda-oss/modules/c++/sys/include/sys/Span.h b/externals/coda-oss/modules/c++/sys/include/sys/Span.h
new file mode 100644
index 000000000..23b72d02c
--- /dev/null
+++ b/externals/coda-oss/modules/c++/sys/include/sys/Span.h
@@ -0,0 +1,188 @@
+/* =========================================================================
+ * This file is part of sys-c++
+ * =========================================================================
+ *
+ * (C) Copyright 2004 - 2014, MDA Information Systems LLC
+ * (C) Copyright 2023, Maxar Technologies, Inc.
+ *
+ * sys-c++ is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; If not,
+ * see .
+ *
+ */
+
+#ifndef CODA_OSS_sys_Span_h_INCLUDED_
+#define CODA_OSS_sys_Span_h_INCLUDED_
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace sys // not "mem", it depends on sys.
+{
+
+// Creating a `span` is verbose w/o deduction guidelines in C++17.
+// Some overloads to ease the pain.
+template
+inline coda_oss::span make_span(const T* ptr, size_t sz) noexcept
+{
+ return coda_oss::span(ptr, sz);
+}
+template
+inline coda_oss::span make_const_span(T* ptr, size_t sz) noexcept
+{
+ return coda_oss::span(ptr, sz);
+}
+template
+inline coda_oss::span make_writable_span(T* ptr, size_t sz) noexcept // c.f., as_writable_bytes()
+{
+ return coda_oss::span(ptr, sz);
+}
+template
+inline coda_oss::span make_span(T* ptr, size_t sz) noexcept
+{
+ return make_writable_span(ptr, sz);
+}
+
+template
+inline auto make_span(const void* ptr, size_t sz) noexcept
+{
+ return make_span(static_cast(ptr), sz);
+}
+template
+inline auto make_const_span(void* ptr, size_t sz) noexcept
+{
+ return make_const_span(static_cast(ptr), sz);
+}
+template
+inline auto make_span(void* ptr, size_t sz) noexcept
+{
+ return make_writable_span(static_cast(ptr), sz);
+}
+
+template
+inline auto make_const_span(coda_oss::span v) noexcept // turn span into span
+{
+ return make_const_span(v.data(), v.size());
+}
+
+template
+inline auto make_span(const std::vector& v) noexcept
+{
+ return make_span(v.data(), v.size());
+}
+template
+inline auto make_const_span(std::vector& v) noexcept
+{
+ return make_const_span(v.data(), v.size());
+}
+template
+inline auto make_span(std::vector& v) noexcept
+{
+ return make_writable_span(v.data(), v.size());
+}
+
+template
+inline auto make_span(const std::array& v) noexcept
+{
+ return make_span(v.data(), v.size());
+}
+template
+inline auto make_const_span(std::array& v) noexcept
+{
+ return make_const_span(v.data(), v.size());
+}
+template
+inline auto make_span(std::array& v) noexcept
+{
+ return make_writable_span(v.data(), v.size());
+}
+
+template
+inline auto make_span(const T (&a)[N]) noexcept
+{
+ return make_span(a, N);
+}
+template
+inline auto make_const_span(T (&a)[N]) noexcept
+{
+ return make_const_span(a, N);
+}
+template
+inline auto make_span(T (&a)[N]) noexcept
+{
+ return make_writable_span(a, N);
+}
+
+// Calling as_bytes() or as_writable_bytes() requires a span, which as
+// noted above is a nuisance to create w/o C++17
+template
+inline auto as_bytes(const T* ptr, size_t sz) noexcept
+{
+ return coda_oss::as_bytes(make_span(ptr, sz));
+}
+template
+inline auto as_writable_bytes(T* ptr, size_t sz) noexcept
+{
+ return coda_oss::as_writable_bytes(make_writable_span(ptr, sz));
+}
+
+template
+inline auto as_bytes(const std::vector& v) noexcept
+{
+ return as_bytes(v.data(), v.size());
+}
+template
+inline auto as_writable_bytes(std::vector& v) noexcept
+{
+ return as_writable_bytes(v.data(), v.size());
+}
+
+template
+inline auto as_bytes(const std::array& v) noexcept
+{
+ return as_bytes(v.data(), v.size());
+}
+template
+inline auto as_writable_bytes(std::array& v) noexcept
+{
+ return as_writable_bytes(v.data(), v.size());
+}
+
+template
+inline auto as_bytes(const T (&a)[N]) noexcept
+{
+ return as_bytes(a, N);
+}
+template
+inline auto as_writable_bytes(T (&a)[N]) noexcept
+{
+ return as_writable_bytes(a, N);
+}
+
+// "cast" a single value to bytes
+template
+inline auto as_bytes(const T& v) noexcept
+{
+ return as_bytes(&v, 1);
+}
+template
+inline auto as_writable_bytes(T& v) noexcept
+{
+ return as_writable_bytes(&v, 1);
+}
+
+}
+#endif // CODA_OSS_sys_Span_h_INCLUDED_
diff --git a/externals/coda-oss/modules/c++/sys/source/AbstractOS.cpp b/externals/coda-oss/modules/c++/sys/source/AbstractOS.cpp
index 549415680..ede2d6cce 100644
--- a/externals/coda-oss/modules/c++/sys/source/AbstractOS.cpp
+++ b/externals/coda-oss/modules/c++/sys/source/AbstractOS.cpp
@@ -28,6 +28,8 @@
#include