diff --git a/externals/coda-oss/.github/workflows/build_unittest.yml b/externals/coda-oss/.github/workflows/build_unittest.yml index 58fd636e9a..547282c851 100644 --- a/externals/coda-oss/.github/workflows/build_unittest.yml +++ b/externals/coda-oss/.github/workflows/build_unittest.yml @@ -1,3 +1,6 @@ +env: + CTEST_TIMEOUT: 120 + name: build_unittest on: @@ -46,10 +49,10 @@ jobs: - name: test # should run w/o install run: | cd target-Release - ctest -C Release --output-on-failure + ctest -C Release --output-on-failure --timeout $env:CTEST_TIMEOUT cd .. cd target-Debug - ctest -C Debug --output-on-failure + ctest -C Debug --output-on-failure --timeout $env:CTEST_TIMEOUT - name: install run: | cd target-Release @@ -132,7 +135,7 @@ jobs: # should run w/o install run: | cd target - ctest --output-on-failure + ctest --output-on-failure --timeout $CTEST_TIMEOUT - name: install run: | cd target @@ -141,7 +144,7 @@ jobs: build-linux-cmake: strategy: matrix: - os: [ubuntu-22.04] + os: [ubuntu-22.04, ubuntu-24.04] configuration: [Debug, Release] avx: [AVX512F] name: ${{ matrix.os }}-${{ matrix.configuration }}-${{ matrix.avx }}-CMake @@ -163,43 +166,45 @@ jobs: # should run w/o install run: | cd out - ctest --output-on-failure - - build-waf: - strategy: - matrix: - os: [windows-2019, ubuntu-22.04] - python-version: ['3.7'] - debugging: ['--enable-debugging', ''] - name: ${{ matrix.os }}-${{ matrix.python-version }}-waf${{ matrix.debugging }} - runs-on: ${{ matrix.os }} - steps: - - name: Skip Duplicate Actions - uses: fkirc/skip-duplicate-actions@v5.3.1 - - uses: actions/checkout@v4 # https://github.com/marketplace/actions/checkout - - name: Set up Python - uses: actions/setup-python@v5 # https://github.com/marketplace/actions/setup-python - with: - python-version: ${{ matrix.python-version }} - - name: configure_with_swig - if: ${{ matrix.os == 'ubuntu-22.04' }} - run: | - pip install numpy - mkdir install${{ matrix.os }}Waf-Github - python waf configure --prefix="$PWD/install${{ matrix.os }}Waf-Github" --enable-swig ${{ matrix.debugging }} - - name: configure_without_swig - if: ${{ matrix.os == 'windows-2019' }} - run: | - pip install numpy - mkdir install${{ matrix.os }}Waf-Github - python waf configure --prefix="$PWD/install${{ matrix.os }}Waf-Github" ${{ matrix.debugging }} - - name: build - run: | - python waf build - - name: install - run: | - python waf install - - name: test - run: | - python waf install --alltests + ctest --output-on-failure --timeout $CTEST_TIMEOUT +# Plan to remove waf soon - disable build and see who complains +# build-waf: +# strategy: +# matrix: +# os: [ +# # BROKEN: windows-latest, +# ubuntu-22.04] +# python-version: ['3.7'] +# debugging: ['--enable-debugging', ''] +# name: ${{ matrix.os }}-${{ matrix.python-version }}-waf${{ matrix.debugging }} +# runs-on: ${{ matrix.os }} +# steps: +# - name: Skip Duplicate Actions +# uses: fkirc/skip-duplicate-actions@v5.3.1 +# - uses: actions/checkout@v4 # https://github.com/marketplace/actions/checkout +# - name: Set up Python +# uses: actions/setup-python@v5 # https://github.com/marketplace/actions/setup-python +# with: +# python-version: ${{ matrix.python-version }} +# - name: configure_with_swig +# if: ${{ matrix.os == 'ubuntu-22.04' }} +# run: | +# pip install numpy +# mkdir install${{ matrix.os }}Waf-Github +# python waf configure --prefix="$PWD/install${{ matrix.os }}Waf-Github" --enable-swig ${{ matrix.debugging }} +# - name: configure_without_swig +# if: ${{ matrix.os == 'windows-latest' }} +# run: | +# pip install numpy +# mkdir install${{ matrix.os }}Waf-Github +# python waf configure --prefix="$PWD/install${{ matrix.os }}Waf-Github" ${{ matrix.debugging }} +# - name: build +# run: | +# python waf build +# - name: install +# run: | +# python waf install +# - name: test +# run: | +# python waf install --alltests diff --git a/externals/coda-oss/CMakeLists.txt b/externals/coda-oss/CMakeLists.txt index 65401e3490..45edf67f71 100644 --- a/externals/coda-oss/CMakeLists.txt +++ b/externals/coda-oss/CMakeLists.txt @@ -3,7 +3,7 @@ # Author: Scott A. Colcord cmake_minimum_required(VERSION 3.14) -project(coda-oss) +project(coda-oss VERSION 1.0.0) if (EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake") # build and package with conan @@ -16,7 +16,7 @@ endif() if (${CMAKE_PROJECT_NAME} STREQUAL coda-oss) # this is the top level project - # Allow other project to set different standard. + # Allow other project to set different standard. set(CMAKE_CXX_STANDARD 14) set(CXX_STANDARD_REQUIRED true) @@ -25,8 +25,9 @@ if (${CMAKE_PROJECT_NAME} STREQUAL coda-oss) if (MSVC) add_compile_options(/WX) # warnings as errors add_compile_options(/MP) # multi-processor compile - elseif (UNIX) + elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") add_compile_options(-Werror) # warnings as errors + add_compile_options(-Wno-error=c++20-compat) endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") @@ -38,6 +39,13 @@ if (${CMAKE_PROJECT_NAME} STREQUAL coda-oss) install(DIRECTORY "cmake/" DESTINATION "${CODA_STD_PROJECT_LIB_DIR}/cmake/" FILES_MATCHING PATTERN "*.cmake") + + # If the package version is defined, write a version file for find_package + set(version_file "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}ConfigVersion.cmake") + include(CMakePackageConfigHelpers) + write_basic_package_version_file(${version_file} VERSION ${CMAKE_PROJECT_VERSION} COMPATIBILITY SameMajorVersion) + install(FILES ${version_file} DESTINATION "lib/cmake") + endif() add_subdirectory("modules") diff --git a/externals/coda-oss/README.md b/externals/coda-oss/README.md index f5792fd50b..ff05d8d3e4 100644 --- a/externals/coda-oss/README.md +++ b/externals/coda-oss/README.md @@ -11,6 +11,8 @@ CODA is a set of modules, and each module, while complimentary to one another, has a very specific and largely independent purpose. +CODA follows [Semantic Versioning](https://semver.org/). + Building CODA -------------- diff --git a/externals/coda-oss/build/build.py b/externals/coda-oss/build/build.py index 833091fa1e..bdd34caa9e 100644 --- a/externals/coda-oss/build/build.py +++ b/externals/coda-oss/build/build.py @@ -1526,7 +1526,12 @@ def copytree_tgt(tsk): symlinks = tsk.symlinks if hasattr(tsk, 'ignore'): ignore = tsk.ignore - shutil.copytree(tsk.src, dest, symlinks, ignore) + + def copytree_helper(src, dst): + Logs.pprint('GREEN', f'- copy {dst} (from {src})') + shutil.copy2(src, dst) + + shutil.copytree(tsk.src, dest, symlinks, ignore, copy_function=copytree_helper) @task_gen @feature('install_as_tgt') diff --git a/externals/coda-oss/cmake/CodaBuild.cmake b/externals/coda-oss/cmake/CodaBuild.cmake index be841d3fee..9f57b5a7ec 100644 --- a/externals/coda-oss/cmake/CodaBuild.cmake +++ b/externals/coda-oss/cmake/CodaBuild.cmake @@ -275,14 +275,8 @@ function(coda_generate_package_config) "cmake/${CMAKE_PROJECT_NAME}Config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake" INSTALL_DESTINATION "lib/cmake" - PATH_VARS ${ARGN} - ) - #write_basic_package_version_file( - # ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake - # VERSION 1.2.3 - # COMPATIBILITY SameMajorVersion ) + PATH_VARS ${ARGN}) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake" - #"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}ConfigVersion.cmake" DESTINATION "lib/cmake") endif() endfunction() diff --git a/externals/coda-oss/modules/c++/CMakeLists.txt b/externals/coda-oss/modules/c++/CMakeLists.txt index 9db23eb77d..ed14083d6d 100644 --- a/externals/coda-oss/modules/c++/CMakeLists.txt +++ b/externals/coda-oss/modules/c++/CMakeLists.txt @@ -9,7 +9,7 @@ if (MSVC) # > extremely noisy and low-value warnings. In general, the STL does not attempt to be `/Wall` clean. string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") # add_compile_options(/W4) -elseif (UNIX) +elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") # https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html #add_compile_options(-Werror) # Make all warnings into errors add_compile_options(-Wall -Wextra -Wpedantic -pedantic-errors -Wunused) @@ -19,8 +19,6 @@ elseif (UNIX) add_compile_options(-Wsuggest-override) add_compile_options(-Woverloaded-virtual) #add_compile_options(-Warray-bounds) - add_compile_options(-Wduplicated-branches -Wduplicated-cond) - add_compile_options(-Wtrampolines) add_compile_options(-Wshadow) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast") #add_compile_options(-Wfloat-equal) @@ -30,7 +28,12 @@ elseif (UNIX) add_compile_options(-Wno-double-promotion) # implicit conversion of `float` to `double` is fine add_compile_options(-Wno-array-bounds) # TODO: fix the code! - add_compile_options(-Wno-maybe-uninitialized) # TODO: fix the code! + + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + add_compile_options(-Wduplicated-branches -Wduplicated-cond) + add_compile_options(-Wtrampolines) + add_compile_options(-Wno-maybe-uninitialized) # TODO: fix the code! + endif() # Need a newer compiler than GCC 9 #add_compile_options(-Wnrvo) diff --git a/externals/coda-oss/modules/c++/gsl/include/gsl/assert b/externals/coda-oss/modules/c++/gsl/include/gsl/assert index a6012048fc..4f9853d995 100644 --- a/externals/coda-oss/modules/c++/gsl/include/gsl/assert +++ b/externals/coda-oss/modules/c++/gsl/include/gsl/assert @@ -46,14 +46,15 @@ // Hopefully temporary until suppression standardization occurs // #if defined(__clang__) -#define GSL_SUPPRESS(x) [[gsl::suppress("x")]] -#else -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]] +#elif defined(_MSC_VER) && _MSC_VER >= 1950 +// Visual Studio versions after 2022 (_MSC_VER > 1944) support the justification message. +#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]] +#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__NVCC__) #define GSL_SUPPRESS(x) [[gsl::suppress(x)]] #else #define GSL_SUPPRESS(x) -#endif // _MSC_VER -#endif // __clang__ +#endif // defined(__clang__) #define GSL_STRINGIFY_DETAIL(x) #x #define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x) diff --git a/externals/coda-oss/modules/c++/gsl/include/gsl/byte b/externals/coda-oss/modules/c++/gsl/include/gsl/byte index 9231340b56..0ca2561381 100644 --- a/externals/coda-oss/modules/c++/gsl/include/gsl/byte +++ b/externals/coda-oss/modules/c++/gsl/include/gsl/byte @@ -18,18 +18,19 @@ #define GSL_BYTE_H // -// make suppress attributes work for some compilers +// make suppress attributes parse for some compilers // Hopefully temporary until suppression standardization occurs // #if defined(__clang__) -#define GSL_SUPPRESS(x) [[gsl::suppress("x")]] -#else -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]] +#elif defined(_MSC_VER) && _MSC_VER >= 1950 +// Visual Studio versions after 2022 (_MSC_VER > 1944) support the justification message. +#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]] +#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__NVCC__) #define GSL_SUPPRESS(x) [[gsl::suppress(x)]] #else #define GSL_SUPPRESS(x) -#endif // _MSC_VER -#endif // __clang__ +#endif // defined(__clang__) #include diff --git a/externals/coda-oss/modules/c++/logging/include/logging/Handler.h b/externals/coda-oss/modules/c++/logging/include/logging/Handler.h index a9df56434c..e9313e81f9 100644 --- a/externals/coda-oss/modules/c++/logging/include/logging/Handler.h +++ b/externals/coda-oss/modules/c++/logging/include/logging/Handler.h @@ -3,6 +3,7 @@ * ========================================================================= * * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * logging-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 @@ -28,6 +29,8 @@ #define CODA_OSS_logging_Handler_h_INCLUDED_ #include +#include + #include "config/Exports.h" #include "logging/LogRecord.h" #include "logging/Formatter.h" @@ -94,7 +97,7 @@ struct CODA_OSS_API Handler : public Filterer virtual void emitRecord(const LogRecord* record) = 0; LogLevel mLevel = LogLevel::LOG_NOTSET; - sys::Mutex mHandlerLock; + std::recursive_mutex mHandlerLock; Formatter* mFormatter = nullptr; StandardFormatter mDefaultFormatter; }; diff --git a/externals/coda-oss/modules/c++/logging/include/logging/Logger.h b/externals/coda-oss/modules/c++/logging/include/logging/Logger.h index 2b33c90658..a9e5c5dc99 100644 --- a/externals/coda-oss/modules/c++/logging/include/logging/Logger.h +++ b/externals/coda-oss/modules/c++/logging/include/logging/Logger.h @@ -3,6 +3,7 @@ * ========================================================================= * * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * logging-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 @@ -142,6 +143,14 @@ struct CODA_OSS_API Logger : public Filterer return mName; } + /*! + * Returns the current log level of the first handler, if any. Otherwise + * returns LogLevel::LOG_NOTSET. Note that each handler may have a + * different log level. However, the setLevel function changes the level + * of all handlers attached to this logger. + */ + LogLevel getLevel(); + //! Removes all handlers void reset(); diff --git a/externals/coda-oss/modules/c++/logging/source/Handler.cpp b/externals/coda-oss/modules/c++/logging/source/Handler.cpp index 52bd289c70..4362ac6ba5 100644 --- a/externals/coda-oss/modules/c++/logging/source/Handler.cpp +++ b/externals/coda-oss/modules/c++/logging/source/Handler.cpp @@ -3,6 +3,7 @@ * ========================================================================= * * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * logging-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 @@ -57,7 +58,7 @@ bool Handler::handle(const LogRecord* record) if (filter(record)) { //acquire lock - mt::CriticalSection lock(&mHandlerLock); + mt::CriticalSection lock(&mHandlerLock); try { emitRecord(record); diff --git a/externals/coda-oss/modules/c++/logging/source/Logger.cpp b/externals/coda-oss/modules/c++/logging/source/Logger.cpp index 3f38375374..3febfa68bb 100644 --- a/externals/coda-oss/modules/c++/logging/source/Logger.cpp +++ b/externals/coda-oss/modules/c++/logging/source/Logger.cpp @@ -3,6 +3,7 @@ * ========================================================================= * * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * logging-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 @@ -239,3 +240,16 @@ void logging::Logger::reset() } mHandlers.clear(); } + +logging::LogLevel logging::Logger::getLevel() +{ + LogLevel level = LogLevel::LOG_NOTSET; + if (!mHandlers.empty()) + { + Handler_T handler = mHandlers.front(); + level = handler.first->getLevel(); + } + + return level; +} + diff --git a/externals/coda-oss/modules/c++/logging/source/StreamHandler.cpp b/externals/coda-oss/modules/c++/logging/source/StreamHandler.cpp index 555522a800..2a208538fc 100644 --- a/externals/coda-oss/modules/c++/logging/source/StreamHandler.cpp +++ b/externals/coda-oss/modules/c++/logging/source/StreamHandler.cpp @@ -3,6 +3,7 @@ * ========================================================================= * * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * logging-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 @@ -111,7 +112,7 @@ void StreamHandler::write(const std::string& str) if (!str.empty()) { //acquire lock - mt::CriticalSection lock(&mHandlerLock); + mt::CriticalSection lock(&mHandlerLock); // write to stream mStream->write(str); diff --git a/externals/coda-oss/modules/c++/math.poly/include/math/poly/Fixed1D.h b/externals/coda-oss/modules/c++/math.poly/include/math/poly/Fixed1D.h index 51e17a6bd0..4aa010b62d 100644 --- a/externals/coda-oss/modules/c++/math.poly/include/math/poly/Fixed1D.h +++ b/externals/coda-oss/modules/c++/math.poly/include/math/poly/Fixed1D.h @@ -137,8 +137,8 @@ template class Fixed1D } } - inline size_t order() const { return _Order; } - inline size_t size() const { return _Order + 1; } + constexpr inline size_t order() const { return _Order; } + constexpr inline size_t size() const { return _Order + 1; } /*! * @@ -186,6 +186,36 @@ template class Fixed1D return rv; } + /*! + * Evaluate the 1st derivative of our polynomial at 'at' + */ + _T velocity(double at) const + { + _T rv{}; + double atPower = 1; + for (size_t i = 1; i <= _Order; i++) + { + rv += static_cast(i) * mCoef[i]*atPower; + atPower *= at; + } + return rv; + } + + /*! + * Evaluate the 2nd derivative of our polynomial at 'at' + */ + _T acceleration(double at) const + { + _T rv{}; + double atPower = 1; + for (size_t i = 2; i <= _Order; i++) + { + rv += static_cast((i - 1) * i) * mCoef[i]*atPower; + atPower *= at; + } + return rv; + } + /*! * Integrate between start and end * diff --git a/externals/coda-oss/modules/c++/math.poly/include/math/poly/Fixed2D.h b/externals/coda-oss/modules/c++/math.poly/include/math/poly/Fixed2D.h index 4e87fcd2e8..3f74702591 100644 --- a/externals/coda-oss/modules/c++/math.poly/include/math/poly/Fixed2D.h +++ b/externals/coda-oss/modules/c++/math.poly/include/math/poly/Fixed2D.h @@ -95,8 +95,10 @@ template class Fixed2D return *this; } - size_t orderX() const { return _OrderX; } - size_t orderY() const { return _OrderY; } + constexpr size_t orderX() const { return _OrderX; } + constexpr size_t orderY() const { return _OrderY; } + constexpr size_t sizeX() const { return _OrderX + 1; } + constexpr size_t sizeY() const { return _OrderY + 1; } inline const std::array, _OrderX+1>& coeffs() const { diff --git a/externals/coda-oss/modules/c++/math.poly/include/math/poly/OneD.hpp b/externals/coda-oss/modules/c++/math.poly/include/math/poly/OneD.hpp index c461e5ad7b..3552490285 100644 --- a/externals/coda-oss/modules/c++/math.poly/include/math/poly/OneD.hpp +++ b/externals/coda-oss/modules/c++/math.poly/include/math/poly/OneD.hpp @@ -155,17 +155,32 @@ OneD< math::linear::VectorN<3, double> >::derivative() const template _T -OneD<_T>::velocity(double x) const +OneD<_T>::velocity(double at) const { - return derivative()(x); + _T ret{}; + double atPwr = 1.0; + const auto sz = mCoef.size(); + for (size_t i = 1 ; i < sz; i++) + { + ret += static_cast(i) * mCoef[i]*atPwr; + atPwr *= at; + } + return ret; } template _T -OneD<_T>::acceleration(double x) const +OneD<_T>::acceleration(double at) const { - return derivative().derivative()(x); - + _T ret{}; + double atPwr = 1.0; + const auto sz = mCoef.size(); + for (size_t i = 2 ; i < sz; i++) + { + ret += static_cast(i * (i - 1)) * mCoef[i]*atPwr; + atPwr *= at; + } + return ret; } template diff --git a/externals/coda-oss/modules/c++/math.poly/unittests/test_1d_poly.cpp b/externals/coda-oss/modules/c++/math.poly/unittests/test_1d_poly.cpp index d88b7f584e..1793b67747 100644 --- a/externals/coda-oss/modules/c++/math.poly/unittests/test_1d_poly.cpp +++ b/externals/coda-oss/modules/c++/math.poly/unittests/test_1d_poly.cpp @@ -146,9 +146,83 @@ TEST_CASE(testTransformInput) } } +TEST_CASE(testVelocity) +{ + std::vector values; + getRandValues(values); + + // Constant poly should have 0 velocity + math::poly::OneD poly(getRandPoly(0)); + for (const auto& val: values) + { + TEST_ASSERT_EQ(poly.velocity(val), 0.0); + } + + // Linear poly should have constant velocity + poly = getRandPoly(1); + for (const auto& val: values) + { + TEST_ASSERT_EQ(poly.velocity(val), poly[1]); + } + + // Check quadratic and cubic against the derivative + poly = getRandPoly(2); + for (const auto& val: values) + { + TEST_ASSERT_EQ(poly.velocity(val), poly.derivative()(val)); + } + + poly = getRandPoly(3); + for (const auto& val: values) + { + TEST_ASSERT_EQ(poly.velocity(val), poly.derivative()(val)); + } +} + +TEST_CASE(testAcceleration) +{ + std::vector values; + getRandValues(values); + + // Constant and linear polys should have 0 acceleration + math::poly::OneD poly(getRandPoly(0)); + for (const auto& val: values) + { + TEST_ASSERT_EQ(poly.acceleration(val), 0.0); + } + + poly = getRandPoly(1); + for (const auto& val: values) + { + TEST_ASSERT_EQ(poly.acceleration(val), 0); + } + + // Quadratic poly should have constant acceleration + poly = getRandPoly(2); + for (const auto& val: values) + { + TEST_ASSERT_EQ(poly.acceleration(val), 2 * poly[2]); + } + + // Check cubic and quartic against the 2nd derivative + poly = getRandPoly(3); + for (const auto& val: values) + { + TEST_ASSERT_EQ(poly.acceleration(val), poly.derivative().derivative()(val)); + } + + poly = getRandPoly(4); + for (const auto& val: values) + { + TEST_ASSERT_EQ(poly.acceleration(val), poly.derivative().derivative()(val)); + } +} + TEST_MAIN( TEST_CHECK(testScaleVariable); TEST_CHECK(testTruncateTo); TEST_CHECK(testTruncateToNonZeros); TEST_CHECK(testTransformInput); - ) + TEST_CHECK(testVelocity); + TEST_CHECK(testAcceleration); +) diff --git a/externals/coda-oss/modules/c++/math.poly/unittests/test_fixed_1d_poly.cpp b/externals/coda-oss/modules/c++/math.poly/unittests/test_fixed_1d_poly.cpp index e28a250a11..f2a24089dc 100644 --- a/externals/coda-oss/modules/c++/math.poly/unittests/test_fixed_1d_poly.cpp +++ b/externals/coda-oss/modules/c++/math.poly/unittests/test_fixed_1d_poly.cpp @@ -26,8 +26,8 @@ #include #include "TestCase.h" -static const size_t ORDER = 5; -typedef math::poly::Fixed1D TestFixed1D; +template +using Fixed1D = math::poly::Fixed1D; double getRand() { @@ -37,9 +37,10 @@ double getRand() return (50.0 * rand() / RAND_MAX - 25.0); } -TestFixed1D getRandPoly() +template +Fixed1D getRandPoly() { - TestFixed1D poly; + Fixed1D poly; for (size_t ii = 0; ii <= ORDER; ++ii) { poly[ii] = getRand(); @@ -62,11 +63,11 @@ TEST_CASE(testScaleVariable) std::vector value; getRandValues(value); - TestFixed1D poly(getRandPoly()); + auto poly(getRandPoly<5>()); // transformedPoly = poly(x * scale, y * scale) const double scale(13.34); - TestFixed1D transformedPoly = poly.scaleVariable(scale); + auto transformedPoly = poly.scaleVariable(scale); for (size_t ii = 0; ii < value.size(); ++ii) { @@ -80,6 +81,80 @@ TEST_CASE(testScaleVariable) } } +TEST_CASE(testVelocity) +{ + std::vector values; + getRandValues(values); + + // Constant poly should have 0 velocity + auto constPoly(getRandPoly<0>()); + for (const auto& val: values) + { + TEST_ASSERT_EQ(constPoly.velocity(val), 0.0); + } + + // Linear poly should have constant velocity + auto linearPoly(getRandPoly<1>()); + for (const auto& val: values) + { + TEST_ASSERT_EQ(linearPoly.velocity(val), linearPoly[1]); + } + + // Check quadratic and cubic against the derivative + auto quadraticPoly(getRandPoly<2>()); + for (const auto& val: values) + { + TEST_ASSERT_EQ(quadraticPoly.velocity(val), quadraticPoly.derivative()(val)); + } + + auto cubicPoly(getRandPoly<3>()); + for (const auto& val: values) + { + TEST_ASSERT_EQ(cubicPoly.velocity(val), cubicPoly.derivative()(val)); + } +} + +TEST_CASE(testAcceleration) +{ + std::vector values; + getRandValues(values); + + // Constant and linear polys should have 0 acceleration + auto constPoly(getRandPoly<0>()); + for (const auto& val: values) + { + TEST_ASSERT_EQ(constPoly.acceleration(val), 0.0); + } + + auto linearPoly(getRandPoly<1>()); + for (const auto& val: values) + { + TEST_ASSERT_EQ(linearPoly.acceleration(val), 0.0); + } + + // Quadratic poly should have constant acceleration + auto quadraticPoly(getRandPoly<2>()); + for (const auto& val: values) + { + TEST_ASSERT_EQ(quadraticPoly.acceleration(val), 2 * quadraticPoly[2]); + } + + // Check cubic and quartic against the 2nd derivative + auto cubicPoly(getRandPoly<3>()); + for (const auto& val: values) + { + TEST_ASSERT_EQ(cubicPoly.acceleration(val), cubicPoly.derivative().derivative()(val)); + } + + auto quarticPoly(getRandPoly<4>()); + for (const auto& val: values) + { + TEST_ASSERT_EQ(quarticPoly.acceleration(val), quarticPoly.derivative().derivative()(val)); + } +} + TEST_MAIN( TEST_CHECK(testScaleVariable); + TEST_CHECK(testVelocity); + TEST_CHECK(testAcceleration); ) diff --git a/externals/coda-oss/modules/c++/mt/include/mt/OrderedRequestQueue.h b/externals/coda-oss/modules/c++/mt/include/mt/OrderedRequestQueue.h new file mode 100644 index 0000000000..876248f2ea --- /dev/null +++ b/externals/coda-oss/modules/c++/mt/include/mt/OrderedRequestQueue.h @@ -0,0 +1,285 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2026, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved + * + * mt-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 __MT_ORDERED_REQUEST_QUEUE_H__ +#define __MT_ORDERED_REQUEST_QUEUE_H__ + +#include +#include "sys/Thread.h" +#include "sys/ConditionVar.h" +#include "sys/Mutex.h" +#include "sys/Dbg.h" + +namespace mt +{ +template +class AbstractComparator +{ + public: + virtual bool operator()(const T& lhs, const T& rhs) const + { + return lhs < rhs; + } +}; + +/*! + * + * \class OrderedRequestQueue + * \brief Thread-safe altenrative to request queue + * + * std::set inserts an element into a thread lock request queue + * that orders its elements based off of the provided operator. + * Dequeue blocks the thread until an element is avaliable. + * + */ + +template> +class OrderedRequestQueue +{ +public: + //! Default constructor + OrderedRequestQueue() : + mAvailableSpace(&mQueueLock), + mAvailableItems(&mQueueLock) + { + } + + OrderedRequestQueue(const CmpFtor f) : + mRequestQueue(f), + mAvailableSpace(&mQueueLock), + mAvailableItems(&mQueueLock) + { + } + + //! Put a (copy of, unless T is a pointer) request on the queue + void enqueue(T request) + { +#ifdef THREAD_DEBUG + dbg_printf("Locking (enqueue)\n"); +#endif + mQueueLock.lock(); + + mRequestQueue.insert(request); +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (enqueue), new size [%d]\n", mRequestQueue.size()); +#endif + mQueueLock.unlock(); + + mAvailableItems.signal(); + } + + //! Retrieve (by reference) T from the queue. blocks until ok + void dequeue(T& request) + { +#ifdef THREAD_DEBUG + dbg_printf("Locking (dequeue)\n"); +#endif + mQueueLock.lock(); + while (isEmpty()) + { + mAvailableItems.wait(); + } + + auto first = mRequestQueue.begin(); + request = *first; + mRequestQueue.erase(first); + +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (dequeue), new size [%d]\n", mRequestQueue.size()); +#endif + mQueueLock.unlock(); + mAvailableSpace.signal(); + } + + //! Retrieves a copy of the n'th item from the front of the queue (0 = first item) without removing it + T peek(size_t n = 0) + { + T request; +#ifdef THREAD_DEBUG + dbg_printf("Locking (peek)\n"); +#endif + mQueueLock.lock(); + if (mRequestQueue.size() > n) + { + auto iter = mRequestQueue.begin(); + while (n--) + { + ++iter; + } + request = *iter; + } + else + { + mQueueLock.unlock(); + throw except::Exception(Ctxt("Request queue cannot peek beyond end of queue")); + } + mQueueLock.unlock(); +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (peek)\n"); +#endif + + return request; + } + + //! Lets the n'th request from the front cut in line and dequeue + void cutAndDequeue(size_t n, T& request) + { +#ifdef THREAD_DEBUG + dbg_printf("Locking (peek)\n"); +#endif + mQueueLock.lock(); + if (mRequestQueue.size() > n) + { + auto iter = mRequestQueue.begin(); + while (n--) + { + ++iter; + } + request = *iter; + mRequestQueue.erase(iter); + } + else + { + mQueueLock.unlock(); + throw except::Exception(Ctxt("Request queue cannot access beyond end of queue")); + } + mQueueLock.unlock(); + mAvailableSpace.signal(); +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (peek)\n"); +#endif + } + + //! Check to see if its empty + inline bool isEmpty() + { + return (mRequestQueue.size() == 0); + } + + //! Check the length + inline size_t length() + { + return mRequestQueue.size(); + } + + void clear() + { +#ifdef THREAD_DEBUG + dbg_printf("Locking (clear)\n"); +#endif + mQueueLock.lock(); + mRequestQueue.clear(); + +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (clear), new size [%d]\n", mRequestQueue.size()); +#endif + mQueueLock.unlock(); + mAvailableSpace.signal(); + } + + //! Aggregates ProcFunctor of all of the elements of the queue + template + AggregateType aggregate(const ProcFunctor& aggregate, const AggregateType& initial) + { + mQueueLock.lock(); + AggregateType cumulative = initial; + for (typename std::set::iterator iter = mRequestQueue.begin(); + iter != mRequestQueue.end(); + ++iter) + { + cumulative = aggregate(*iter, cumulative); + } + + mQueueLock.unlock(); + return cumulative; + } + + //! Remove the given request from the queue + // Does nothing if the given request is not in the queue + // \return true if an item was removed, false otherwise + template + bool removeRequest(const CmpFunctor& compare) + { + mQueueLock.lock(); + for (typename std::set::iterator iter = mRequestQueue.begin(); + iter != mRequestQueue.end(); + ++iter) + { + if (compare(*iter)) + { + mRequestQueue.erase(iter); + mQueueLock.unlock(); + mAvailableSpace.signal(); + return true; + } + } + mQueueLock.unlock(); + return false; + } + + //! Remove the given request from the queue and return the request object + // Does nothing if the given request is not in the queue + // \return true if an item was removed, false otherwise + // request is set the object of the request in the queue + template + bool removeAndGetRequest(const CmpFunctor& compare, T& request) + { + mQueueLock.lock(); + for (typename std::set::iterator iter = mRequestQueue.begin(); + iter != mRequestQueue.end(); + ++iter) + { + if (compare(*iter)) + { + request = *iter; + mRequestQueue.erase(iter); + mQueueLock.unlock(); + mAvailableSpace.signal(); + return true; + } + } + mQueueLock.unlock(); + return false; + } + +private: + // Noncopyable + OrderedRequestQueue(const OrderedRequestQueue& ); + const OrderedRequestQueue& operator=(const OrderedRequestQueue& ); + +private: + //! The internal data structure + std::set mRequestQueue; + //! The synchronizer + sys::Mutex mQueueLock; + //! This condition is "is there space?" + sys::ConditionVar mAvailableSpace; + //! This condition is "is there an item?" + sys::ConditionVar mAvailableItems; +}; + +template +using RunnableOrderedRequestQueue = OrderedRequestQueue; +} + +#endif // __MT_REQUEST_QUEUE_H__ diff --git a/externals/coda-oss/modules/c++/mt/include/mt/RequestQueue.h b/externals/coda-oss/modules/c++/mt/include/mt/RequestQueue.h index ad33a53a14..e20ae21daf 100644 --- a/externals/coda-oss/modules/c++/mt/include/mt/RequestQueue.h +++ b/externals/coda-oss/modules/c++/mt/include/mt/RequestQueue.h @@ -3,6 +3,7 @@ * ========================================================================= * * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * mt-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 @@ -23,15 +24,18 @@ #ifndef __MT_REQUEST_QUEUE_H__ #define __MT_REQUEST_QUEUE_H__ -#include +#include #include "sys/Thread.h" #include "sys/ConditionVar.h" #include "sys/Mutex.h" #include "sys/Dbg.h" + namespace mt { + + /*! * * \class RequestQueue @@ -51,6 +55,7 @@ namespace mt template struct RequestQueue { +public: //! Default constructor RequestQueue() : mAvailableSpace(&mQueueLock), @@ -58,14 +63,30 @@ struct RequestQueue { } - // Put a (copy of, unless T is a pointer) request on the queue + //! Puts the request at the front of the queue + void priorityEnqueue(T request) + { +#ifdef THREAD_DEBUG + dbg_printf("Locking (enqueue)\n"); +#endif + mQueueLock.lock(); + mRequestQueue.push_front(request); +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (enqueue), new size [%d]\n", mRequestQueue.size()); +#endif + mQueueLock.unlock(); + + mAvailableItems.signal(); + } + + //! Put a (copy of, unless T is a pointer) request on the queue void enqueue(T request) { #ifdef THREAD_DEBUG dbg_printf("Locking (enqueue)\n"); #endif mQueueLock.lock(); - mRequestQueue.push(request); + mRequestQueue.push_back(request); #ifdef THREAD_DEBUG dbg_printf("Unlocking (enqueue), new size [%d]\n", mRequestQueue.size()); #endif @@ -74,7 +95,7 @@ struct RequestQueue mAvailableItems.signal(); } - // Retrieve (by reference) T from the queue. blocks until ok + //! Retrieve (by reference) T from the queue. blocks until ok void dequeue(T& request) { #ifdef THREAD_DEBUG @@ -87,7 +108,7 @@ struct RequestQueue } request = mRequestQueue.front(); - mRequestQueue.pop(); + mRequestQueue.pop_front(); #ifdef THREAD_DEBUG dbg_printf("Unlocking (dequeue), new size [%d]\n", mRequestQueue.size()); @@ -95,14 +116,64 @@ struct RequestQueue mQueueLock.unlock(); mAvailableSpace.signal(); } + + //! Retrieves a copy of the n'th item from the front of the queue (0 = first item) without removing it + T peek(size_t n = 0) + { + T request; +#ifdef THREAD_DEBUG + dbg_printf("Locking (peek)\n"); +#endif + mQueueLock.lock(); + if (mRequestQueue.size() > n) + { + request = mRequestQueue[n]; + } + else + { + mQueueLock.unlock(); + throw except::Exception(Ctxt("Request queue cannot peek beyond end of queue")); + } + mQueueLock.unlock(); +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (peek)\n"); +#endif + + return request; + } - // Check to see if its empty - bool isEmpty() const + //! Lets the n'th request from the front cut in line and dequeue + //! NOTE: The RequestQueue does not prevent changes to the queue between + //! when peak() and cutAndDequeue() are called + void cutAndDequeue(size_t n, T& request) + { +#ifdef THREAD_DEBUG + dbg_printf("Locking (peek)\n"); +#endif + mQueueLock.lock(); + if (mRequestQueue.size() > n) + { + request = mRequestQueue[n]; + mRequestQueue.erase(mRequestQueue.begin()+n); + } + else + { + mQueueLock.unlock(); + throw except::Exception(Ctxt("Request queue cannot access beyond end of queue")); + } + mQueueLock.unlock(); +#ifdef THREAD_DEBUG + dbg_printf("Unlocking (peek)\n"); +#endif + } + + //! Check to see if its empty + inline bool isEmpty() const { return mRequestQueue.empty(); } - // Check the length + //! Check the length int length() const { return mRequestQueue.size(); @@ -116,7 +187,7 @@ struct RequestQueue mQueueLock.lock(); while (!isEmpty()) { - mRequestQueue.pop(); + mRequestQueue.pop_front(); } #ifdef THREAD_DEBUG @@ -126,12 +197,53 @@ struct RequestQueue mAvailableSpace.signal(); } + //! Aggregates ProcFunctor of all of the elements of the queue + template + AggregateType aggregate(const ProcFunctor& aggregate, const AggregateType& initial) + { + mQueueLock.lock(); + AggregateType cumulative = initial; + for (typename std::deque::iterator iter = mRequestQueue.begin(); + iter != mRequestQueue.end(); + ++iter) + { + cumulative = aggregate(*iter, cumulative); + } + + mQueueLock.unlock(); + return cumulative; + } + + //! Remove the given request from the queue + // Does nothing if the given request is not in the queue + // \return true if an item was removed, false otherwise + template + bool removeRequest(const CmpFunctor& compare) + { + mQueueLock.lock(); + for (typename std::deque::iterator iter = mRequestQueue.begin(); + iter != mRequestQueue.end(); + ++iter) + { + if (compare(*iter)) + { + mRequestQueue.erase(iter); + mQueueLock.unlock(); + mAvailableSpace.signal(); + return true; + } + } + mQueueLock.unlock(); + return false; + } + +private: RequestQueue(const RequestQueue&) = delete; RequestQueue& operator=(const RequestQueue&) = delete; private: //! The internal data structure - std::queue mRequestQueue; + std::deque mRequestQueue; //! The synchronizer sys::Mutex mQueueLock; //! This condition is "is there space?" diff --git a/externals/coda-oss/modules/c++/mt/unittests/OrderedRequestQueueTest.cpp b/externals/coda-oss/modules/c++/mt/unittests/OrderedRequestQueueTest.cpp new file mode 100644 index 0000000000..0d609f7733 --- /dev/null +++ b/externals/coda-oss/modules/c++/mt/unittests/OrderedRequestQueueTest.cpp @@ -0,0 +1,112 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved + * + * mt-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 +#include "TestCase.h" + +class EvenFirst +{ +public: + bool operator()(int lhs, int rhs) const + { + bool result; + if ((lhs % 2 && rhs % 2) || (!(lhs%2) && !(rhs%2)) ) + { + result = lhs < rhs; + } + else + { + result = !(lhs % 2); + } + return result; + } +}; + +namespace +{ +/** + * Tests priority enqueue and dequeue via the OrderedRequestQueues + * standard numerical ordering and a custom even first comparator + */ +TEST_CASE(PriorityEnqueue) +{ + mt::OrderedRequestQueue testSubject; + testSubject.enqueue(1); + testSubject.enqueue(2); + testSubject.enqueue(3); + testSubject.enqueue(4); + testSubject.enqueue(5); + testSubject.enqueue(6); + + int request = -1; + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 1); + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 2); + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 3); + + testSubject.enqueue(10); + + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 4); + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 5); + + testSubject.enqueue(1); + + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 1); + + mt::OrderedRequestQueue test2; + test2.enqueue(1); + test2.enqueue(2); + test2.enqueue(3); + test2.enqueue(4); + test2.enqueue(5); + test2.enqueue(6); + + test2.dequeue(request); + TEST_ASSERT_EQ(request, 2); + test2.dequeue(request); + TEST_ASSERT_EQ(request, 4); + test2.dequeue(request); + TEST_ASSERT_EQ(request, 6); + test2.dequeue(request); + TEST_ASSERT_EQ(request, 1); + test2.dequeue(request); + TEST_ASSERT_EQ(request, 3); + test2.dequeue(request); + TEST_ASSERT_EQ(request, 5); + + +} + +} + +int main(int, char**) +{ + TEST_CHECK(PriorityEnqueue); + + return 0; +} diff --git a/externals/coda-oss/modules/c++/mt/unittests/RequestQueueTest.cpp b/externals/coda-oss/modules/c++/mt/unittests/RequestQueueTest.cpp new file mode 100644 index 0000000000..bc7a4d6042 --- /dev/null +++ b/externals/coda-oss/modules/c++/mt/unittests/RequestQueueTest.cpp @@ -0,0 +1,63 @@ +/* ========================================================================= + * This file is part of mt-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved + * + * mt-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 +#include "TestCase.h" + +namespace +{ +TEST_CASE(PriorityEnqueue) +{ + mt::RequestQueue testSubject; + testSubject.enqueue(1); + testSubject.enqueue(2); + testSubject.enqueue(3); + testSubject.enqueue(4); + testSubject.enqueue(5); + testSubject.enqueue(6); + testSubject.priorityEnqueue(7); + + int request = -1; + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 7); + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 1); + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 2); + + testSubject.priorityEnqueue(8); + + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 8); + testSubject.dequeue(request); + TEST_ASSERT_EQ(request, 3); +} + +} + +int main(int, char**) +{ + TEST_CHECK(PriorityEnqueue); + + return 0; +} diff --git a/externals/coda-oss/modules/c++/sys/CMakeLists.txt b/externals/coda-oss/modules/c++/sys/CMakeLists.txt index 7404c3474b..dad78ab968 100644 --- a/externals/coda-oss/modules/c++/sys/CMakeLists.txt +++ b/externals/coda-oss/modules/c++/sys/CMakeLists.txt @@ -1,5 +1,7 @@ set(MODULE_NAME sys) +include(CheckSourceCompiles) +check_source_compiles(CXX [[ int main() { __builtin_cpu_init(); return 0; } ]] HAVE_BUILTIN_CPU_INIT) coda_generate_module_config_header(${MODULE_NAME}) coda_add_module( diff --git a/externals/coda-oss/modules/c++/sys/include/sys/Dbg.h b/externals/coda-oss/modules/c++/sys/include/sys/Dbg.h index 5c896f354a..55c2214162 100644 --- a/externals/coda-oss/modules/c++/sys/include/sys/Dbg.h +++ b/externals/coda-oss/modules/c++/sys/include/sys/Dbg.h @@ -4,6 +4,7 @@ * * (C) Copyright 2004 - 2014, MDA Information Systems LLC * (C) Copyright 2021, Maxar Technologies, Inc. + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * 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 @@ -71,8 +72,6 @@ //#error "NDEBUG should be #define'd with __OPTIMIZE__" #endif #define CODA_OSS_DEBUG 0 // i.e., release - #else - #error "Can't #define CODA_OSS_DEBUG for __GNUC__." #endif #endif // __GNUC__ diff --git a/externals/coda-oss/modules/c++/sys/include/sys/sys_config.h.cmake.in b/externals/coda-oss/modules/c++/sys/include/sys/sys_config.h.cmake.in index 5544c1fd9d..21bf3098d1 100644 --- a/externals/coda-oss/modules/c++/sys/include/sys/sys_config.h.cmake.in +++ b/externals/coda-oss/modules/c++/sys/include/sys/sys_config.h.cmake.in @@ -1,6 +1,7 @@ #ifndef _@tgt_munged_name@_CONFIG_H_ #define _@tgt_munged_name@_CONFIG_H_ +#cmakedefine01 HAVE_BUILTIN_CPU_INIT #cmakedefine HAVE_PTHREAD_H @HAVE_PTHREAD_H@ #cmakedefine HAVE_EXECINFO_H @HAVE_EXECINFO_H@ #cmakedefine HAVE_CLOCK_GETTIME @HAVE_CLOCK_GETTIME@ diff --git a/externals/coda-oss/modules/c++/sys/source/OSUnix.cpp b/externals/coda-oss/modules/c++/sys/source/OSUnix.cpp index 9a3cb61b9a..20479365e4 100644 --- a/externals/coda-oss/modules/c++/sys/source/OSUnix.cpp +++ b/externals/coda-oss/modules/c++/sys/source/OSUnix.cpp @@ -3,6 +3,7 @@ * ========================================================================= * * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * 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 @@ -32,7 +33,7 @@ #include #include "sys/Conf.h" - +#include "sys/sys_config.h" #ifndef _WIN32 #include @@ -425,6 +426,8 @@ void sys::OSUnix::getAvailableCPUs(std::vector& physicalCPUs, sys::SIMDInstructionSet sys::OSUnix::getSIMDInstructionSet() const { +// NOTE: This function relies on compiler instrinsics at runtime +#if (defined(__x86_64__) || defined(__i386__)) && HAVE_BUILTIN_CPU_INIT // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/X86-Built-in-Functions.html __builtin_cpu_init(); @@ -440,8 +443,9 @@ sys::SIMDInstructionSet sys::OSUnix::getSIMDInstructionSet() const { return SIMDInstructionSet::SSE2; } +#endif - throw std::runtime_error("SSE2 support is required."); + throw std::runtime_error("SIMD support is required."); } void sys::OSUnix::createSymlink(const std::string& origPathname, diff --git a/externals/coda-oss/modules/c++/sys/tests/DateTimeTest.cpp b/externals/coda-oss/modules/c++/sys/tests/DateTimeTest.cpp index b2c5597f0f..f351b8befb 100644 --- a/externals/coda-oss/modules/c++/sys/tests/DateTimeTest.cpp +++ b/externals/coda-oss/modules/c++/sys/tests/DateTimeTest.cpp @@ -3,6 +3,7 @@ * ========================================================================= * * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * 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 @@ -34,6 +35,7 @@ int main(int, char**) try { sys::LocalDateTime now; + std::cout << "Epoch seconds: " << sys::DateTime::getEpochSeconds() << std::endl; std::cout << "Today is: " << now.getMonth() << "/" << now.getDayOfMonth() << "/" << now.getYear() << std::endl; std::cout << "Time is: " << now.getHour() << ":" << now.getMinute() diff --git a/externals/coda-oss/modules/c++/sys/unittests/test_path.cpp b/externals/coda-oss/modules/c++/sys/unittests/test_path.cpp index a444b9c656..2aec90623c 100644 --- a/externals/coda-oss/modules/c++/sys/unittests/test_path.cpp +++ b/externals/coda-oss/modules/c++/sys/unittests/test_path.cpp @@ -4,6 +4,7 @@ * * (C) Copyright 2004 - 2016, MDA Information Systems LLC * (C) Copyright 2021, Maxar Technologies, Inc. + * (C) Copyright 2025-26 ARKA Group, L.P. All rights reserved * * 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 @@ -123,7 +124,7 @@ TEST_CASE(test_std_filesystem_is_absolute) url = "s3://example.com"; // 2 letters TEST_ASSERT_FALSE(url.is_absolute()); - TEST_ASSERT_TRUE(url.is_relative()); // Should this be false? + TEST_ASSERT_TRUE(url.is_relative()); url = "ftp://example.com"; // 3 letters TEST_ASSERT_FALSE(url.is_absolute()); diff --git a/externals/coda-oss/modules/c++/xml.lite/CMakeLists.txt b/externals/coda-oss/modules/c++/xml.lite/CMakeLists.txt index ad13e57988..1f0ee238e8 100644 --- a/externals/coda-oss/modules/c++/xml.lite/CMakeLists.txt +++ b/externals/coda-oss/modules/c++/xml.lite/CMakeLists.txt @@ -1,9 +1,8 @@ set(MODULE_NAME xml.lite) if(ENABLE_XML) - if (UNIX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-zero-as-null-pointer-constant") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-suggest-override") + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + add_compile_options(-Wno-zero-as-null-pointer-constant -Wno-suggest-override) endif() if(CONAN_PACKAGE_NAME) diff --git a/externals/coda-oss/modules/drivers/gsl/GSL-4.0.0/include/gsl/assert b/externals/coda-oss/modules/drivers/gsl/GSL-4.0.0/include/gsl/assert index a6012048fc..4f9853d995 100644 --- a/externals/coda-oss/modules/drivers/gsl/GSL-4.0.0/include/gsl/assert +++ b/externals/coda-oss/modules/drivers/gsl/GSL-4.0.0/include/gsl/assert @@ -46,14 +46,15 @@ // Hopefully temporary until suppression standardization occurs // #if defined(__clang__) -#define GSL_SUPPRESS(x) [[gsl::suppress("x")]] -#else -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]] +#elif defined(_MSC_VER) && _MSC_VER >= 1950 +// Visual Studio versions after 2022 (_MSC_VER > 1944) support the justification message. +#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]] +#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__NVCC__) #define GSL_SUPPRESS(x) [[gsl::suppress(x)]] #else #define GSL_SUPPRESS(x) -#endif // _MSC_VER -#endif // __clang__ +#endif // defined(__clang__) #define GSL_STRINGIFY_DETAIL(x) #x #define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x) diff --git a/externals/coda-oss/modules/drivers/gsl/GSL-4.0.0/include/gsl/byte b/externals/coda-oss/modules/drivers/gsl/GSL-4.0.0/include/gsl/byte index 9231340b56..0ca2561381 100644 --- a/externals/coda-oss/modules/drivers/gsl/GSL-4.0.0/include/gsl/byte +++ b/externals/coda-oss/modules/drivers/gsl/GSL-4.0.0/include/gsl/byte @@ -18,18 +18,19 @@ #define GSL_BYTE_H // -// make suppress attributes work for some compilers +// make suppress attributes parse for some compilers // Hopefully temporary until suppression standardization occurs // #if defined(__clang__) -#define GSL_SUPPRESS(x) [[gsl::suppress("x")]] -#else -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]] +#elif defined(_MSC_VER) && _MSC_VER >= 1950 +// Visual Studio versions after 2022 (_MSC_VER > 1944) support the justification message. +#define GSL_SUPPRESS(x) [[gsl::suppress(#x)]] +#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__NVCC__) #define GSL_SUPPRESS(x) [[gsl::suppress(x)]] #else #define GSL_SUPPRESS(x) -#endif // _MSC_VER -#endif // __clang__ +#endif // defined(__clang__) #include diff --git a/externals/coda-oss/modules/drivers/hdf5/CMakeLists.txt b/externals/coda-oss/modules/drivers/hdf5/CMakeLists.txt index c061c7e833..9e8e930a82 100644 --- a/externals/coda-oss/modules/drivers/hdf5/CMakeLists.txt +++ b/externals/coda-oss/modules/drivers/hdf5/CMakeLists.txt @@ -4,11 +4,12 @@ set(TARGET_LANGUAGE c++) if(CODA_ENABLE_HDF5) # set up warnings if (MSVC) - # DO NOT use standard (not legacy) C pre-processor - add_compile_options(/Zc:preprocessor-) - - add_compile_definitions (_BIND_TO_CURRENT_VCLIBS_VERSION=1 _CONSOLE) + add_compile_definitions(_BIND_TO_CURRENT_VCLIBS_VERSION=1 _CONSOLE) endif() + add_compile_options( + $<$:/Zc:preprocessor-> + $<$:-Wno-implicit-function-declaration> + ) coda_add_module(${MODULE_NAME} VERSION 1.14.2) else() diff --git a/externals/coda-oss/modules/drivers/xml/xerces/CMakeLists.txt b/externals/coda-oss/modules/drivers/xml/xerces/CMakeLists.txt index fca630811f..ac804d20e6 100644 --- a/externals/coda-oss/modules/drivers/xml/xerces/CMakeLists.txt +++ b/externals/coda-oss/modules/drivers/xml/xerces/CMakeLists.txt @@ -68,7 +68,7 @@ else() check_include_file("arpa/inet.h" HAVE_ARPA_INET_H) check_include_file("netdb.h" HAVE_NETDB_H) check_include_file("intrin.h" HAVE_INTRIN_H) - set(HAVE_EMMINTRIN_H true) + check_include_file("immintrin.h" HAVE_EMMINTRIN_H) set(HAVE_WCHAR_H true) set(HAVE_STDINT_H true) set(HAVE_STDIO_H true) diff --git a/externals/coda-oss/modules/drivers/zlib/CMakeLists.txt b/externals/coda-oss/modules/drivers/zlib/CMakeLists.txt index 77ec31fa98..9c17cec17c 100644 --- a/externals/coda-oss/modules/drivers/zlib/CMakeLists.txt +++ b/externals/coda-oss/modules/drivers/zlib/CMakeLists.txt @@ -75,6 +75,9 @@ if (ZIP_HOME) target_link_libraries(minizip INTERFACE ${minizip_PATH}) elseif(ENABLE_ZIP) message("ZIP_HOME not specified, so zlib and minizip will be built") + + add_compile_options($<$:-Wno-implicit-function-declaration>) + coda_fetch_driver( NAME ${TARGET_NAME} ARCHIVE "zlib-1.2.13.tar" diff --git a/six/modules/c++/six.sidd/include/six/sidd/DerivedXMLParser.h b/six/modules/c++/six.sidd/include/six/sidd/DerivedXMLParser.h index 4827b0a74f..5956bedea7 100644 --- a/six/modules/c++/six.sidd/include/six/sidd/DerivedXMLParser.h +++ b/six/modules/c++/six.sidd/include/six/sidd/DerivedXMLParser.h @@ -86,6 +86,9 @@ struct DerivedXMLParser : public six::XMLParser static const char SFA_URI[]; + static + std::string getIsmPrefix(const xml::lite::Element* element); + static void getAttributeList(const xml::lite::Attributes& attributes, const std::string& attributeName, diff --git a/six/modules/c++/six.sidd/source/DerivedXMLParser.cpp b/six/modules/c++/six.sidd/source/DerivedXMLParser.cpp index 54b8d545f9..48af01c039 100644 --- a/six/modules/c++/six.sidd/source/DerivedXMLParser.cpp +++ b/six/modules/c++/six.sidd/source/DerivedXMLParser.cpp @@ -53,6 +53,36 @@ DerivedXMLParser::DerivedXMLParser(Version siddVersion, std::unique_ptrgetParent()) + element = element->getParent(); + + static const xml::lite::Uri xmlns("http://www.w3.org/2000/xmlns/"); + static const xml::lite::Uri ism_201609("urn:us:gov:ic:ism:201609"); + static const xml::lite::Uri ism_13("urn:us:gov:ic:ism:13"); + static const xml::lite::Uri ism("urn:us:gov:ic:ism"); + + for (auto& attribute : element->getAttributes()) + { + xml::lite::Uri uri; + attribute.getUri(uri); + if (uri != xmlns) + continue; + + const xml::lite::Uri uriValue(attribute.getValue()); + if ((uriValue == ism_201609) || (uriValue == ism_13) || (uriValue == ism)) + { + return attribute.getLocalName(); + } + } + + return ""; +} + void DerivedXMLParser::getAttributeList( const xml::lite::Attributes& attributes, const std::string& attributeName, @@ -322,6 +352,10 @@ void DerivedXMLParser::parseDerivedClassificationFromXML( const XMLAttributes& classificationAttributes = classificationElem->getAttributes(); + std::string prefix = getIsmPrefix(classificationElem); + if (!prefix.empty()) + prefix = prefix + ":"; + //! from ism:ISMRootNodeAttributeGroup // Could do // toType( @@ -331,81 +365,81 @@ void DerivedXMLParser::parseDerivedClassificationFromXML( //! from ism:ResourceNodeAttributeGroup // NOTE: "resouceElement" is fixed to true so it isn't saved here classification.createDate = toType( - classificationAttributes.getValue("ism:createDate")); + classificationAttributes.getValue(prefix + "createDate")); // optional getAttributeListIfExists(classificationAttributes, - "ism:compliesWith", + prefix + "compliesWith", classification.compliesWith); //! from ism:SecurityAttributesGroup // -- referenced in ism::ResourceNodeAttributeGroup classification.classification - = classificationAttributes.getValue("ism:classification"); + = classificationAttributes.getValue(prefix + "classification"); getAttributeList(classificationAttributes, - "ism:ownerProducer", + prefix + "ownerProducer", classification.ownerProducer); // optional getAttributeListIfExists(classificationAttributes, - "ism:SCIcontrols", + prefix + "SCIcontrols", classification.sciControls); // optional getAttributeListIfExists(classificationAttributes, - "ism:SARIdentifier", + prefix + "SARIdentifier", classification.sarIdentifier); // optional getAttributeListIfExists(classificationAttributes, - "ism:disseminationControls", + prefix + "disseminationControls", classification.disseminationControls); // optional getAttributeListIfExists(classificationAttributes, - "ism:FGIsourceOpen", classification.fgiSourceOpen); + prefix + "FGIsourceOpen", classification.fgiSourceOpen); // optional getAttributeListIfExists(classificationAttributes, - "ism:FGIsourceProtected", + prefix + "FGIsourceProtected", classification.fgiSourceProtected); // optional getAttributeListIfExists(classificationAttributes, - "ism:releasableTo", + prefix + "releasableTo", classification.releasableTo); // optional getAttributeListIfExists(classificationAttributes, - "ism:nonICmarkings", + prefix + "nonICmarkings", classification.nonICMarkings); // optional getAttributeIfExists(classificationAttributes, - "ism:classifiedBy", + prefix + "classifiedBy", classification.classifiedBy); // optional getAttributeIfExists(classificationAttributes, - "ism:compilationReason", + prefix + "compilationReason", classification.compilationReason); // optional getAttributeIfExists(classificationAttributes, - "ism:derivativelyClassifiedBy", + prefix + "derivativelyClassifiedBy", classification.derivativelyClassifiedBy); // optional getAttributeIfExists(classificationAttributes, - "ism:classificationReason", + prefix + "classificationReason", classification.classificationReason); // optional getAttributeListIfExists(classificationAttributes, - "ism:nonUSControls", + prefix + "nonUSControls", classification.nonUSControls); // optional getAttributeIfExists(classificationAttributes, - "ism:derivedFrom", + prefix + "derivedFrom", classification.derivedFrom); // optional getAttributeIfExists(classificationAttributes, - "ism:declassDate", + prefix + "declassDate", classification.declassDate); // optional getAttributeIfExists(classificationAttributes, - "ism:declassEvent", + prefix + "declassEvent", classification.declassEvent); // optional getAttributeIfExists(classificationAttributes, - "ism:declassException", + prefix + "declassException", classification.declassException); } diff --git a/six/modules/c++/six.sidd/source/DerivedXMLParser100.cpp b/six/modules/c++/six.sidd/source/DerivedXMLParser100.cpp index 401813e9e6..14c058d18e 100644 --- a/six/modules/c++/six.sidd/source/DerivedXMLParser100.cpp +++ b/six/modules/c++/six.sidd/source/DerivedXMLParser100.cpp @@ -162,16 +162,20 @@ void DerivedXMLParser100::parseDerivedClassificationFromXML( const ElemAttributes& classificationAttributes = classificationElem->getAttributes(); + std::string prefix = getIsmPrefix(classificationElem); + if (!prefix.empty()) + prefix = prefix + ":"; + getAttributeListIfExists(classificationAttributes, - "ism:compliesWith", + prefix + "compliesWith", classification.compliesWith); // optional getAttributeIfExists(classificationAttributes, - "ism:typeOfExemptedSource", + prefix + "typeOfExemptedSource", classification.exemptedSourceType); // optional getAttributeIfExists(classificationAttributes, - "ism:dateOfExemptedSource", + prefix + "dateOfExemptedSource", classification.exemptedSourceDate); } diff --git a/six/modules/c++/six.sidd/source/DerivedXMLParser200.cpp b/six/modules/c++/six.sidd/source/DerivedXMLParser200.cpp index bdb7720595..bd70546c79 100644 --- a/six/modules/c++/six.sidd/source/DerivedXMLParser200.cpp +++ b/six/modules/c++/six.sidd/source/DerivedXMLParser200.cpp @@ -321,44 +321,48 @@ void DerivedXMLParser200::parseDerivedClassificationFromXML( const XMLAttributes& classificationAttributes = classificationElem->getAttributes(); + std::string prefix = getIsmPrefix(classificationElem); + if (!prefix.empty()) + prefix = prefix + ":"; + getAttributeList(classificationAttributes, - "ism:compliesWith", + prefix + "compliesWith", classification.compliesWith); // optional getAttributeIfExists(classificationAttributes, - "ism:exemptFrom", + prefix + "exemptFrom", classification.exemptFrom); // optional getAttributeIfExists(classificationAttributes, - "ism:joint", + prefix + "joint", classification.joint); // optional getAttributeListIfExists(classificationAttributes, - "ism:atomicEnergyMarkings", + prefix + "atomicEnergyMarkings", classification.atomicEnergyMarkings); // optional getAttributeListIfExists(classificationAttributes, - "ism:displayOnlyTo", + prefix + "displayOnlyTo", classification.displayOnlyTo); // optional getAttributeIfExists(classificationAttributes, - "ism:noticeType", + prefix + "noticeType", classification.noticeType); // optional getAttributeIfExists(classificationAttributes, - "ism:noticeReason", + prefix + "noticeReason", classification.noticeReason); // optional getAttributeIfExists(classificationAttributes, - "ism:noticeDate", + prefix + "noticeDate", classification.noticeDate); // optional getAttributeIfExists(classificationAttributes, - "ism:unregisteredNoticeType", + prefix + "unregisteredNoticeType", classification.unregisteredNoticeType); // optional getAttributeIfExists(classificationAttributes, - "ism:externalNotice", + prefix + "externalNotice", classification.externalNotice); } diff --git a/six/modules/c++/six.sidd/source/DerivedXMLParser300.cpp b/six/modules/c++/six.sidd/source/DerivedXMLParser300.cpp index db2ec21d48..aebb234581 100644 --- a/six/modules/c++/six.sidd/source/DerivedXMLParser300.cpp +++ b/six/modules/c++/six.sidd/source/DerivedXMLParser300.cpp @@ -81,7 +81,7 @@ DerivedXMLParser300::DerivedXMLParser300(logging::Logger& log, six::sidd300::ISM DerivedXMLParser(VERSION, std::make_unique(versionToURI(VERSION), false, SI_COMMON_URI, log), log) - { + { mISMVersion = ismVersion; } @@ -265,44 +265,48 @@ void DerivedXMLParser300::parseDerivedClassificationFromXML( DerivedXMLParser::parseDerivedClassificationFromXML(classificationElem, classification); const auto& classificationAttributes = classificationElem->getAttributes(); + std::string prefix = getIsmPrefix(classificationElem); + if (!prefix.empty()) + prefix = prefix + ":"; + getAttributeList(classificationAttributes, - "ism:compliesWith", + prefix + "compliesWith", classification.compliesWith); // optional getAttributeIfExists(classificationAttributes, - "ism:exemptFrom", + prefix + "exemptFrom", classification.exemptFrom); // optional getAttributeIfExists(classificationAttributes, - "ism:joint", + prefix + "joint", classification.joint); // optional getAttributeListIfExists(classificationAttributes, - "ism:atomicEnergyMarkings", + prefix + "atomicEnergyMarkings", classification.atomicEnergyMarkings); // optional getAttributeListIfExists(classificationAttributes, - "ism:displayOnlyTo", + prefix + "displayOnlyTo", classification.displayOnlyTo); // optional getAttributeIfExists(classificationAttributes, - "ism:noticeType", + prefix + "noticeType", classification.noticeType); // optional getAttributeIfExists(classificationAttributes, - "ism:noticeReason", + prefix + "noticeReason", classification.noticeReason); // optional getAttributeIfExists(classificationAttributes, - "ism:noticeDate", + prefix + "noticeDate", classification.noticeDate); // optional getAttributeIfExists(classificationAttributes, - "ism:unregisteredNoticeType", + prefix + "unregisteredNoticeType", classification.unregisteredNoticeType); // optional getAttributeIfExists(classificationAttributes, - "ism:externalNotice", + prefix + "externalNotice", classification.externalNotice); } @@ -337,7 +341,7 @@ void DerivedXMLParser300::parseJ2KCompression(const xml::lite::Element& j2kElem, for (size_t ii = 0; ii < layerElems.size(); ++ii) { // In SIDD 3.0, the `index` attribute type changed from `positiveInteger` to `nonNegativeInteger` - // (matching C-style indexing). Since we had a problem with this, use the opportunity to + // (matching C-style indexing). Since we had a problem with this, use the opportunity to // validate the `index` value. const auto& attributes = layerElems[ii]->getAttributes(); std::string strIndex;