diff --git a/.github/workflows/comment-command.yml b/.github/workflows/comment-command.yml index cafece2fcf9..15f99264a4e 100644 --- a/.github/workflows/comment-command.yml +++ b/.github/workflows/comment-command.yml @@ -43,7 +43,7 @@ jobs: distribution: 'temurin' java-version: 17 - name: Install wpiformat - run: pip3 install wpiformat==2024.40 + run: pip3 install wpiformat==2024.41 - name: Run wpiformat run: wpiformat - name: Run spotlessApply diff --git a/.github/workflows/lint-format.yml b/.github/workflows/lint-format.yml index a995ec44c6b..624414b165e 100644 --- a/.github/workflows/lint-format.yml +++ b/.github/workflows/lint-format.yml @@ -27,7 +27,7 @@ jobs: with: python-version: '3.10' - name: Install wpiformat - run: pip3 install wpiformat==2024.40 + run: pip3 install wpiformat==2024.41 - name: Run run: wpiformat - name: Check output @@ -66,7 +66,7 @@ jobs: with: python-version: '3.10' - name: Install wpiformat - run: pip3 install wpiformat==2024.40 + run: pip3 install wpiformat==2024.41 - name: Create compile_commands.json run: | ./gradlew generateCompileCommands -Ptoolchain-optional-roboRio diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index 07341b7fbfe..3e71c5e8301 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -34,7 +34,7 @@ jobs: with: image: wpilib/roborio-cross-ubuntu:2024-22.04 options: -v ${{ github.workspace }}:/work -w /work -e GITHUB_REF -e CI -e DISPLAY - run: df . && rm -f semicolon_delimited_script && ./gradlew :wpilibc:publish :wpilibj:publish :wpilibNewCommands:publish :hal:publish :cameraserver:publish :ntcore:publish :cscore:publish :wpimath:publish :wpinet:publish :wpiutil:publish :apriltag:publish :wpiunits:publish :simulation:halsim_gui:publish :simulation:halsim_ds_socket:publish :fieldImages:publish -x test -x Javadoc -x doxygen --build-cache && cp -r /root/releases/maven/development /work + run: df . && rm -f semicolon_delimited_script && ./gradlew :wpilibc:publish :wpilibj:publish :wpilibNewCommands:publish :hal:publish :cameraserver:publish :ntcore:publish :cscore:publish :wpimath:publish :wpinet:publish :wpiutil:publish :apriltag:publish :wpiunits:publish :simulation:halsim_gui:publish :simulation:halsim_ds_socket:publish :fieldImages:publish :epilogue-processor:publish :epilogue-runtime:publish :thirdparty:googletest:publish -x test -x Javadoc -x doxygen --build-cache && cp -r /root/releases/maven/development /work - uses: actions/upload-artifact@v4 with: name: MavenArtifacts diff --git a/.github/workflows/upstream-utils.yml b/.github/workflows/upstream-utils.yml index 15597d05143..bd4e7ac39a8 100644 --- a/.github/workflows/upstream-utils.yml +++ b/.github/workflows/upstream-utils.yml @@ -35,11 +35,26 @@ jobs: cd upstream_utils ./apriltag.py clone ./apriltag.py copy-src + - name: Run argparse_lib.py + run: | + cd upstream_utils + ./argparse_lib.py clone + ./argparse_lib.py copy-src + - name: Run concurrentqueue.py + run: | + cd upstream_utils + ./concurrentqueue.py clone + ./concurrentqueue.py copy-src - name: Run eigen.py run: | cd upstream_utils ./eigen.py clone ./eigen.py copy-src + - name: Run expected.py + run: | + cd upstream_utils + ./expected.py clone + ./expected.py copy-src - name: Run fmt.py run: | cd upstream_utils diff --git a/.styleguide b/.styleguide index f1e32ce536f..feb5dc3e00e 100644 --- a/.styleguide +++ b/.styleguide @@ -33,8 +33,9 @@ includeOtherLibs { ^cameraserver/ ^cscore ^fmt/ - ^gtest/ + ^glass/ ^google/ + ^gtest/ ^hal/ ^imgui ^implot diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bcc181ea80..13c85a831e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,7 @@ option(WITH_EXAMPLES "Build examples" OFF) option(WITH_TESTS "Build unit tests (requires internet connection)" ON) option(WITH_GUI "Build GUI items" ON) option(WITH_SIMULATION_MODULES "Build simulation modules" ON) +option(WITH_PROTOBUF "Build protobuf support" ON) # Options for using a package manager (e.g., vcpkg) for certain dependencies. option(USE_SYSTEM_FMTLIB "Use system fmtlib" OFF) @@ -128,12 +129,14 @@ else() find_package(Java REQUIRED COMPONENTS Runtime) endif() -find_package(LIBSSH 0.7.1) +find_package(LIBSSH CONFIG 0.7.1) set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) -set(protobuf_MODULE_COMPATIBLE ON CACHE BOOL "" FORCE) -find_package(Protobuf REQUIRED) -find_program(PROTOC_COMPILER protoc REQUIRED) +if(WITH_PROTOBUF) + set(protobuf_MODULE_COMPATIBLE ON CACHE BOOL "" FORCE) + find_package(Protobuf REQUIRED) + find_program(PROTOC_COMPILER protoc REQUIRED) +endif() set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF) get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) diff --git a/apriltag/src/main/native/cpp/AprilTagDetector.cpp b/apriltag/src/main/native/cpp/AprilTagDetector.cpp index ca06c2b9477..08046d16dca 100644 --- a/apriltag/src/main/native/cpp/AprilTagDetector.cpp +++ b/apriltag/src/main/native/cpp/AprilTagDetector.cpp @@ -5,7 +5,7 @@ #include "frc/apriltag/AprilTagDetector.h" #include -#include +#include #ifdef _WIN32 #pragma warning(disable : 4200) diff --git a/apriltag/src/main/native/cpp/AprilTagFieldLayout.cpp b/apriltag/src/main/native/cpp/AprilTagFieldLayout.cpp index c0b4ca233bb..c90fad3626d 100644 --- a/apriltag/src/main/native/cpp/AprilTagFieldLayout.cpp +++ b/apriltag/src/main/native/cpp/AprilTagFieldLayout.cpp @@ -5,6 +5,8 @@ #include "frc/apriltag/AprilTagFieldLayout.h" #include +#include +#include #include #include @@ -15,14 +17,12 @@ using namespace frc; AprilTagFieldLayout::AprilTagFieldLayout(std::string_view path) { - std::error_code ec; - std::unique_ptr fileBuffer = - wpi::MemoryBuffer::GetFile(path, ec); - if (fileBuffer == nullptr || ec) { + auto fileBuffer = wpi::MemoryBuffer::GetFile(path); + if (!fileBuffer) { throw std::runtime_error(fmt::format("Cannot open file: {}", path)); } - wpi::json json = wpi::json::parse(fileBuffer->GetCharBuffer()); + wpi::json json = wpi::json::parse(fileBuffer.value()->GetCharBuffer()); for (const auto& tag : json.at("tags").get>()) { m_apriltags[tag.ID] = tag; diff --git a/apriltag/src/test/native/cpp/LoadConfigTest.cpp b/apriltag/src/test/native/cpp/LoadConfigTest.cpp index ba6fe81ff96..9cf5b6fa105 100644 --- a/apriltag/src/test/native/cpp/LoadConfigTest.cpp +++ b/apriltag/src/test/native/cpp/LoadConfigTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "frc/apriltag/AprilTagFieldLayout.h" diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 3a0ddb1510e..99d4892632a 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -9,5 +9,5 @@ repositories { } } dependencies { - implementation "edu.wpi.first:native-utils:2025.2.0" + implementation "edu.wpi.first:native-utils:2025.3.0" } diff --git a/cameraserver/multiCameraServer/src/main/native/cpp/main.cpp b/cameraserver/multiCameraServer/src/main/native/cpp/main.cpp index 011f8119f08..f3e0a7b72e3 100644 --- a/cameraserver/multiCameraServer/src/main/native/cpp/main.cpp +++ b/cameraserver/multiCameraServer/src/main/native/cpp/main.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -94,18 +95,17 @@ bool ReadCameraConfig(const wpi::json& config) { bool ReadConfig() { // open config file - std::error_code ec; - std::unique_ptr fileBuffer = - wpi::MemoryBuffer::GetFile(configFile, ec); - if (fileBuffer == nullptr || ec) { - wpi::print(stderr, "could not open '{}': {}\n", configFile, ec.message()); + auto fileBuffer = wpi::MemoryBuffer::GetFile(configFile); + if (!fileBuffer) { + wpi::print(stderr, "could not open '{}': {}\n", configFile, + fileBuffer.error().message()); return false; } // parse file wpi::json j; try { - j = wpi::json::parse(fileBuffer->GetCharBuffer()); + j = wpi::json::parse(fileBuffer.value()->GetCharBuffer()); } catch (const wpi::json::parse_error& e) { wpi::print(stderr, "config error in '{}': byte {}: {}\n", configFile, e.byte, e.what()); diff --git a/cameraserver/src/main/native/cpp/cameraserver/CameraServer.cpp b/cameraserver/src/main/native/cpp/cameraserver/CameraServer.cpp index c13c113c563..69293bbaac9 100644 --- a/cameraserver/src/main/native/cpp/cameraserver/CameraServer.cpp +++ b/cameraserver/src/main/native/cpp/cameraserver/CameraServer.cpp @@ -5,6 +5,9 @@ #include "cameraserver/CameraServer.h" #include +#include +#include +#include #include #include diff --git a/cameraserver/src/main/native/cpp/cameraserver/CameraServerShared.cpp b/cameraserver/src/main/native/cpp/cameraserver/CameraServerShared.cpp index 6d1ebc2c17a..4b6c9cf5af1 100644 --- a/cameraserver/src/main/native/cpp/cameraserver/CameraServerShared.cpp +++ b/cameraserver/src/main/native/cpp/cameraserver/CameraServerShared.cpp @@ -4,6 +4,9 @@ #include "cameraserver/CameraServerShared.h" +#include +#include + #include namespace { diff --git a/cameraserver/src/main/native/cpp/vision/VisionRunner.cpp b/cameraserver/src/main/native/cpp/vision/VisionRunner.cpp index b55325a7df1..1458db502bf 100644 --- a/cameraserver/src/main/native/cpp/vision/VisionRunner.cpp +++ b/cameraserver/src/main/native/cpp/vision/VisionRunner.cpp @@ -4,6 +4,7 @@ #include "vision/VisionRunner.h" +#include #include #include diff --git a/cmake/modules/AddTest.cmake b/cmake/modules/AddTest.cmake index 224cffa3b2d..b916f6f2cc4 100644 --- a/cmake/modules/AddTest.cmake +++ b/cmake/modules/AddTest.cmake @@ -2,6 +2,9 @@ include(CompileWarnings) macro(wpilib_add_test name srcdir) file(GLOB_RECURSE test_src ${srcdir}/*.cpp) + if(NOT WITH_PROTOBUF) + list(FILTER test_src EXCLUDE REGEX "/proto/") + endif() add_executable(${name}_test ${test_src}) set_property(TARGET ${name}_test PROPERTY FOLDER "tests") wpilib_target_warnings(${name}_test) diff --git a/cmake/modules/FindLIBSSH.cmake b/cmake/modules/FindLIBSSH.cmake deleted file mode 100644 index 6578aa99761..00000000000 --- a/cmake/modules/FindLIBSSH.cmake +++ /dev/null @@ -1,143 +0,0 @@ -# - Try to find LibSSH -# Once done this will define -# -# LIBSSH_FOUND - system has LibSSH -# LIBSSH_INCLUDE_DIRS - the LibSSH include directory -# LIBSSH_LIBRARIES - link these to use LibSSH -# LIBSSH_VERSION - -# -# Author Michal Vasko -# Copyright (c) 2020 CESNET, z.s.p.o. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. The name of the author may not be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -include(FindPackageHandleStandardArgs) - -if(LIBSSH_LIBRARIES AND LIBSSH_INCLUDE_DIRS) - # in cache already - set(LIBSSH_FOUND TRUE) -else() - find_path( - LIBSSH_INCLUDE_DIR - NAMES libssh/libssh.h - PATHS - /usr/include - /usr/local/include - /opt/local/include - /sw/include - ${CMAKE_INCLUDE_PATH} - ${CMAKE_INSTALL_PREFIX}/include - ) - - find_library( - LIBSSH_LIBRARY - NAMES ssh.so libssh.so libssh.dylib - PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /sw/lib - ${CMAKE_LIBRARY_PATH} - ${CMAKE_INSTALL_PREFIX}/lib - ) - - if(LIBSSH_INCLUDE_DIR AND LIBSSH_LIBRARY) - # learn libssh version - if(EXISTS ${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h) - set(LIBSSH_HEADER_PATH ${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h) - else() - set(LIBSSH_HEADER_PATH ${LIBSSH_INCLUDE_DIR}/libssh/libssh.h) - endif() - file( - STRINGS - ${LIBSSH_HEADER_PATH} - LIBSSH_VERSION_MAJOR - REGEX "#define[ ]+LIBSSH_VERSION_MAJOR[ ]+[0-9]+" - ) - if(NOT LIBSSH_VERSION_MAJOR) - message( - STATUS - "LIBSSH_VERSION_MAJOR not found, assuming libssh is too old and cannot be used!" - ) - set(LIBSSH_INCLUDE_DIR "LIBSSH_INCLUDE_DIR-NOTFOUND") - set(LIBSSH_LIBRARY "LIBSSH_LIBRARY-NOTFOUND") - else() - string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MAJOR ${LIBSSH_VERSION_MAJOR}) - file( - STRINGS - ${LIBSSH_HEADER_PATH} - LIBSSH_VERSION_MINOR - REGEX "#define[ ]+LIBSSH_VERSION_MINOR[ ]+[0-9]+" - ) - string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MINOR ${LIBSSH_VERSION_MINOR}) - file( - STRINGS - ${LIBSSH_HEADER_PATH} - LIBSSH_VERSION_PATCH - REGEX "#define[ ]+LIBSSH_VERSION_MICRO[ ]+[0-9]+" - ) - string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_PATCH ${LIBSSH_VERSION_PATCH}) - - set(LIBSSH_VERSION - ${LIBSSH_VERSION_MAJOR}.${LIBSSH_VERSION_MINOR}.${LIBSSH_VERSION_PATCH} - ) - - if(LIBSSH_VERSION VERSION_LESS 0.8.0) - # libssh_threads also needs to be linked for these versions - string( - REPLACE - "libssh.so" - "libssh_threads.so" - LIBSSH_THREADS_LIBRARY - ${LIBSSH_LIBRARY} - ) - string( - REPLACE - "libssh.dylib" - "libssh_threads.dylib" - LIBSSH_THREADS_LIBRARY - ${LIBSSH_THREADS_LIBRARY} - ) - string( - REPLACE - "ssh.so" - "ssh_threads.so" - LIBSSH_THREADS_LIBRARY - ${LIBSSH_THREADS_LIBRARY} - ) - endif() - endif() - endif() - - set(LIBSSH_INCLUDE_DIRS ${LIBSSH_INCLUDE_DIR}) - set(LIBSSH_LIBRARIES ${LIBSSH_LIBRARY} ${LIBSSH_THREADS_LIBRARY}) - mark_as_advanced(LIBSSH_INCLUDE_DIRS LIBSSH_LIBRARIES) - - find_package_handle_standard_args( - LIBSSH - FOUND_VAR LIBSSH_FOUND - REQUIRED_VARS LIBSSH_INCLUDE_DIRS LIBSSH_LIBRARIES - VERSION_VAR LIBSSH_VERSION - ) -endif() diff --git a/crossConnIntegrationTests/src/main/native/cpp/PWMTest.cpp b/crossConnIntegrationTests/src/main/native/cpp/PWMTest.cpp index d209658c9ce..49ff7b0e45d 100644 --- a/crossConnIntegrationTests/src/main/native/cpp/PWMTest.cpp +++ b/crossConnIntegrationTests/src/main/native/cpp/PWMTest.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include diff --git a/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp b/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp index e7e8721d9f4..0244c28bfe3 100644 --- a/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp +++ b/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp @@ -4,11 +4,13 @@ #include "ConfigurableSourceImpl.h" +#include +#include + #include #include "Handle.h" #include "Instance.h" -#include "Log.h" #include "Notifier.h" using namespace cs; diff --git a/cscore/src/main/native/cpp/Frame.cpp b/cscore/src/main/native/cpp/Frame.cpp index af108f46a72..759086f4e07 100644 --- a/cscore/src/main/native/cpp/Frame.cpp +++ b/cscore/src/main/native/cpp/Frame.cpp @@ -5,13 +5,13 @@ #include "Frame.h" #include +#include #include #include #include #include "Instance.h" -#include "Log.h" #include "SourceImpl.h" using namespace cs; diff --git a/cscore/src/main/native/cpp/HttpCameraImpl.cpp b/cscore/src/main/native/cpp/HttpCameraImpl.cpp index 05a5c90cafe..8c463d0408a 100644 --- a/cscore/src/main/native/cpp/HttpCameraImpl.cpp +++ b/cscore/src/main/native/cpp/HttpCameraImpl.cpp @@ -4,12 +4,16 @@ #include "HttpCameraImpl.h" +#include +#include +#include +#include + #include #include #include #include -#include "Handle.h" #include "Instance.h" #include "JpegUtil.h" #include "Log.h" diff --git a/cscore/src/main/native/cpp/Instance.cpp b/cscore/src/main/native/cpp/Instance.cpp index 979c80adcfb..33ee5968d92 100644 --- a/cscore/src/main/native/cpp/Instance.cpp +++ b/cscore/src/main/native/cpp/Instance.cpp @@ -4,7 +4,9 @@ #include "Instance.h" +#include #include +#include #include #include @@ -30,6 +32,7 @@ static void def_log_func(unsigned int level, const char* file, return; } wpi::print(stderr, "CS: {}: {} ({}:{})\n", levelmsg, msg, + // NOLINTNEXTLINE(build/include_what_you_use) fs::path{file}.filename().string(), line); } diff --git a/cscore/src/main/native/cpp/JpegUtil.cpp b/cscore/src/main/native/cpp/JpegUtil.cpp index 1abc01979c3..18bcf8c8faf 100644 --- a/cscore/src/main/native/cpp/JpegUtil.cpp +++ b/cscore/src/main/native/cpp/JpegUtil.cpp @@ -4,6 +4,8 @@ #include "JpegUtil.h" +#include + #include #include diff --git a/cscore/src/main/native/cpp/MjpegServerImpl.cpp b/cscore/src/main/native/cpp/MjpegServerImpl.cpp index f6f63d6673d..5ce5c39a528 100644 --- a/cscore/src/main/native/cpp/MjpegServerImpl.cpp +++ b/cscore/src/main/native/cpp/MjpegServerImpl.cpp @@ -5,6 +5,9 @@ #include "MjpegServerImpl.h" #include +#include +#include +#include #include #include @@ -15,7 +18,6 @@ #include #include -#include "Handle.h" #include "Instance.h" #include "JpegUtil.h" #include "Log.h" diff --git a/cscore/src/main/native/cpp/Notifier.cpp b/cscore/src/main/native/cpp/Notifier.cpp index 371189634d3..f9127ed41ea 100644 --- a/cscore/src/main/native/cpp/Notifier.cpp +++ b/cscore/src/main/native/cpp/Notifier.cpp @@ -4,9 +4,7 @@ #include "Notifier.h" -#include #include -#include #include "Handle.h" #include "Instance.h" diff --git a/cscore/src/main/native/cpp/PropertyContainer.cpp b/cscore/src/main/native/cpp/PropertyContainer.cpp index 0b8474f7241..5fdbd6899b9 100644 --- a/cscore/src/main/native/cpp/PropertyContainer.cpp +++ b/cscore/src/main/native/cpp/PropertyContainer.cpp @@ -4,6 +4,10 @@ #include "PropertyContainer.h" +#include +#include +#include + #include #include #include diff --git a/cscore/src/main/native/cpp/RawSinkImpl.cpp b/cscore/src/main/native/cpp/RawSinkImpl.cpp index bdbf2c1a9a6..3e38cb81c3b 100644 --- a/cscore/src/main/native/cpp/RawSinkImpl.cpp +++ b/cscore/src/main/native/cpp/RawSinkImpl.cpp @@ -4,8 +4,10 @@ #include "RawSinkImpl.h" +#include +#include + #include "Instance.h" -#include "cscore.h" #include "cscore_raw.h" using namespace cs; diff --git a/cscore/src/main/native/cpp/RawSourceImpl.cpp b/cscore/src/main/native/cpp/RawSourceImpl.cpp index aad27b240ef..d06cecdb412 100644 --- a/cscore/src/main/native/cpp/RawSourceImpl.cpp +++ b/cscore/src/main/native/cpp/RawSourceImpl.cpp @@ -4,11 +4,11 @@ #include "RawSourceImpl.h" +#include + #include -#include "Handle.h" #include "Instance.h" -#include "Log.h" #include "Notifier.h" #include "cscore_raw.h" diff --git a/cscore/src/main/native/cpp/SinkImpl.cpp b/cscore/src/main/native/cpp/SinkImpl.cpp index 0897bb8d6a5..32d86adf163 100644 --- a/cscore/src/main/native/cpp/SinkImpl.cpp +++ b/cscore/src/main/native/cpp/SinkImpl.cpp @@ -4,6 +4,8 @@ #include "SinkImpl.h" +#include + #include #include diff --git a/cscore/src/main/native/cpp/SourceImpl.cpp b/cscore/src/main/native/cpp/SourceImpl.cpp index e30821064ae..6bdee5bab98 100644 --- a/cscore/src/main/native/cpp/SourceImpl.cpp +++ b/cscore/src/main/native/cpp/SourceImpl.cpp @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/cscore/src/main/native/cpp/Telemetry.cpp b/cscore/src/main/native/cpp/Telemetry.cpp index 751ef44cf5f..a3e8e5b7144 100644 --- a/cscore/src/main/native/cpp/Telemetry.cpp +++ b/cscore/src/main/native/cpp/Telemetry.cpp @@ -5,7 +5,7 @@ #include "Telemetry.h" #include -#include +#include #include #include @@ -14,7 +14,6 @@ #include "Instance.h" #include "Notifier.h" #include "SourceImpl.h" -#include "cscore_cpp.h" using namespace cs; diff --git a/cscore/src/main/native/cpp/cscore_c.cpp b/cscore/src/main/native/cpp/cscore_c.cpp index 521a1ffa501..b55d6979955 100644 --- a/cscore/src/main/native/cpp/cscore_c.cpp +++ b/cscore/src/main/native/cpp/cscore_c.cpp @@ -4,15 +4,17 @@ #include "cscore_c.h" +#include #include #include +#include +#include #include #include #include "c_util.h" #include "cscore_cpp.h" -#include "cscore_raw.h" static CS_Event ConvertToC(const cs::RawEvent& rawEvent) { CS_Event event; diff --git a/cscore/src/main/native/cpp/cscore_cpp.cpp b/cscore/src/main/native/cpp/cscore_cpp.cpp index a46b805c01f..f0414f40100 100644 --- a/cscore/src/main/native/cpp/cscore_cpp.cpp +++ b/cscore/src/main/native/cpp/cscore_cpp.cpp @@ -4,13 +4,16 @@ #include "cscore_cpp.h" +#include +#include +#include + #include #include #include #include "Handle.h" #include "Instance.h" -#include "Log.h" #include "NetworkListener.h" #include "Notifier.h" #include "PropertyContainer.h" diff --git a/cscore/src/main/native/cpp/cscore_oo.cpp b/cscore/src/main/native/cpp/cscore_oo.cpp index cca5ba73dde..457fb1870c3 100644 --- a/cscore/src/main/native/cpp/cscore_oo.cpp +++ b/cscore/src/main/native/cpp/cscore_oo.cpp @@ -4,6 +4,9 @@ #include "cscore_oo.h" +#include +#include + #include #include diff --git a/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp b/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp index 6c133762122..b000894310b 100644 --- a/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp +++ b/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp @@ -2,8 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. -#include +#include #include +#include #include diff --git a/cscore/src/main/native/linux/NetworkListener.cpp b/cscore/src/main/native/linux/NetworkListener.cpp index 9771cfa20f8..e84ae8f4ac0 100644 --- a/cscore/src/main/native/linux/NetworkListener.cpp +++ b/cscore/src/main/native/linux/NetworkListener.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include diff --git a/cscore/src/main/native/linux/NetworkUtil.cpp b/cscore/src/main/native/linux/NetworkUtil.cpp index 43e0fa8cd1f..7a7b1ef2cec 100644 --- a/cscore/src/main/native/linux/NetworkUtil.cpp +++ b/cscore/src/main/native/linux/NetworkUtil.cpp @@ -9,6 +9,9 @@ #include #include +#include +#include + namespace cs { std::vector GetNetworkInterfaces() { diff --git a/cscore/src/main/native/linux/UsbCameraImpl.cpp b/cscore/src/main/native/linux/UsbCameraImpl.cpp index eca6ab77975..e46bb1402ff 100644 --- a/cscore/src/main/native/linux/UsbCameraImpl.cpp +++ b/cscore/src/main/native/linux/UsbCameraImpl.cpp @@ -21,6 +21,9 @@ #include #include +#include +#include +#include #include #include @@ -30,7 +33,6 @@ #include #include -#include "Handle.h" #include "Instance.h" #include "JpegUtil.h" #include "Log.h" diff --git a/cscore/src/main/native/linux/UsbCameraListener.cpp b/cscore/src/main/native/linux/UsbCameraListener.cpp index c5a993470c4..70aac34bb9e 100644 --- a/cscore/src/main/native/linux/UsbCameraListener.cpp +++ b/cscore/src/main/native/linux/UsbCameraListener.cpp @@ -4,6 +4,8 @@ #include "UsbCameraListener.h" +#include + #include #include #include diff --git a/cscore/src/main/native/linux/UsbCameraProperty.cpp b/cscore/src/main/native/linux/UsbCameraProperty.cpp index d6bb9804f6e..d8847d17657 100644 --- a/cscore/src/main/native/linux/UsbCameraProperty.cpp +++ b/cscore/src/main/native/linux/UsbCameraProperty.cpp @@ -4,6 +4,10 @@ #include "UsbCameraProperty.h" +#include +#include +#include + #include #include #include diff --git a/cscore/src/main/native/linux/UsbUtil.cpp b/cscore/src/main/native/linux/UsbUtil.cpp index fc6cbd29712..620871db0bd 100644 --- a/cscore/src/main/native/linux/UsbUtil.cpp +++ b/cscore/src/main/native/linux/UsbUtil.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include #include @@ -16,7 +18,6 @@ #include #include "Instance.h" -#include "Log.h" namespace cs { diff --git a/cscore/src/main/native/osx/NetworkUtil.cpp b/cscore/src/main/native/osx/NetworkUtil.cpp index 0aaf53537fc..f45e0b5964d 100644 --- a/cscore/src/main/native/osx/NetworkUtil.cpp +++ b/cscore/src/main/native/osx/NetworkUtil.cpp @@ -2,6 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include + #include "cscore_cpp.h" namespace cs { diff --git a/cscore/src/main/native/windows/COMCreators.cpp b/cscore/src/main/native/windows/COMCreators.cpp index 5ccddff2671..f3a1e56e5ca 100644 --- a/cscore/src/main/native/windows/COMCreators.cpp +++ b/cscore/src/main/native/windows/COMCreators.cpp @@ -13,13 +13,13 @@ // https://github.com/opencv/opencv/blob/master/modules/videoio/src/cap_msmf.cpp -#include -#include #include #include #include #include +#include + #include "COMCreators.h" #include "ComPtr.h" diff --git a/cscore/src/main/native/windows/NetworkUtil.cpp b/cscore/src/main/native/windows/NetworkUtil.cpp index 86b99bc2493..f3ab681470c 100644 --- a/cscore/src/main/native/windows/NetworkUtil.cpp +++ b/cscore/src/main/native/windows/NetworkUtil.cpp @@ -5,6 +5,9 @@ #include #include +#include +#include + #include "cscore_cpp.h" #pragma comment(lib, "Ws2_32.lib") diff --git a/cscore/src/main/native/windows/UsbCameraImpl.cpp b/cscore/src/main/native/windows/UsbCameraImpl.cpp index 606ceb2145d..1f180a142ca 100644 --- a/cscore/src/main/native/windows/UsbCameraImpl.cpp +++ b/cscore/src/main/native/windows/UsbCameraImpl.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/cscore/src/main/native/windows/UsbCameraListener.cpp b/cscore/src/main/native/windows/UsbCameraListener.cpp index be33771ab82..ec2d07617ad 100644 --- a/cscore/src/main/native/windows/UsbCameraListener.cpp +++ b/cscore/src/main/native/windows/UsbCameraListener.cpp @@ -9,6 +9,8 @@ #include // NOLINT(build/include_order) +#include + #define IDT_TIMER1 1001 using namespace cs; diff --git a/datalogtool/CMakeLists.txt b/datalogtool/CMakeLists.txt index 00b760e14a9..ba9475d2eb7 100644 --- a/datalogtool/CMakeLists.txt +++ b/datalogtool/CMakeLists.txt @@ -25,8 +25,7 @@ add_executable( ${APP_ICON_MACOSX} ) wpilib_link_macos_gui(datalogtool) -target_link_libraries(datalogtool libglass ${LIBSSH_LIBRARIES}) -target_include_directories(datalogtool SYSTEM PRIVATE ${LIBSSH_INCLUDE_DIRS}) +target_link_libraries(datalogtool libglass ssh) if(WIN32) set_target_properties(datalogtool PROPERTIES WIN32_EXECUTABLE YES) diff --git a/datalogtool/src/main/native/cpp/Downloader.cpp b/datalogtool/src/main/native/cpp/Downloader.cpp index 0a8b90dceeb..84b186db2bf 100644 --- a/datalogtool/src/main/native/cpp/Downloader.cpp +++ b/datalogtool/src/main/native/cpp/Downloader.cpp @@ -13,6 +13,9 @@ #include #include +#include +#include +#include #include #include diff --git a/datalogtool/src/main/native/cpp/Exporter.cpp b/datalogtool/src/main/native/cpp/Exporter.cpp index afca913e64d..a1213f40b62 100644 --- a/datalogtool/src/main/native/cpp/Exporter.cpp +++ b/datalogtool/src/main/native/cpp/Exporter.cpp @@ -6,12 +6,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -180,17 +182,16 @@ InputFile::~InputFile() { } static std::unique_ptr LoadDataLog(std::string_view filename) { - std::error_code ec; - auto buf = wpi::MemoryBuffer::GetFile(filename, ec); - std::string fn{filename}; - if (ec) { + auto fileBuffer = wpi::MemoryBuffer::GetFile(filename); + if (!fileBuffer) { return std::make_unique( - fn, fmt::format("Could not open file: {}", ec.message())); + filename, + fmt::format("Could not open file: {}", fileBuffer.error().message())); } - wpi::log::DataLogReader reader{std::move(buf)}; + wpi::log::DataLogReader reader{std::move(*fileBuffer)}; if (!reader.IsValid()) { - return std::make_unique(fn, "Not a valid datalog file"); + return std::make_unique(filename, "Not a valid datalog file"); } return std::make_unique( diff --git a/datalogtool/src/main/native/cpp/Sftp.cpp b/datalogtool/src/main/native/cpp/Sftp.cpp index 3a33d13afe3..42f2d039ac5 100644 --- a/datalogtool/src/main/native/cpp/Sftp.cpp +++ b/datalogtool/src/main/native/cpp/Sftp.cpp @@ -4,6 +4,10 @@ #include "Sftp.h" +#include +#include +#include + #include using namespace sftp; diff --git a/glass/src/app/native/cpp/main.cpp b/glass/src/app/native/cpp/main.cpp index ec0c2c0ddd6..63715b25780 100644 --- a/glass/src/app/native/cpp/main.cpp +++ b/glass/src/app/native/cpp/main.cpp @@ -3,6 +3,7 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include #include @@ -14,7 +15,6 @@ #include "glass/Context.h" #include "glass/MainMenuBar.h" -#include "glass/Model.h" #include "glass/Storage.h" #include "glass/View.h" #include "glass/networktables/NetworkTables.h" diff --git a/glass/src/lib/native/cpp/Context.cpp b/glass/src/lib/native/cpp/Context.cpp index 5adcd943bb1..be837e64b55 100644 --- a/glass/src/lib/native/cpp/Context.cpp +++ b/glass/src/lib/native/cpp/Context.cpp @@ -4,9 +4,10 @@ #include "glass/Context.h" -#include -#include #include +#include +#include +#include #include #include @@ -128,50 +129,44 @@ static bool JsonToWindow(const wpi::json& jfile, const char* filename) { } static bool LoadWindowStorageImpl(const std::string& filename) { - std::error_code ec; - std::unique_ptr fileBuffer = - wpi::MemoryBuffer::GetFile(filename, ec); - if (fileBuffer == nullptr || ec) { + auto fileBuffer = wpi::MemoryBuffer::GetFile(filename); + if (!fileBuffer) { ImGui::LogText("error opening %s: %s", filename.c_str(), - ec.message().c_str()); + fileBuffer.error().message().c_str()); + return false; + } + try { + return JsonToWindow(wpi::json::parse(fileBuffer.value()->GetCharBuffer()), + filename.c_str()); + } catch (wpi::json::parse_error& e) { + ImGui::LogText("Error loading %s: %s", filename.c_str(), e.what()); return false; - } else { - try { - return JsonToWindow(wpi::json::parse(fileBuffer->GetCharBuffer()), - filename.c_str()); - } catch (wpi::json::parse_error& e) { - ImGui::LogText("Error loading %s: %s", filename.c_str(), e.what()); - return false; - } } } static bool LoadStorageRootImpl(Context* ctx, const std::string& filename, std::string_view rootName) { - std::error_code ec; - std::unique_ptr fileBuffer = - wpi::MemoryBuffer::GetFile(filename, ec); - if (fileBuffer == nullptr || ec) { + auto fileBuffer = wpi::MemoryBuffer::GetFile(filename); + if (!fileBuffer) { ImGui::LogText("error opening %s: %s", filename.c_str(), - ec.message().c_str()); + fileBuffer.error().message().c_str()); return false; - } else { - auto& storage = ctx->storageRoots[rootName]; - bool createdStorage = false; - if (!storage) { - storage = std::make_unique(); - createdStorage = true; - } - try { - storage->FromJson(wpi::json::parse(fileBuffer->GetCharBuffer()), - filename.c_str()); - } catch (wpi::json::parse_error& e) { - ImGui::LogText("Error loading %s: %s", filename.c_str(), e.what()); - if (createdStorage) { - ctx->storageRoots.erase(rootName); - } - return false; + } + auto& storage = ctx->storageRoots[rootName]; + bool createdStorage = false; + if (!storage) { + storage = std::make_unique(); + createdStorage = true; + } + try { + storage->FromJson(wpi::json::parse(fileBuffer.value()->GetCharBuffer()), + filename.c_str()); + } catch (wpi::json::parse_error& e) { + ImGui::LogText("Error loading %s: %s", filename.c_str(), e.what()); + if (createdStorage) { + ctx->storageRoots.erase(rootName); } + return false; } return true; } diff --git a/glass/src/lib/native/cpp/MainMenuBar.cpp b/glass/src/lib/native/cpp/MainMenuBar.cpp index b426df40fcb..97da26a9afd 100644 --- a/glass/src/lib/native/cpp/MainMenuBar.cpp +++ b/glass/src/lib/native/cpp/MainMenuBar.cpp @@ -4,6 +4,9 @@ #include "glass/MainMenuBar.h" +#include +#include + #include #include #include diff --git a/glass/src/lib/native/cpp/Storage.cpp b/glass/src/lib/native/cpp/Storage.cpp index 6cab4430b7a..f455212f61b 100644 --- a/glass/src/lib/native/cpp/Storage.cpp +++ b/glass/src/lib/native/cpp/Storage.cpp @@ -5,6 +5,10 @@ #include "glass/Storage.h" #include +#include +#include +#include +#include #include #include diff --git a/glass/src/lib/native/cpp/View.cpp b/glass/src/lib/native/cpp/View.cpp index 3f28200d7d7..1007603a5c3 100644 --- a/glass/src/lib/native/cpp/View.cpp +++ b/glass/src/lib/native/cpp/View.cpp @@ -4,6 +4,9 @@ #include "glass/View.h" +#include +#include + using namespace glass; namespace { diff --git a/glass/src/lib/native/cpp/WindowManager.cpp b/glass/src/lib/native/cpp/WindowManager.cpp index 8e76b5f87a4..3d90be5624b 100644 --- a/glass/src/lib/native/cpp/WindowManager.cpp +++ b/glass/src/lib/native/cpp/WindowManager.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include diff --git a/glass/src/lib/native/cpp/hardware/AnalogInput.cpp b/glass/src/lib/native/cpp/hardware/AnalogInput.cpp index a2051cf6b49..8c45f011386 100644 --- a/glass/src/lib/native/cpp/hardware/AnalogInput.cpp +++ b/glass/src/lib/native/cpp/hardware/AnalogInput.cpp @@ -4,6 +4,8 @@ #include "glass/hardware/AnalogInput.h" +#include + #include #include diff --git a/glass/src/lib/native/cpp/hardware/AnalogOutput.cpp b/glass/src/lib/native/cpp/hardware/AnalogOutput.cpp index 2436dd28f41..11790f8ca8d 100644 --- a/glass/src/lib/native/cpp/hardware/AnalogOutput.cpp +++ b/glass/src/lib/native/cpp/hardware/AnalogOutput.cpp @@ -4,6 +4,8 @@ #include "glass/hardware/AnalogOutput.h" +#include + #include #include "glass/Context.h" diff --git a/glass/src/lib/native/cpp/hardware/Encoder.cpp b/glass/src/lib/native/cpp/hardware/Encoder.cpp index b359274e5a4..b74547c735a 100644 --- a/glass/src/lib/native/cpp/hardware/Encoder.cpp +++ b/glass/src/lib/native/cpp/hardware/Encoder.cpp @@ -4,6 +4,8 @@ #include "glass/hardware/Encoder.h" +#include + #include #include #include diff --git a/glass/src/lib/native/cpp/hardware/LEDDisplay.cpp b/glass/src/lib/native/cpp/hardware/LEDDisplay.cpp index c3c2406dbcb..6ad7fc54a74 100644 --- a/glass/src/lib/native/cpp/hardware/LEDDisplay.cpp +++ b/glass/src/lib/native/cpp/hardware/LEDDisplay.cpp @@ -4,6 +4,8 @@ #include "glass/hardware/LEDDisplay.h" +#include + #include #include "glass/Context.h" diff --git a/glass/src/lib/native/cpp/hardware/PWM.cpp b/glass/src/lib/native/cpp/hardware/PWM.cpp index f719a2b15aa..6f58fbaff02 100644 --- a/glass/src/lib/native/cpp/hardware/PWM.cpp +++ b/glass/src/lib/native/cpp/hardware/PWM.cpp @@ -4,6 +4,8 @@ #include "glass/hardware/PWM.h" +#include + #include #include diff --git a/glass/src/lib/native/cpp/hardware/Pneumatic.cpp b/glass/src/lib/native/cpp/hardware/Pneumatic.cpp index 10ec61e142b..bc39860dbb4 100644 --- a/glass/src/lib/native/cpp/hardware/Pneumatic.cpp +++ b/glass/src/lib/native/cpp/hardware/Pneumatic.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/glass/src/lib/native/cpp/hardware/Relay.cpp b/glass/src/lib/native/cpp/hardware/Relay.cpp index e071de7d3ca..ff383d0fa5f 100644 --- a/glass/src/lib/native/cpp/hardware/Relay.cpp +++ b/glass/src/lib/native/cpp/hardware/Relay.cpp @@ -4,6 +4,8 @@ #include "glass/hardware/Relay.h" +#include + #include #include "glass/Context.h" diff --git a/glass/src/lib/native/cpp/other/DeviceTree.cpp b/glass/src/lib/native/cpp/other/DeviceTree.cpp index b242c07b46c..2360d83386a 100644 --- a/glass/src/lib/native/cpp/other/DeviceTree.cpp +++ b/glass/src/lib/native/cpp/other/DeviceTree.cpp @@ -5,6 +5,7 @@ #include "glass/other/DeviceTree.h" #include +#include #include #include diff --git a/glass/src/lib/native/cpp/other/FMS.cpp b/glass/src/lib/native/cpp/other/FMS.cpp index 4e702e5b481..86ed0205a7a 100644 --- a/glass/src/lib/native/cpp/other/FMS.cpp +++ b/glass/src/lib/native/cpp/other/FMS.cpp @@ -4,6 +4,8 @@ #include "glass/other/FMS.h" +#include + #include #include #include diff --git a/glass/src/lib/native/cpp/other/Field2D.cpp b/glass/src/lib/native/cpp/other/Field2D.cpp index be6cca6485f..505a9d60550 100644 --- a/glass/src/lib/native/cpp/other/Field2D.cpp +++ b/glass/src/lib/native/cpp/other/Field2D.cpp @@ -8,8 +8,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -540,16 +542,14 @@ bool FieldInfo::LoadJson(std::span is, std::string_view filename) { } void FieldInfo::LoadJsonFile(std::string_view jsonfile) { - std::error_code ec; - std::unique_ptr fileBuffer = - wpi::MemoryBuffer::GetFile(jsonfile, ec); - if (fileBuffer == nullptr || ec) { + auto fileBuffer = wpi::MemoryBuffer::GetFile(jsonfile); + if (!fileBuffer) { std::fputs("GUI: could not open field JSON file\n", stderr); return; } - LoadJson( - {reinterpret_cast(fileBuffer->begin()), fileBuffer->size()}, - jsonfile); + LoadJson({reinterpret_cast(fileBuffer.value()->begin()), + fileBuffer.value()->size()}, + jsonfile); } bool FieldInfo::LoadImageImpl(const std::string& fn) { diff --git a/glass/src/lib/native/cpp/other/Log.cpp b/glass/src/lib/native/cpp/other/Log.cpp index accf024063e..4209338526f 100644 --- a/glass/src/lib/native/cpp/other/Log.cpp +++ b/glass/src/lib/native/cpp/other/Log.cpp @@ -4,6 +4,8 @@ #include "glass/other/Log.h" +#include + #include using namespace glass; diff --git a/glass/src/lib/native/cpp/other/Mechanism2D.cpp b/glass/src/lib/native/cpp/other/Mechanism2D.cpp index 0592910d049..b09acf81d30 100644 --- a/glass/src/lib/native/cpp/other/Mechanism2D.cpp +++ b/glass/src/lib/native/cpp/other/Mechanism2D.cpp @@ -8,8 +8,10 @@ #include #include #include +#include #include #include +#include #include #include diff --git a/glass/src/lib/native/cpp/other/Plot.cpp b/glass/src/lib/native/cpp/other/Plot.cpp index 0b617098541..56fc04d099d 100644 --- a/glass/src/lib/native/cpp/other/Plot.cpp +++ b/glass/src/lib/native/cpp/other/Plot.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include "glass/Context.h" diff --git a/glass/src/lib/native/cpp/other/Subsystem.cpp b/glass/src/lib/native/cpp/other/Subsystem.cpp index c4ed4746deb..b8bbb5b06d0 100644 --- a/glass/src/lib/native/cpp/other/Subsystem.cpp +++ b/glass/src/lib/native/cpp/other/Subsystem.cpp @@ -4,10 +4,9 @@ #include "glass/other/Subsystem.h" -#include +#include -#include "glass/Context.h" -#include "glass/DataSource.h" +#include using namespace glass; diff --git a/glass/src/lib/native/cpp/support/DataLogReaderThread.cpp b/glass/src/lib/native/cpp/support/DataLogReaderThread.cpp index b9fdb445631..c4336f65567 100644 --- a/glass/src/lib/native/cpp/support/DataLogReaderThread.cpp +++ b/glass/src/lib/native/cpp/support/DataLogReaderThread.cpp @@ -4,6 +4,7 @@ #include "glass/support/DataLogReaderThread.h" +#include #include #include @@ -109,11 +110,13 @@ void DataLogReaderThread::ReadMain() { schema, err); } } else if (auto filename = wpi::remove_prefix(name, "/.schema/proto:")) { +#ifndef NO_PROTOBUF // protobuf descriptor handling if (!m_protoDb.Add(*filename, data)) { wpi::print("could not decode protobuf '{}' filename '{}'\n", name, *filename); } +#endif } } diff --git a/glass/src/lib/native/cpp/support/EnumSetting.cpp b/glass/src/lib/native/cpp/support/EnumSetting.cpp index b863b70ab89..167cf1b7d25 100644 --- a/glass/src/lib/native/cpp/support/EnumSetting.cpp +++ b/glass/src/lib/native/cpp/support/EnumSetting.cpp @@ -4,6 +4,8 @@ #include "glass/support/EnumSetting.h" +#include + #include using namespace glass; diff --git a/glass/src/lib/native/cpp/support/ExpressionParser.cpp b/glass/src/lib/native/cpp/support/ExpressionParser.cpp index 6522b3cf8be..c7bb1a72eb2 100644 --- a/glass/src/lib/native/cpp/support/ExpressionParser.cpp +++ b/glass/src/lib/native/cpp/support/ExpressionParser.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/glass/src/lib/native/include/glass/support/DataLogReaderThread.h b/glass/src/lib/native/include/glass/support/DataLogReaderThread.h index bcbc9623ef8..2cfb89e39be 100644 --- a/glass/src/lib/native/include/glass/support/DataLogReaderThread.h +++ b/glass/src/lib/native/include/glass/support/DataLogReaderThread.h @@ -17,9 +17,12 @@ #include #include #include -#include #include +#ifndef NO_PROTOBUF +#include +#endif + namespace glass { class DataLogReaderRange { @@ -75,7 +78,9 @@ class DataLogReaderThread { } wpi::StructDescriptorDatabase& GetStructDatabase() { return m_structDb; } +#ifndef NO_PROTOBUF wpi::ProtobufMessageDatabase& GetProtobufDatabase() { return m_protoDb; } +#endif const wpi::log::DataLogReader& GetReader() const { return m_reader; } @@ -94,7 +99,9 @@ class DataLogReaderThread { std::map> m_entriesByName; wpi::DenseMap m_entriesById; wpi::StructDescriptorDatabase m_structDb; +#ifndef NO_PROTOBUF wpi::ProtobufMessageDatabase m_protoDb; +#endif std::thread m_thread; }; diff --git a/glass/src/libnt/native/cpp/NTCommandScheduler.cpp b/glass/src/libnt/native/cpp/NTCommandScheduler.cpp index 26a5740c78a..eef0c1a40cf 100644 --- a/glass/src/libnt/native/cpp/NTCommandScheduler.cpp +++ b/glass/src/libnt/native/cpp/NTCommandScheduler.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTCommandScheduler.h" +#include + #include #include diff --git a/glass/src/libnt/native/cpp/NTCommandSelector.cpp b/glass/src/libnt/native/cpp/NTCommandSelector.cpp index 64c616e4b18..ce8f8a2e48f 100644 --- a/glass/src/libnt/native/cpp/NTCommandSelector.cpp +++ b/glass/src/libnt/native/cpp/NTCommandSelector.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTCommandSelector.h" +#include + #include #include diff --git a/glass/src/libnt/native/cpp/NTDifferentialDrive.cpp b/glass/src/libnt/native/cpp/NTDifferentialDrive.cpp index 57d1fa837c1..58de26f392c 100644 --- a/glass/src/libnt/native/cpp/NTDifferentialDrive.cpp +++ b/glass/src/libnt/native/cpp/NTDifferentialDrive.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTDifferentialDrive.h" +#include + #include #include #include diff --git a/glass/src/libnt/native/cpp/NTDigitalInput.cpp b/glass/src/libnt/native/cpp/NTDigitalInput.cpp index 28b916cfbba..e96a041e5fa 100644 --- a/glass/src/libnt/native/cpp/NTDigitalInput.cpp +++ b/glass/src/libnt/native/cpp/NTDigitalInput.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTDigitalInput.h" +#include + #include #include diff --git a/glass/src/libnt/native/cpp/NTDigitalOutput.cpp b/glass/src/libnt/native/cpp/NTDigitalOutput.cpp index aa9200dc705..fe9021f97ef 100644 --- a/glass/src/libnt/native/cpp/NTDigitalOutput.cpp +++ b/glass/src/libnt/native/cpp/NTDigitalOutput.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTDigitalOutput.h" +#include + #include using namespace glass; diff --git a/glass/src/libnt/native/cpp/NTField2D.cpp b/glass/src/libnt/native/cpp/NTField2D.cpp index 1fd87377570..a9ed6f650e1 100644 --- a/glass/src/libnt/native/cpp/NTField2D.cpp +++ b/glass/src/libnt/native/cpp/NTField2D.cpp @@ -5,6 +5,9 @@ #include "glass/networktables/NTField2D.h" #include +#include +#include +#include #include #include diff --git a/glass/src/libnt/native/cpp/NTGyro.cpp b/glass/src/libnt/native/cpp/NTGyro.cpp index a036b39c53d..1a078f57a25 100644 --- a/glass/src/libnt/native/cpp/NTGyro.cpp +++ b/glass/src/libnt/native/cpp/NTGyro.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTGyro.h" +#include + #include #include diff --git a/glass/src/libnt/native/cpp/NTMecanumDrive.cpp b/glass/src/libnt/native/cpp/NTMecanumDrive.cpp index cb564e81689..f090cfcf6f4 100644 --- a/glass/src/libnt/native/cpp/NTMecanumDrive.cpp +++ b/glass/src/libnt/native/cpp/NTMecanumDrive.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTMecanumDrive.h" +#include + #include #include #include diff --git a/glass/src/libnt/native/cpp/NTMechanism2D.cpp b/glass/src/libnt/native/cpp/NTMechanism2D.cpp index 3954936d2ca..d98da48d47a 100644 --- a/glass/src/libnt/native/cpp/NTMechanism2D.cpp +++ b/glass/src/libnt/native/cpp/NTMechanism2D.cpp @@ -5,6 +5,8 @@ #include "glass/networktables/NTMechanism2D.h" #include +#include +#include #include #include diff --git a/glass/src/libnt/native/cpp/NTMotorController.cpp b/glass/src/libnt/native/cpp/NTMotorController.cpp index 1de6714fbf2..d28b8dd983b 100644 --- a/glass/src/libnt/native/cpp/NTMotorController.cpp +++ b/glass/src/libnt/native/cpp/NTMotorController.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTMotorController.h" +#include + #include #include diff --git a/glass/src/libnt/native/cpp/NTPIDController.cpp b/glass/src/libnt/native/cpp/NTPIDController.cpp index 9796f6d4471..49037abab4a 100644 --- a/glass/src/libnt/native/cpp/NTPIDController.cpp +++ b/glass/src/libnt/native/cpp/NTPIDController.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTPIDController.h" +#include + #include #include diff --git a/glass/src/libnt/native/cpp/NTProfiledPIDController.cpp b/glass/src/libnt/native/cpp/NTProfiledPIDController.cpp index 798864c313c..2beb829a4f7 100644 --- a/glass/src/libnt/native/cpp/NTProfiledPIDController.cpp +++ b/glass/src/libnt/native/cpp/NTProfiledPIDController.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTProfiledPIDController.h" +#include + #include #include diff --git a/glass/src/libnt/native/cpp/NTStringChooser.cpp b/glass/src/libnt/native/cpp/NTStringChooser.cpp index f0fad43843a..92c2a4bd035 100644 --- a/glass/src/libnt/native/cpp/NTStringChooser.cpp +++ b/glass/src/libnt/native/cpp/NTStringChooser.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTStringChooser.h" +#include + #include #include diff --git a/glass/src/libnt/native/cpp/NTSubsystem.cpp b/glass/src/libnt/native/cpp/NTSubsystem.cpp index 3078f87fc40..28a8e7bf482 100644 --- a/glass/src/libnt/native/cpp/NTSubsystem.cpp +++ b/glass/src/libnt/native/cpp/NTSubsystem.cpp @@ -4,6 +4,8 @@ #include "glass/networktables/NTSubsystem.h" +#include + #include using namespace glass; diff --git a/glass/src/libnt/native/cpp/NetworkTables.cpp b/glass/src/libnt/native/cpp/NetworkTables.cpp index 0f249ca340a..179de1fad21 100644 --- a/glass/src/libnt/native/cpp/NetworkTables.cpp +++ b/glass/src/libnt/native/cpp/NetworkTables.cpp @@ -4,18 +4,21 @@ #include "glass/networktables/NetworkTables.h" +#include #include #include #include +#include #include +#include #include #include +#include #include +#include #include #include -#include -#include #include #include #include @@ -31,6 +34,11 @@ #include #include +#ifndef NO_PROTOBUF +#include +#include +#endif + #include "glass/Context.h" #include "glass/DataSource.h" #include "glass/Storage.h" @@ -346,6 +354,7 @@ static void UpdateStructValueSource(NetworkTablesModel& model, } } +#ifndef NO_PROTOBUF static void UpdateProtobufValueSource(NetworkTablesModel& model, NetworkTablesModel::ValueSource* out, const google::protobuf::Message& msg, @@ -534,6 +543,7 @@ static void UpdateProtobufValueSource(NetworkTablesModel& model, } } } +#endif static void UpdateJsonValueSource(NetworkTablesModel& model, NetworkTablesModel::ValueSource* out, @@ -764,6 +774,7 @@ void NetworkTablesModel::ValueSource::UpdateFromValue( valueChildren.clear(); } } else if (auto filename = wpi::remove_prefix(typeStr, "proto:")) { +#ifndef NO_PROTOBUF auto msg = model.m_protoDb.Find(*filename); if (msg) { msg->Clear(); @@ -777,6 +788,9 @@ void NetworkTablesModel::ValueSource::UpdateFromValue( } else { valueChildren.clear(); } +#else + valueChildren.clear(); +#endif } else { valueChildren.clear(); } @@ -902,6 +916,7 @@ void NetworkTablesModel::Update() { wpi::remove_prefix(entry->info.name, "/.schema/proto:"); entry->value.IsRaw() && filename && entry->info.type_str == "proto:FileDescriptorProto") { +#ifndef NO_PROTOBUF // protobuf descriptor handling if (!m_protoDb.Add(*filename, entry->value.GetRaw())) { wpi::print("could not decode protobuf '{}' filename '{}'\n", @@ -918,6 +933,7 @@ void NetworkTablesModel::Update() { } } } +#endif } } } diff --git a/glass/src/libnt/native/cpp/NetworkTablesProvider.cpp b/glass/src/libnt/native/cpp/NetworkTablesProvider.cpp index 414c2a331d4..36e892ecaa0 100644 --- a/glass/src/libnt/native/cpp/NetworkTablesProvider.cpp +++ b/glass/src/libnt/native/cpp/NetworkTablesProvider.cpp @@ -5,6 +5,8 @@ #include "glass/networktables/NetworkTablesProvider.h" #include +#include +#include #include #include diff --git a/glass/src/libnt/native/cpp/NetworkTablesSettings.cpp b/glass/src/libnt/native/cpp/NetworkTablesSettings.cpp index 33c4f02e4c5..bca067f779d 100644 --- a/glass/src/libnt/native/cpp/NetworkTablesSettings.cpp +++ b/glass/src/libnt/native/cpp/NetworkTablesSettings.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/glass/src/libnt/native/cpp/StandardNetworkTables.cpp b/glass/src/libnt/native/cpp/StandardNetworkTables.cpp index 4cc21212690..05796c39a76 100644 --- a/glass/src/libnt/native/cpp/StandardNetworkTables.cpp +++ b/glass/src/libnt/native/cpp/StandardNetworkTables.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include "glass/networktables/NTCommandScheduler.h" #include "glass/networktables/NTCommandSelector.h" #include "glass/networktables/NTDifferentialDrive.h" diff --git a/glass/src/libnt/native/include/glass/networktables/NetworkTables.h b/glass/src/libnt/native/include/glass/networktables/NetworkTables.h index 8416cf9dfdb..bca5a411925 100644 --- a/glass/src/libnt/native/include/glass/networktables/NetworkTables.h +++ b/glass/src/libnt/native/include/glass/networktables/NetworkTables.h @@ -18,9 +18,12 @@ #include #include #include -#include #include +#ifndef NO_PROTOBUF +#include +#endif + #include "glass/Model.h" #include "glass/View.h" @@ -168,7 +171,9 @@ class NetworkTablesModel : public Model { Entry* AddEntry(NT_Topic topic); wpi::StructDescriptorDatabase& GetStructDatabase() { return m_structDb; } +#ifndef NO_PROTOBUF wpi::ProtobufMessageDatabase& GetProtobufDatabase() { return m_protoDb; } +#endif private: void RebuildTree(); @@ -191,7 +196,9 @@ class NetworkTablesModel : public Model { Client m_server; wpi::StructDescriptorDatabase m_structDb; +#ifndef NO_PROTOBUF wpi::ProtobufMessageDatabase m_protoDb; +#endif }; using NetworkTablesFlags = int; diff --git a/hal/src/main/native/athena/AddressableLED.cpp b/hal/src/main/native/athena/AddressableLED.cpp index 05fe5def2b4..8aaa2f33b78 100644 --- a/hal/src/main/native/athena/AddressableLED.cpp +++ b/hal/src/main/native/athena/AddressableLED.cpp @@ -5,6 +5,7 @@ #include "hal/AddressableLED.h" #include +#include #include diff --git a/hal/src/main/native/athena/AnalogInternal.cpp b/hal/src/main/native/athena/AnalogInternal.cpp index 7ae6adc2b50..47dd1bdbb58 100644 --- a/hal/src/main/native/athena/AnalogInternal.cpp +++ b/hal/src/main/native/athena/AnalogInternal.cpp @@ -5,6 +5,7 @@ #include "AnalogInternal.h" #include +#include #include diff --git a/hal/src/main/native/athena/AnalogTrigger.cpp b/hal/src/main/native/athena/AnalogTrigger.cpp index 2e72a43a395..e90b55e3f5f 100644 --- a/hal/src/main/native/athena/AnalogTrigger.cpp +++ b/hal/src/main/native/athena/AnalogTrigger.cpp @@ -4,6 +4,8 @@ #include "hal/AnalogTrigger.h" +#include + #include "AnalogInternal.h" #include "ConstantsInternal.h" #include "DutyCycleInternal.h" diff --git a/hal/src/main/native/athena/CANAPI.cpp b/hal/src/main/native/athena/CANAPI.cpp index c69bc748269..751b0253f55 100644 --- a/hal/src/main/native/athena/CANAPI.cpp +++ b/hal/src/main/native/athena/CANAPI.cpp @@ -5,6 +5,7 @@ #include "hal/CANAPI.h" #include +#include #include #include diff --git a/hal/src/main/native/athena/CTREPCM.cpp b/hal/src/main/native/athena/CTREPCM.cpp index 79c1ae39833..ba3da88bbfb 100644 --- a/hal/src/main/native/athena/CTREPCM.cpp +++ b/hal/src/main/native/athena/CTREPCM.cpp @@ -4,6 +4,8 @@ #include "hal/CTREPCM.h" +#include + #include #include "HALInitializer.h" diff --git a/hal/src/main/native/athena/CTREPDP.cpp b/hal/src/main/native/athena/CTREPDP.cpp index 21896ec7785..571240d62e5 100644 --- a/hal/src/main/native/athena/CTREPDP.cpp +++ b/hal/src/main/native/athena/CTREPDP.cpp @@ -4,6 +4,8 @@ #include "CTREPDP.h" +#include + #include #include diff --git a/hal/src/main/native/athena/Counter.cpp b/hal/src/main/native/athena/Counter.cpp index bb8da37098e..5259cbff99b 100644 --- a/hal/src/main/native/athena/Counter.cpp +++ b/hal/src/main/native/athena/Counter.cpp @@ -5,6 +5,7 @@ #include "hal/Counter.h" #include +#include #include diff --git a/hal/src/main/native/athena/DigitalInternal.cpp b/hal/src/main/native/athena/DigitalInternal.cpp index 13fa560d197..dc41fc81814 100644 --- a/hal/src/main/native/athena/DigitalInternal.cpp +++ b/hal/src/main/native/athena/DigitalInternal.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/hal/src/main/native/athena/Encoder.cpp b/hal/src/main/native/athena/Encoder.cpp index 1f50eb8b244..055ad163fa6 100644 --- a/hal/src/main/native/athena/Encoder.cpp +++ b/hal/src/main/native/athena/Encoder.cpp @@ -4,6 +4,8 @@ #include "hal/Encoder.h" +#include + #include #include "EncoderInternal.h" diff --git a/hal/src/main/native/athena/FRCDriverStation.cpp b/hal/src/main/native/athena/FRCDriverStation.cpp index e3080782b55..9891033039a 100644 --- a/hal/src/main/native/athena/FRCDriverStation.cpp +++ b/hal/src/main/native/athena/FRCDriverStation.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/hal/src/main/native/athena/HAL.cpp b/hal/src/main/native/athena/HAL.cpp index 7c5f1f64a97..d91d976fd53 100644 --- a/hal/src/main/native/athena/HAL.cpp +++ b/hal/src/main/native/athena/HAL.cpp @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include #include @@ -297,20 +299,15 @@ void HAL_GetSerialNumber(struct WPI_String* serialNumber) { void InitializeRoboRioComments(void) { if (!roboRioCommentsStringInitialized) { - std::error_code ec; - std::unique_ptr fileBuffer = - wpi::MemoryBuffer::GetFile("/etc/machine-info", ec); - - std::string_view fileContents; - if (fileBuffer && !ec) { - fileContents = - std::string_view(reinterpret_cast(fileBuffer->begin()), - fileBuffer->size()); - } else { + auto fileBuffer = wpi::MemoryBuffer::GetFile("/etc/machine-info"); + if (!fileBuffer) { roboRioCommentsStringSize = 0; roboRioCommentsStringInitialized = true; return; } + std::string_view fileContents{ + reinterpret_cast(fileBuffer.value()->begin()), + fileBuffer.value()->size()}; std::string_view searchString = "PRETTY_HOSTNAME=\""; size_t start = fileContents.find(searchString); diff --git a/hal/src/main/native/athena/REVPDH.cpp b/hal/src/main/native/athena/REVPDH.cpp index 053f6d06db9..86f2e34dc68 100644 --- a/hal/src/main/native/athena/REVPDH.cpp +++ b/hal/src/main/native/athena/REVPDH.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/hal/src/main/native/athena/REVPH.cpp b/hal/src/main/native/athena/REVPH.cpp index a7a6bb87bd9..bb3784c5c30 100644 --- a/hal/src/main/native/athena/REVPH.cpp +++ b/hal/src/main/native/athena/REVPH.cpp @@ -4,6 +4,7 @@ #include "hal/REVPH.h" +#include #include #include diff --git a/hal/src/main/native/athena/SPI.cpp b/hal/src/main/native/athena/SPI.cpp index 6c277a93ea3..8654af947d4 100644 --- a/hal/src/main/native/athena/SPI.cpp +++ b/hal/src/main/native/athena/SPI.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/hal/src/main/native/athena/cpp/SerialHelper.cpp b/hal/src/main/native/athena/cpp/SerialHelper.cpp index 71e747c070c..11d61872c74 100644 --- a/hal/src/main/native/athena/cpp/SerialHelper.cpp +++ b/hal/src/main/native/athena/cpp/SerialHelper.cpp @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include #include diff --git a/hal/src/main/native/cpp/jni/CANJNI.cpp b/hal/src/main/native/cpp/jni/CANJNI.cpp index 40838d3892c..40f77ddd5cc 100644 --- a/hal/src/main/native/cpp/jni/CANJNI.cpp +++ b/hal/src/main/native/cpp/jni/CANJNI.cpp @@ -176,7 +176,6 @@ Java_edu_wpi_first_hal_can_CANJNI_readCANStreamSession // OOM, just return elem = JLocal{env, CreateCANStreamMessage(env)}; if (elem) { - std::printf("Allocated and set object\n"); env->SetObjectArrayElement(messages, i, elem); } else { return 0; diff --git a/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp b/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp index d489bdd36e3..c001c2c5a1f 100644 --- a/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp +++ b/hal/src/main/native/cpp/jni/SimDeviceJNI.cpp @@ -4,6 +4,9 @@ #include +#include +#include + #include #include "HALUtil.h" diff --git a/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp index 38d9ce7ca42..00335b67be0 100644 --- a/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp +++ b/hal/src/main/native/cpp/jni/simulation/AddressableLEDDataJNI.cpp @@ -4,6 +4,8 @@ #include +#include + #include "CallbackStore.h" #include "ConstBufferCallbackStore.h" #include "edu_wpi_first_hal_simulation_AddressableLEDDataJNI.h" diff --git a/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.cpp b/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.cpp index f83ab625887..54fb3ecaba1 100644 --- a/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.cpp +++ b/hal/src/main/native/cpp/jni/simulation/BufferCallbackStore.cpp @@ -7,14 +7,13 @@ #include #include +#include #include #include "SimulatorJNI.h" #include "hal/Types.h" -#include "hal/Value.h" #include "hal/handles/UnlimitedHandleResource.h" -#include "hal/simulation/NotifyListener.h" using namespace hal; using namespace hal::sim; diff --git a/hal/src/main/native/cpp/jni/simulation/CallbackStore.cpp b/hal/src/main/native/cpp/jni/simulation/CallbackStore.cpp index f57dfb35418..f36478aaf2c 100644 --- a/hal/src/main/native/cpp/jni/simulation/CallbackStore.cpp +++ b/hal/src/main/native/cpp/jni/simulation/CallbackStore.cpp @@ -7,6 +7,7 @@ #include #include +#include #include @@ -14,7 +15,6 @@ #include "hal/Types.h" #include "hal/Value.h" #include "hal/handles/UnlimitedHandleResource.h" -#include "hal/simulation/NotifyListener.h" using namespace hal; using namespace hal::sim; diff --git a/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.cpp b/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.cpp index af57803ebd4..e8c8b3161d2 100644 --- a/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.cpp +++ b/hal/src/main/native/cpp/jni/simulation/ConstBufferCallbackStore.cpp @@ -7,14 +7,13 @@ #include #include +#include #include #include "SimulatorJNI.h" #include "hal/Types.h" -#include "hal/Value.h" #include "hal/handles/UnlimitedHandleResource.h" -#include "hal/simulation/NotifyListener.h" using namespace hal; using namespace hal::sim; diff --git a/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp b/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp index 98dab720b10..3d9e2cb1468 100644 --- a/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp +++ b/hal/src/main/native/cpp/jni/simulation/SimDeviceDataJNI.cpp @@ -7,13 +7,15 @@ #include #include +#include +#include #include +#include #include #include "SimulatorJNI.h" #include "edu_wpi_first_hal_simulation_SimDeviceDataJNI.h" -#include "hal/SimDevice.h" #include "hal/handles/UnlimitedHandleResource.h" #include "hal/simulation/SimDeviceData.h" diff --git a/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.cpp b/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.cpp index 5b2ff2bfcfe..3c58c945753 100644 --- a/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.cpp +++ b/hal/src/main/native/cpp/jni/simulation/SpiReadAutoReceiveBufferCallbackStore.cpp @@ -7,14 +7,13 @@ #include #include +#include #include #include "SimulatorJNI.h" #include "hal/Types.h" -#include "hal/Value.h" #include "hal/handles/UnlimitedHandleResource.h" -#include "hal/simulation/NotifyListener.h" using namespace hal; using namespace hal::sim; diff --git a/hal/src/main/native/sim/CANAPI.cpp b/hal/src/main/native/sim/CANAPI.cpp index 4689d1f4e4e..eaa42fa2a16 100644 --- a/hal/src/main/native/sim/CANAPI.cpp +++ b/hal/src/main/native/sim/CANAPI.cpp @@ -4,6 +4,8 @@ #include "hal/CANAPI.h" +#include + #include #include "CANAPIInternal.h" diff --git a/hal/src/main/native/sim/CTREPCM.cpp b/hal/src/main/native/sim/CTREPCM.cpp index 93f91356b91..9d06ecb6364 100644 --- a/hal/src/main/native/sim/CTREPCM.cpp +++ b/hal/src/main/native/sim/CTREPCM.cpp @@ -4,10 +4,11 @@ #include "hal/CTREPCM.h" +#include + #include "HALInitializer.h" #include "HALInternal.h" #include "PortsInternal.h" -#include "hal/CANAPI.h" #include "hal/Errors.h" #include "hal/handles/IndexedHandleResource.h" #include "mockdata/CTREPCMDataInternal.h" diff --git a/hal/src/main/native/sim/Encoder.cpp b/hal/src/main/native/sim/Encoder.cpp index 66ad87d2743..f7be2bdd9bd 100644 --- a/hal/src/main/native/sim/Encoder.cpp +++ b/hal/src/main/native/sim/Encoder.cpp @@ -4,6 +4,8 @@ #include "hal/Encoder.h" +#include + #include "CounterInternal.h" #include "HALInitializer.h" #include "HALInternal.h" diff --git a/hal/src/main/native/sim/Extensions.cpp b/hal/src/main/native/sim/Extensions.cpp index 95495c645d5..7d22f41fe55 100644 --- a/hal/src/main/native/sim/Extensions.cpp +++ b/hal/src/main/native/sim/Extensions.cpp @@ -5,7 +5,9 @@ #include "hal/Extensions.h" #include +#include #include +#include #include #include diff --git a/hal/src/main/native/sim/HAL.cpp b/hal/src/main/native/sim/HAL.cpp index 5960452be02..1754f5f215f 100644 --- a/hal/src/main/native/sim/HAL.cpp +++ b/hal/src/main/native/sim/HAL.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -25,7 +26,6 @@ NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution, #include "ErrorsInternal.h" #include "HALInitializer.h" #include "MockHooksInternal.h" -#include "hal/DriverStation.h" #include "hal/Errors.h" #include "hal/Extensions.h" #include "hal/handles/HandlesInternal.h" diff --git a/hal/src/main/native/sim/Notifier.cpp b/hal/src/main/native/sim/Notifier.cpp index 225798c0775..8ec58858a43 100644 --- a/hal/src/main/native/sim/Notifier.cpp +++ b/hal/src/main/native/sim/Notifier.cpp @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include #include #include diff --git a/hal/src/main/native/sim/REVPH.cpp b/hal/src/main/native/sim/REVPH.cpp index 957aed73f8a..e09deeaea5f 100644 --- a/hal/src/main/native/sim/REVPH.cpp +++ b/hal/src/main/native/sim/REVPH.cpp @@ -4,10 +4,11 @@ #include "hal/REVPH.h" +#include + #include "HALInitializer.h" #include "HALInternal.h" #include "PortsInternal.h" -#include "hal/CANAPI.h" #include "hal/Errors.h" #include "hal/handles/IndexedHandleResource.h" #include "mockdata/REVPHDataInternal.h" diff --git a/hal/src/main/native/sim/mockdata/DriverStationData.cpp b/hal/src/main/native/sim/mockdata/DriverStationData.cpp index d7b8a087fa4..b46e0e81d62 100644 --- a/hal/src/main/native/sim/mockdata/DriverStationData.cpp +++ b/hal/src/main/native/sim/mockdata/DriverStationData.cpp @@ -5,7 +5,6 @@ #include #include "DriverStationDataInternal.h" -#include "hal/DriverStation.h" using namespace hal; diff --git a/hal/src/main/native/sim/mockdata/EncoderData.cpp b/hal/src/main/native/sim/mockdata/EncoderData.cpp index 62ff7440993..8b012ed9d06 100644 --- a/hal/src/main/native/sim/mockdata/EncoderData.cpp +++ b/hal/src/main/native/sim/mockdata/EncoderData.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include "../PortsInternal.h" #include "EncoderDataInternal.h" diff --git a/hal/src/main/native/sim/mockdata/RoboRioData.cpp b/hal/src/main/native/sim/mockdata/RoboRioData.cpp index 94d61f8972b..613d89d4fdc 100644 --- a/hal/src/main/native/sim/mockdata/RoboRioData.cpp +++ b/hal/src/main/native/sim/mockdata/RoboRioData.cpp @@ -2,7 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. -#include "../PortsInternal.h" +#include + #include "RoboRioDataInternal.h" using namespace hal; diff --git a/hal/src/main/native/sim/mockdata/SimDeviceData.cpp b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp index 5b60cbb264a..b849957f68c 100644 --- a/hal/src/main/native/sim/mockdata/SimDeviceData.cpp +++ b/hal/src/main/native/sim/mockdata/SimDeviceData.cpp @@ -5,6 +5,8 @@ #include "hal/simulation/SimDeviceData.h" // NOLINT(build/include_order) #include +#include +#include #include diff --git a/hal/src/test/native/cpp/can/CANTest.cpp b/hal/src/test/native/cpp/can/CANTest.cpp index 72a81cd9c17..4a0ad691d3f 100644 --- a/hal/src/test/native/cpp/can/CANTest.cpp +++ b/hal/src/test/native/cpp/can/CANTest.cpp @@ -2,10 +2,11 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "hal/CANAPI.h" -#include "hal/HAL.h" #include "hal/simulation/CanData.h" namespace hal { diff --git a/hal/src/test/native/cpp/handles/HandleTest.cpp b/hal/src/test/native/cpp/handles/HandleTest.cpp index d230a06bbd5..d3fd1c72658 100644 --- a/hal/src/test/native/cpp/handles/HandleTest.cpp +++ b/hal/src/test/native/cpp/handles/HandleTest.cpp @@ -2,9 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include -#include "hal/HAL.h" #include "hal/handles/IndexedClassedHandleResource.h" #define HAL_TestHandle HAL_Handle diff --git a/hal/src/test/native/cpp/mockdata/AnalogInDataTest.cpp b/hal/src/test/native/cpp/mockdata/AnalogInDataTest.cpp index e823375545e..965565cbb40 100644 --- a/hal/src/test/native/cpp/mockdata/AnalogInDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/AnalogInDataTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "hal/AnalogInput.h" diff --git a/hal/src/test/native/cpp/mockdata/AnalogOutDataTest.cpp b/hal/src/test/native/cpp/mockdata/AnalogOutDataTest.cpp index 11dad057975..56ed8ba053c 100644 --- a/hal/src/test/native/cpp/mockdata/AnalogOutDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/AnalogOutDataTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "hal/AnalogOutput.h" diff --git a/hal/src/test/native/cpp/mockdata/DIODataTest.cpp b/hal/src/test/native/cpp/mockdata/DIODataTest.cpp index 35bfac5a37e..fba657df087 100644 --- a/hal/src/test/native/cpp/mockdata/DIODataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/DIODataTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "hal/DIO.h" diff --git a/hal/src/test/native/cpp/mockdata/DriverStationDataTest.cpp b/hal/src/test/native/cpp/mockdata/DriverStationDataTest.cpp index ffab223b18a..5ff1a316e6a 100644 --- a/hal/src/test/native/cpp/mockdata/DriverStationDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/DriverStationDataTest.cpp @@ -3,6 +3,7 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include #include diff --git a/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp b/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp index af4499b88f7..ef6cc042968 100644 --- a/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/I2CDataTest.cpp @@ -2,11 +2,11 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include -#include "hal/HAL.h" #include "hal/I2C.h" -#include "hal/handles/HandlesInternal.h" #include "hal/simulation/I2CData.h" namespace hal { diff --git a/hal/src/test/native/cpp/mockdata/PCMDataTest.cpp b/hal/src/test/native/cpp/mockdata/PCMDataTest.cpp index 70a36a9b35d..d3c5a8021b9 100644 --- a/hal/src/test/native/cpp/mockdata/PCMDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/PCMDataTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "hal/CTREPCM.h" diff --git a/hal/src/test/native/cpp/mockdata/PDPDataTest.cpp b/hal/src/test/native/cpp/mockdata/PDPDataTest.cpp index 2e9977f0ae7..14a36843eda 100644 --- a/hal/src/test/native/cpp/mockdata/PDPDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/PDPDataTest.cpp @@ -2,11 +2,11 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include -#include "hal/HAL.h" #include "hal/PowerDistribution.h" -#include "hal/handles/HandlesInternal.h" #include "hal/simulation/PowerDistributionData.h" namespace hal { diff --git a/hal/src/test/native/cpp/mockdata/PWMDataTest.cpp b/hal/src/test/native/cpp/mockdata/PWMDataTest.cpp index b32e0a03c54..1054589af3b 100644 --- a/hal/src/test/native/cpp/mockdata/PWMDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/PWMDataTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "hal/HAL.h" diff --git a/hal/src/test/native/cpp/mockdata/RelayDataTest.cpp b/hal/src/test/native/cpp/mockdata/RelayDataTest.cpp index e4017ca4549..3815b89c964 100644 --- a/hal/src/test/native/cpp/mockdata/RelayDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/RelayDataTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "hal/HAL.h" diff --git a/hal/src/test/native/cpp/mockdata/SPIDataTest.cpp b/hal/src/test/native/cpp/mockdata/SPIDataTest.cpp index 1ae626072f5..18e8ab3fbb6 100644 --- a/hal/src/test/native/cpp/mockdata/SPIDataTest.cpp +++ b/hal/src/test/native/cpp/mockdata/SPIDataTest.cpp @@ -2,11 +2,11 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include -#include "hal/HAL.h" #include "hal/SPI.h" -#include "hal/handles/HandlesInternal.h" #include "hal/simulation/SPIData.h" namespace hal { diff --git a/ntcore/src/dev/native/cpp/main.cpp b/ntcore/src/dev/native/cpp/main.cpp index 49cae5be4a1..c37949a2951 100644 --- a/ntcore/src/dev/native/cpp/main.cpp +++ b/ntcore/src/dev/native/cpp/main.cpp @@ -7,10 +7,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include diff --git a/ntcore/src/main/native/cpp/ConnectionList.cpp b/ntcore/src/main/native/cpp/ConnectionList.cpp index 8dfca216cad..f4ae7475a14 100644 --- a/ntcore/src/main/native/cpp/ConnectionList.cpp +++ b/ntcore/src/main/native/cpp/ConnectionList.cpp @@ -4,6 +4,9 @@ #include "ConnectionList.h" +#include +#include + #include #include #include diff --git a/ntcore/src/main/native/cpp/InstanceImpl.cpp b/ntcore/src/main/native/cpp/InstanceImpl.cpp index b34db7323df..fd442ccb8a0 100644 --- a/ntcore/src/main/native/cpp/InstanceImpl.cpp +++ b/ntcore/src/main/native/cpp/InstanceImpl.cpp @@ -4,6 +4,10 @@ #include "InstanceImpl.h" +#include +#include +#include + using namespace nt; std::atomic InstanceImpl::s_default{-1}; diff --git a/ntcore/src/main/native/cpp/ListenerStorage.cpp b/ntcore/src/main/native/cpp/ListenerStorage.cpp index 4270d0b919e..da06d6192e0 100644 --- a/ntcore/src/main/native/cpp/ListenerStorage.cpp +++ b/ntcore/src/main/native/cpp/ListenerStorage.cpp @@ -5,6 +5,8 @@ #include "ListenerStorage.h" #include +#include +#include #include diff --git a/ntcore/src/main/native/cpp/LocalStorage.cpp b/ntcore/src/main/native/cpp/LocalStorage.cpp index 7bc931f5345..e34139b12c2 100644 --- a/ntcore/src/main/native/cpp/LocalStorage.cpp +++ b/ntcore/src/main/native/cpp/LocalStorage.cpp @@ -5,6 +5,10 @@ #include "LocalStorage.h" #include +#include +#include +#include +#include #include #include diff --git a/ntcore/src/main/native/cpp/LoggerImpl.cpp b/ntcore/src/main/native/cpp/LoggerImpl.cpp index 4e49070b3d4..90a655a64ab 100644 --- a/ntcore/src/main/native/cpp/LoggerImpl.cpp +++ b/ntcore/src/main/native/cpp/LoggerImpl.cpp @@ -4,6 +4,8 @@ #include "LoggerImpl.h" +#include + #include #include #include diff --git a/ntcore/src/main/native/cpp/NetworkClient.cpp b/ntcore/src/main/native/cpp/NetworkClient.cpp index 477ade1a72d..0fd9d37a7a0 100644 --- a/ntcore/src/main/native/cpp/NetworkClient.cpp +++ b/ntcore/src/main/native/cpp/NetworkClient.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include diff --git a/ntcore/src/main/native/cpp/NetworkServer.cpp b/ntcore/src/main/native/cpp/NetworkServer.cpp index 04f2c052bdb..b6d8e0d79fd 100644 --- a/ntcore/src/main/native/cpp/NetworkServer.cpp +++ b/ntcore/src/main/native/cpp/NetworkServer.cpp @@ -7,8 +7,11 @@ #include #include +#include #include +#include #include +#include #include #include @@ -351,15 +354,14 @@ void NetworkServer::HandleLocal() { } void NetworkServer::LoadPersistent() { - std::error_code ec; - std::unique_ptr fileBuffer = - wpi::MemoryBuffer::GetFile(m_persistentFilename, ec); - if (fileBuffer == nullptr || ec.value() != 0) { + auto fileBuffer = wpi::MemoryBuffer::GetFile(m_persistentFilename); + if (!fileBuffer) { INFO( "could not open persistent file '{}': {} " "(this can be ignored if you aren't expecting persistent values)", - m_persistentFilename, ec.message()); + m_persistentFilename, fileBuffer.error().message()); // backup file + std::error_code ec; fs::copy_file(m_persistentFilename, m_persistentFilename + ".bak", std::filesystem::copy_options::overwrite_existing, ec); // try to write an empty file so it doesn't happen again @@ -370,7 +372,8 @@ void NetworkServer::LoadPersistent() { } return; } - m_persistentData = std::string{fileBuffer->begin(), fileBuffer->end()}; + m_persistentData = + std::string{fileBuffer.value()->begin(), fileBuffer.value()->end()}; DEBUG4("read data: {}", m_persistentData); } diff --git a/ntcore/src/main/native/cpp/Value.cpp b/ntcore/src/main/native/cpp/Value.cpp index 28765487ae2..c54a2ac63ea 100644 --- a/ntcore/src/main/native/cpp/Value.cpp +++ b/ntcore/src/main/native/cpp/Value.cpp @@ -6,8 +6,12 @@ #include #include +#include #include #include +#include +#include +#include #include #include diff --git a/ntcore/src/main/native/cpp/ValueCircularBuffer.cpp b/ntcore/src/main/native/cpp/ValueCircularBuffer.cpp index 55c2968616e..b9a449f54fd 100644 --- a/ntcore/src/main/native/cpp/ValueCircularBuffer.cpp +++ b/ntcore/src/main/native/cpp/ValueCircularBuffer.cpp @@ -4,6 +4,9 @@ #include "ValueCircularBuffer.h" +#include +#include + using namespace nt; std::vector ValueCircularBuffer::ReadValue(unsigned int types) { diff --git a/ntcore/src/main/native/cpp/jni/NetworkTablesJNI.cpp b/ntcore/src/main/native/cpp/jni/NetworkTablesJNI.cpp index ae10656bb99..4d58d2ec4a0 100644 --- a/ntcore/src/main/native/cpp/jni/NetworkTablesJNI.cpp +++ b/ntcore/src/main/native/cpp/jni/NetworkTablesJNI.cpp @@ -5,6 +5,9 @@ #include #include +#include +#include +#include #include #include diff --git a/ntcore/src/main/native/cpp/net/ClientImpl.cpp b/ntcore/src/main/native/cpp/net/ClientImpl.cpp index 0352ef91e48..abcf3e77b98 100644 --- a/ntcore/src/main/native/cpp/net/ClientImpl.cpp +++ b/ntcore/src/main/native/cpp/net/ClientImpl.cpp @@ -4,9 +4,11 @@ #include "ClientImpl.h" +#include #include #include #include +#include #include #include diff --git a/ntcore/src/main/native/cpp/net/ServerImpl.cpp b/ntcore/src/main/native/cpp/net/ServerImpl.cpp index 4dbb3e82a21..bbbc85d0a05 100644 --- a/ntcore/src/main/native/cpp/net/ServerImpl.cpp +++ b/ntcore/src/main/native/cpp/net/ServerImpl.cpp @@ -6,11 +6,11 @@ #include -#include #include -#include +#include #include #include +#include #include #include diff --git a/ntcore/src/main/native/cpp/net/WireDecoder.cpp b/ntcore/src/main/native/cpp/net/WireDecoder.cpp index 48bf5ad4130..1add69325a7 100644 --- a/ntcore/src/main/native/cpp/net/WireDecoder.cpp +++ b/ntcore/src/main/native/cpp/net/WireDecoder.cpp @@ -6,6 +6,9 @@ #include #include +#include +#include +#include #include #include diff --git a/ntcore/src/main/native/cpp/net/WireEncoder.cpp b/ntcore/src/main/native/cpp/net/WireEncoder.cpp index 42de91cfea6..62cf4c01d8a 100644 --- a/ntcore/src/main/native/cpp/net/WireEncoder.cpp +++ b/ntcore/src/main/native/cpp/net/WireEncoder.cpp @@ -5,6 +5,7 @@ #include "WireEncoder.h" #include +#include #include #include diff --git a/ntcore/src/main/native/cpp/net3/ClientImpl3.cpp b/ntcore/src/main/native/cpp/net3/ClientImpl3.cpp index a65dd89c871..b97d7e65918 100644 --- a/ntcore/src/main/native/cpp/net3/ClientImpl3.cpp +++ b/ntcore/src/main/native/cpp/net3/ClientImpl3.cpp @@ -5,8 +5,10 @@ #include "ClientImpl3.h" #include +#include #include #include +#include #include #include diff --git a/ntcore/src/main/native/cpp/net3/WireDecoder3.cpp b/ntcore/src/main/native/cpp/net3/WireDecoder3.cpp index 51180279b54..03bc9c11c9c 100644 --- a/ntcore/src/main/native/cpp/net3/WireDecoder3.cpp +++ b/ntcore/src/main/native/cpp/net3/WireDecoder3.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/ntcore/src/main/native/cpp/networktables/NetworkTable.cpp b/ntcore/src/main/native/cpp/networktables/NetworkTable.cpp index c81f33ca492..815d5166375 100644 --- a/ntcore/src/main/native/cpp/networktables/NetworkTable.cpp +++ b/ntcore/src/main/native/cpp/networktables/NetworkTable.cpp @@ -5,6 +5,10 @@ #include "networktables/NetworkTable.h" #include +#include +#include +#include +#include #include #include diff --git a/ntcore/src/main/native/cpp/networktables/NetworkTableInstance.cpp b/ntcore/src/main/native/cpp/networktables/NetworkTableInstance.cpp index d2cac1ce6a3..19c1ebfb3e0 100644 --- a/ntcore/src/main/native/cpp/networktables/NetworkTableInstance.cpp +++ b/ntcore/src/main/native/cpp/networktables/NetworkTableInstance.cpp @@ -4,6 +4,11 @@ #include "networktables/NetworkTableInstance.h" +#include +#include +#include +#include + #include #include diff --git a/ntcore/src/main/native/cpp/ntcore_c.cpp b/ntcore/src/main/native/cpp/ntcore_c.cpp index ee8b45eeb1e..83227928118 100644 --- a/ntcore/src/main/native/cpp/ntcore_c.cpp +++ b/ntcore/src/main/native/cpp/ntcore_c.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include diff --git a/ntcore/src/main/native/cpp/ntcore_cpp.cpp b/ntcore/src/main/native/cpp/ntcore_cpp.cpp index 75f20a6db5c..3cb3ce4fd77 100644 --- a/ntcore/src/main/native/cpp/ntcore_cpp.cpp +++ b/ntcore/src/main/native/cpp/ntcore_cpp.cpp @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include #include diff --git a/ntcore/src/main/native/cpp/ntcore_meta.cpp b/ntcore/src/main/native/cpp/ntcore_meta.cpp index 3b947a01fde..05933914190 100644 --- a/ntcore/src/main/native/cpp/ntcore_meta.cpp +++ b/ntcore/src/main/native/cpp/ntcore_meta.cpp @@ -2,6 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include +#include + #include #include #include diff --git a/ntcore/src/test/native/cpp/ConnectionListenerTest.cpp b/ntcore/src/test/native/cpp/ConnectionListenerTest.cpp index 3e4dd24fcb6..b5ae9daf868 100644 --- a/ntcore/src/test/native/cpp/ConnectionListenerTest.cpp +++ b/ntcore/src/test/native/cpp/ConnectionListenerTest.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include diff --git a/ntcore/src/test/native/cpp/LocalStorageTest.cpp b/ntcore/src/test/native/cpp/LocalStorageTest.cpp index 5ea4ec5c8ee..30aa9b2051b 100644 --- a/ntcore/src/test/native/cpp/LocalStorageTest.cpp +++ b/ntcore/src/test/native/cpp/LocalStorageTest.cpp @@ -2,6 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include + #include #include diff --git a/ntcore/src/test/native/cpp/LoggerTest.cpp b/ntcore/src/test/native/cpp/LoggerTest.cpp index 9e974c3fa73..38aaab1901b 100644 --- a/ntcore/src/test/native/cpp/LoggerTest.cpp +++ b/ntcore/src/test/native/cpp/LoggerTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include diff --git a/ntcore/src/test/native/cpp/NetworkTableTest.cpp b/ntcore/src/test/native/cpp/NetworkTableTest.cpp index 4429c8979cc..db856a5d871 100644 --- a/ntcore/src/test/native/cpp/NetworkTableTest.cpp +++ b/ntcore/src/test/native/cpp/NetworkTableTest.cpp @@ -2,6 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include + #include #include "TestPrinters.h" diff --git a/ntcore/src/test/native/cpp/TopicListenerTest.cpp b/ntcore/src/test/native/cpp/TopicListenerTest.cpp index 8f46742a85c..8511b3b4da7 100644 --- a/ntcore/src/test/native/cpp/TopicListenerTest.cpp +++ b/ntcore/src/test/native/cpp/TopicListenerTest.cpp @@ -3,7 +3,9 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include +#include #include #include diff --git a/ntcore/src/test/native/cpp/ValueTest.cpp b/ntcore/src/test/native/cpp/ValueTest.cpp index abb0dd5ece9..c45d5aafa5c 100644 --- a/ntcore/src/test/native/cpp/ValueTest.cpp +++ b/ntcore/src/test/native/cpp/ValueTest.cpp @@ -3,7 +3,10 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include +#include +#include #include @@ -13,7 +16,7 @@ using namespace std::string_view_literals; -namespace std { // NOLINT(clang-tidy.cert-dcl58-cpp) +namespace std { // NOLINT (clang-tidy.cert-dcl58-cpp) template inline bool operator==(std::span lhs, std::span rhs) { if (lhs.size() != rhs.size()) { diff --git a/ntcore/src/test/native/cpp/main.cpp b/ntcore/src/test/native/cpp/main.cpp index 20bd583d2d4..1e832b84cec 100644 --- a/ntcore/src/test/native/cpp/main.cpp +++ b/ntcore/src/test/native/cpp/main.cpp @@ -3,6 +3,7 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include diff --git a/ntcore/src/test/native/cpp/net/ServerImplTest.cpp b/ntcore/src/test/native/cpp/net/ServerImplTest.cpp index 13488acac3d..b21c6e11a27 100644 --- a/ntcore/src/test/native/cpp/net/ServerImplTest.cpp +++ b/ntcore/src/test/native/cpp/net/ServerImplTest.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/ntcore/src/test/native/cpp/net/WireDecoderTest.cpp b/ntcore/src/test/native/cpp/net/WireDecoderTest.cpp index fe5c469f1c8..5d74c61e370 100644 --- a/ntcore/src/test/native/cpp/net/WireDecoderTest.cpp +++ b/ntcore/src/test/native/cpp/net/WireDecoderTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include #include diff --git a/ntcore/src/test/native/cpp/net3/WireDecoder3Test.cpp b/ntcore/src/test/native/cpp/net3/WireDecoder3Test.cpp index 74f0d5462b8..af40483db02 100644 --- a/ntcore/src/test/native/cpp/net3/WireDecoder3Test.cpp +++ b/ntcore/src/test/native/cpp/net3/WireDecoder3Test.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include diff --git a/ntcore/src/test/native/cpp/net3/WireEncoder3Test.cpp b/ntcore/src/test/native/cpp/net3/WireEncoder3Test.cpp index de0593467e5..96c39a12438 100644 --- a/ntcore/src/test/native/cpp/net3/WireEncoder3Test.cpp +++ b/ntcore/src/test/native/cpp/net3/WireEncoder3Test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include diff --git a/ntcoreffi/src/main/native/cpp/DataLogManager.cpp b/ntcoreffi/src/main/native/cpp/DataLogManager.cpp index d8543482fe6..462069f3825 100644 --- a/ntcoreffi/src/main/native/cpp/DataLogManager.cpp +++ b/ntcoreffi/src/main/native/cpp/DataLogManager.cpp @@ -8,12 +8,13 @@ #include #include #include -#include +#include #include #include #include #include +#include #include #include #include @@ -191,6 +192,8 @@ struct Thread final : public wpi::SafeThread { void StartNTLog(); void StopNTLog(); + void StartConsoleLog(); + void StopConsoleLog(); std::string m_logDir; bool m_filenameOverride; @@ -198,6 +201,8 @@ struct Thread final : public wpi::SafeThread { bool m_ntLoggerEnabled = false; NT_DataLogger m_ntEntryLogger = 0; NT_ConnectionDataLogger m_ntConnLogger = 0; + bool m_consoleLoggerEnabled = false; + wpi::FileLogger m_consoleLogger; wpi::log::StringLogEntry m_messageLog; }; @@ -452,6 +457,20 @@ void Thread::StopNTLog() { } } +void Thread::StartConsoleLog() { + if (!m_consoleLoggerEnabled) { + m_consoleLoggerEnabled = true; + m_consoleLogger = {"/home/lvuser/FRC_UserProgram.log", m_log, "output"}; + } +} + +void Thread::StopConsoleLog() { + if (m_consoleLoggerEnabled) { + m_consoleLoggerEnabled = false; + m_consoleLogger = {}; + } +} + Instance::Instance(std::string_view dir, std::string_view filename, double period) { // Delete all previously existing FRC_TBD_*.wpilog files. These only exist @@ -516,6 +535,16 @@ void DataLogManager::LogNetworkTables(bool enabled) { } } +void DataLogManager::LogConsoleOutput(bool enabled) { + if (auto thr = GetInstance().owner.GetThread()) { + if (enabled) { + thr->StartConsoleLog(); + } else if (!enabled) { + thr->StopConsoleLog(); + } + } +} + void DataLogManager::SignalNewDSDataOccur() { wpi::SetSignalObject(DriverStation::gNewDataEvent); } @@ -546,6 +575,10 @@ void DLM_LogNetworkTables(int enabled) { DataLogManager::LogNetworkTables(enabled); } +void DLM_LogConsoleOutput(int enabled) { + DataLogManager::LogConsoleOutput(enabled); +} + void DLM_SignalNewDSDataOccur(void) { DataLogManager::SignalNewDSDataOccur(); } diff --git a/ntcoreffi/src/main/native/include/DataLogManager.h b/ntcoreffi/src/main/native/include/DataLogManager.h index 79d73eaaec7..c0bd6e2b07a 100644 --- a/ntcoreffi/src/main/native/include/DataLogManager.h +++ b/ntcoreffi/src/main/native/include/DataLogManager.h @@ -89,6 +89,11 @@ class DataLogManager final { */ static void LogNetworkTables(bool enabled); + /** + * Enable or disable logging of the console output. Defaults to enabled. + * @param enabled true to enable, false to disable + */ + static void LogConsoleOutput(bool enabled); /** * Signal new DS data is available. */ @@ -152,6 +157,13 @@ const char* DLM_GetLogDir(void); */ void DLM_LogNetworkTables(int enabled); + + /** + * Enable or disable logging of the console output. Defaults to enabled. + * @param enabled true to enable, false to disable + */ +void DLM_LogConsoleOutput(int enabled); + /** * Signal new DS data is available. */ diff --git a/ntcoreffi/src/main/native/symbols.txt b/ntcoreffi/src/main/native/symbols.txt index aeacd0f849e..15668d45773 100644 --- a/ntcoreffi/src/main/native/symbols.txt +++ b/ntcoreffi/src/main/native/symbols.txt @@ -1,6 +1,7 @@ DLM_GetLog DLM_GetLogDir DLM_Log +DLM_LogConsoleOutput DLM_LogNetworkTables DLM_SignalNewDSDataOccur DLM_Start diff --git a/outlineviewer/src/main/native/cpp/main.cpp b/outlineviewer/src/main/native/cpp/main.cpp index 36801ee3dac..72c2b647424 100644 --- a/outlineviewer/src/main/native/cpp/main.cpp +++ b/outlineviewer/src/main/native/cpp/main.cpp @@ -3,6 +3,7 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include #include diff --git a/processstarter/src/main/native/linux/main.cpp b/processstarter/src/main/native/linux/main.cpp index 1ddf1cdc6db..7663292dea5 100644 --- a/processstarter/src/main/native/linux/main.cpp +++ b/processstarter/src/main/native/linux/main.cpp @@ -12,6 +12,7 @@ #include #include #include +#include int main(int argc, char* argv[]) { char path[PATH_MAX]; diff --git a/roborioteamnumbersetter/CMakeLists.txt b/roborioteamnumbersetter/CMakeLists.txt index 7a43baaed9d..c249c7c8c2a 100644 --- a/roborioteamnumbersetter/CMakeLists.txt +++ b/roborioteamnumbersetter/CMakeLists.txt @@ -25,8 +25,7 @@ add_executable( ${APP_ICON_MACOSX} ) wpilib_link_macos_gui(roborioteamnumbersetter) -target_link_libraries(roborioteamnumbersetter libglass wpinet ${LIBSSH_LIBRARIES}) -target_include_directories(roborioteamnumbersetter SYSTEM PRIVATE ${LIBSSH_INCLUDE_DIRS}) +target_link_libraries(roborioteamnumbersetter libglass wpinet ssh) if(WIN32) set_target_properties(roborioteamnumbersetter PROPERTIES WIN32_EXECUTABLE YES) diff --git a/roborioteamnumbersetter/src/main/native/cpp/App.cpp b/roborioteamnumbersetter/src/main/native/cpp/App.cpp index 62b493c4af2..4394b3d841b 100644 --- a/roborioteamnumbersetter/src/main/native/cpp/App.cpp +++ b/roborioteamnumbersetter/src/main/native/cpp/App.cpp @@ -3,8 +3,10 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include #include +#include #ifndef _WIN32 #include diff --git a/roborioteamnumbersetter/src/main/native/cpp/DeploySession.cpp b/roborioteamnumbersetter/src/main/native/cpp/DeploySession.cpp index f831e5f28ba..84a950b4838 100644 --- a/roborioteamnumbersetter/src/main/native/cpp/DeploySession.cpp +++ b/roborioteamnumbersetter/src/main/native/cpp/DeploySession.cpp @@ -4,8 +4,10 @@ #include "DeploySession.h" +#include #include #include +#include #include #include diff --git a/roborioteamnumbersetter/src/main/native/cpp/SshSession.cpp b/roborioteamnumbersetter/src/main/native/cpp/SshSession.cpp index 84fbd6cc188..e20da94d455 100644 --- a/roborioteamnumbersetter/src/main/native/cpp/SshSession.cpp +++ b/roborioteamnumbersetter/src/main/native/cpp/SshSession.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/romiVendordep/RomiVendordep.json b/romiVendordep/RomiVendordep.json index 4ebc02fd9ce..7f6eda70c8c 100644 --- a/romiVendordep/RomiVendordep.json +++ b/romiVendordep/RomiVendordep.json @@ -3,7 +3,7 @@ "name": "Romi-Vendordep", "version": "1.0.0", "uuid": "1010372a-b446-46f4-b229-61e53a26a7dc", - "frcYear": "2024", + "frcYear": "2025", "mavenUrls": [], "jsonUrl": "", "javaDependencies": [ diff --git a/romiVendordep/src/main/native/cpp/romi/OnBoardIO.cpp b/romiVendordep/src/main/native/cpp/romi/OnBoardIO.cpp index cefe9ff2e4c..bba2901f923 100644 --- a/romiVendordep/src/main/native/cpp/romi/OnBoardIO.cpp +++ b/romiVendordep/src/main/native/cpp/romi/OnBoardIO.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include #include diff --git a/shared/java/javacommon.gradle b/shared/java/javacommon.gradle index 6151250c599..48e67e8d737 100644 --- a/shared/java/javacommon.gradle +++ b/shared/java/javacommon.gradle @@ -5,7 +5,7 @@ apply plugin: 'com.google.protobuf' def baseArtifactId = project.baseId def artifactGroupId = project.groupId -def javaBaseName = "_GROUP_edu_wpi_first_${project.baseId}_ID_${project.baseId}-java_CLS" +def javaBaseName = "_GROUP_${project.groupId.replace('.', '_')}_ID_${project.baseId}-java_CLS" def outputsFolder = file("$project.buildDir/outputs") diff --git a/simulation/halsim_ds_socket/src/main/native/cpp/main.cpp b/simulation/halsim_ds_socket/src/main/native/cpp/main.cpp index 7bb86d71c59..3686d3affdb 100644 --- a/simulation/halsim_ds_socket/src/main/native/cpp/main.cpp +++ b/simulation/halsim_ds_socket/src/main/native/cpp/main.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/AccelerometerSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/AccelerometerSimGui.cpp index 22676569f68..115b4ecef50 100644 --- a/simulation/halsim_gui/src/main/native/cpp/AccelerometerSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/AccelerometerSimGui.cpp @@ -4,11 +4,10 @@ #include "AccelerometerSimGui.h" -#include -#include - #include +#include +#include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/AddressableLEDGui.cpp b/simulation/halsim_gui/src/main/native/cpp/AddressableLEDGui.cpp index 2528185516a..d7049362c8a 100644 --- a/simulation/halsim_gui/src/main/native/cpp/AddressableLEDGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/AddressableLEDGui.cpp @@ -4,8 +4,10 @@ #include "AddressableLEDGui.h" -#include +#include +#include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/AnalogGyroSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/AnalogGyroSimGui.cpp index 12149ec69cc..4bd328f4e46 100644 --- a/simulation/halsim_gui/src/main/native/cpp/AnalogGyroSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/AnalogGyroSimGui.cpp @@ -4,12 +4,11 @@ #include "AnalogGyroSimGui.h" -#include -#include - #include #include +#include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/AnalogInputSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/AnalogInputSimGui.cpp index e100d5dd32e..4a428b602ab 100644 --- a/simulation/halsim_gui/src/main/native/cpp/AnalogInputSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/AnalogInputSimGui.cpp @@ -4,12 +4,11 @@ #include "AnalogInputSimGui.h" -#include -#include - #include #include +#include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/AnalogOutputSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/AnalogOutputSimGui.cpp index 8e02fb69ef7..7a98bed575c 100644 --- a/simulation/halsim_gui/src/main/native/cpp/AnalogOutputSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/AnalogOutputSimGui.cpp @@ -4,12 +4,11 @@ #include "AnalogOutputSimGui.h" -#include -#include - #include #include +#include +#include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/DIOSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/DIOSimGui.cpp index 150e4bf436a..13ec169406b 100644 --- a/simulation/halsim_gui/src/main/native/cpp/DIOSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/DIOSimGui.cpp @@ -4,12 +4,11 @@ #include "DIOSimGui.h" -#include -#include - #include #include +#include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.cpp b/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.cpp index 119075642dd..cb238d87e6a 100644 --- a/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.cpp @@ -4,12 +4,6 @@ #include "DriverStationGui.h" -#include -#include -#include -#include -#include - #include #include #include @@ -20,6 +14,11 @@ #include #include +#include +#include +#include +#include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.h b/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.h index cb086c839d4..55c90a39f61 100644 --- a/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.h +++ b/simulation/halsim_gui/src/main/native/cpp/DriverStationGui.h @@ -4,11 +4,11 @@ #pragma once -#include - #include #include +#include + namespace halsimgui { class DSManager : public glass::WindowManager { diff --git a/simulation/halsim_gui/src/main/native/cpp/EncoderSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/EncoderSimGui.cpp index 6a1be270cee..8e53c864d6f 100644 --- a/simulation/halsim_gui/src/main/native/cpp/EncoderSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/EncoderSimGui.cpp @@ -4,7 +4,6 @@ #include "EncoderSimGui.h" -#include #include #include @@ -13,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/HALProvider.cpp b/simulation/halsim_gui/src/main/native/cpp/HALProvider.cpp index dffcd00b700..7d36478b8f0 100644 --- a/simulation/halsim_gui/src/main/native/cpp/HALProvider.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/HALProvider.cpp @@ -4,12 +4,11 @@ #include "HALProvider.h" -#include -#include - -#include #include +#include +#include +#include #include using namespace halsimgui; diff --git a/simulation/halsim_gui/src/main/native/cpp/HALSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/HALSimGui.cpp index 4d005ad0d49..e6329c3b6e8 100644 --- a/simulation/halsim_gui/src/main/native/cpp/HALSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/HALSimGui.cpp @@ -4,9 +4,11 @@ #include "HALSimGui.h" +#include +#include + #include #include - #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/NetworkTablesSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/NetworkTablesSimGui.cpp index 30f123259e9..763d28e8aab 100644 --- a/simulation/halsim_gui/src/main/native/cpp/NetworkTablesSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/NetworkTablesSimGui.cpp @@ -4,10 +4,11 @@ #include "NetworkTablesSimGui.h" +#include + #include #include #include - #include #include "HALSimGui.h" diff --git a/simulation/halsim_gui/src/main/native/cpp/PCMSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/PCMSimGui.cpp index d5a3f3604e4..019a86c76cf 100644 --- a/simulation/halsim_gui/src/main/native/cpp/PCMSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/PCMSimGui.cpp @@ -4,13 +4,12 @@ #include "PCMSimGui.h" -#include -#include - #include #include #include +#include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/PCMSimGui.h b/simulation/halsim_gui/src/main/native/cpp/PCMSimGui.h index da20022ef14..d4842492671 100644 --- a/simulation/halsim_gui/src/main/native/cpp/PCMSimGui.h +++ b/simulation/halsim_gui/src/main/native/cpp/PCMSimGui.h @@ -3,10 +3,10 @@ // the WPILib BSD license file in the root directory of this project. #pragma once -#include - #include +#include + namespace halsimgui { class PCMSimGui { diff --git a/simulation/halsim_gui/src/main/native/cpp/PHSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/PHSimGui.cpp index 47e65e1e5b2..0fc66914c7b 100644 --- a/simulation/halsim_gui/src/main/native/cpp/PHSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/PHSimGui.cpp @@ -4,13 +4,12 @@ #include "PHSimGui.h" -#include -#include - #include #include #include +#include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/PHSimGui.h b/simulation/halsim_gui/src/main/native/cpp/PHSimGui.h index 84fe9d76ac7..348f6df963f 100644 --- a/simulation/halsim_gui/src/main/native/cpp/PHSimGui.h +++ b/simulation/halsim_gui/src/main/native/cpp/PHSimGui.h @@ -3,10 +3,10 @@ // the WPILib BSD license file in the root directory of this project. #pragma once -#include - #include +#include + namespace halsimgui { class PHSimGui { diff --git a/simulation/halsim_gui/src/main/native/cpp/PWMSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/PWMSimGui.cpp index 9eceabdc1c4..2a60f9f4ef0 100644 --- a/simulation/halsim_gui/src/main/native/cpp/PWMSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/PWMSimGui.cpp @@ -4,11 +4,10 @@ #include "PWMSimGui.h" -#include - #include #include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/PowerDistributionSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/PowerDistributionSimGui.cpp index c136c7eddea..a3d4c2b3f72 100644 --- a/simulation/halsim_gui/src/main/native/cpp/PowerDistributionSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/PowerDistributionSimGui.cpp @@ -4,13 +4,12 @@ #include "PowerDistributionSimGui.h" -#include - #include #include #include #include +#include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/RelaySimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/RelaySimGui.cpp index badb4f9a32a..1d163fbb32e 100644 --- a/simulation/halsim_gui/src/main/native/cpp/RelaySimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/RelaySimGui.cpp @@ -4,11 +4,10 @@ #include "RelaySimGui.h" -#include - #include #include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/RoboRioSimGui.cpp b/simulation/halsim_gui/src/main/native/cpp/RoboRioSimGui.cpp index b693569571f..29fa7b4cf24 100644 --- a/simulation/halsim_gui/src/main/native/cpp/RoboRioSimGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/RoboRioSimGui.cpp @@ -4,10 +4,9 @@ #include "RoboRioSimGui.h" -#include - #include +#include #include #include "HALDataSource.h" diff --git a/simulation/halsim_gui/src/main/native/cpp/SimDeviceGui.cpp b/simulation/halsim_gui/src/main/native/cpp/SimDeviceGui.cpp index 55b83cef252..aee5130e440 100644 --- a/simulation/halsim_gui/src/main/native/cpp/SimDeviceGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/SimDeviceGui.cpp @@ -4,10 +4,13 @@ #include "SimDeviceGui.h" -#include #include +#include +#include + #include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/TimingGui.cpp b/simulation/halsim_gui/src/main/native/cpp/TimingGui.cpp index 3ccf6306d18..043e360d571 100644 --- a/simulation/halsim_gui/src/main/native/cpp/TimingGui.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/TimingGui.cpp @@ -4,13 +4,13 @@ #include "TimingGui.h" -#include -#include - #include #include +#include #include +#include +#include #include #include #include diff --git a/simulation/halsim_gui/src/main/native/cpp/main.cpp b/simulation/halsim_gui/src/main/native/cpp/main.cpp index 574090b974c..21fe17404f7 100644 --- a/simulation/halsim_gui/src/main/native/cpp/main.cpp +++ b/simulation/halsim_gui/src/main/native/cpp/main.cpp @@ -2,14 +2,14 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include +#include + #include #include #include #include - -#include -#include - #include #include #include diff --git a/simulation/halsim_gui/src/main/native/include/HALProvider.h b/simulation/halsim_gui/src/main/native/include/HALProvider.h index 0a26a09cd5f..11372b11f45 100644 --- a/simulation/halsim_gui/src/main/native/include/HALProvider.h +++ b/simulation/halsim_gui/src/main/native/include/HALProvider.h @@ -4,15 +4,15 @@ #pragma once -#include -#include - #include #include #include #include #include +#include +#include + namespace halsimgui { class HALProvider : private glass::Provider<> { diff --git a/simulation/halsim_gui/src/main/native/include/HALSimGui.h b/simulation/halsim_gui/src/main/native/include/HALSimGui.h index 68597e5f672..50590e6b6cd 100644 --- a/simulation/halsim_gui/src/main/native/include/HALSimGui.h +++ b/simulation/halsim_gui/src/main/native/include/HALSimGui.h @@ -4,13 +4,13 @@ #pragma once +#include +#include + #include #include #include -#include -#include - #include "HALProvider.h" namespace halsimgui { diff --git a/simulation/halsim_ws_client/src/main/native/cpp/HALSimWS.cpp b/simulation/halsim_ws_client/src/main/native/cpp/HALSimWS.cpp index 21742f06126..3e27d3ec943 100644 --- a/simulation/halsim_ws_client/src/main/native/cpp/HALSimWS.cpp +++ b/simulation/halsim_ws_client/src/main/native/cpp/HALSimWS.cpp @@ -5,6 +5,8 @@ #include "HALSimWS.h" #include +#include +#include #include #include diff --git a/simulation/halsim_ws_client/src/main/native/cpp/HALSimWSClient.cpp b/simulation/halsim_ws_client/src/main/native/cpp/HALSimWSClient.cpp index 1df7ebc7372..14896926b6b 100644 --- a/simulation/halsim_ws_client/src/main/native/cpp/HALSimWSClient.cpp +++ b/simulation/halsim_ws_client/src/main/native/cpp/HALSimWSClient.cpp @@ -4,6 +4,8 @@ #include "HALSimWSClient.h" +#include + #include #include #include diff --git a/simulation/halsim_ws_client/src/main/native/cpp/HALSimWSClientConnection.cpp b/simulation/halsim_ws_client/src/main/native/cpp/HALSimWSClientConnection.cpp index 3e7305b47ad..c889d38b8a3 100644 --- a/simulation/halsim_ws_client/src/main/native/cpp/HALSimWSClientConnection.cpp +++ b/simulation/halsim_ws_client/src/main/native/cpp/HALSimWSClientConnection.cpp @@ -5,6 +5,7 @@ #include "HALSimWSClientConnection.h" #include +#include #include #include diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSHalProviders.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSHalProviders.cpp index 4d6c024558c..4afc6b65bc6 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSHalProviders.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSHalProviders.cpp @@ -4,6 +4,8 @@ #include "WSHalProviders.h" +#include + #include namespace wpilibws { diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_AddressableLED.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_AddressableLED.cpp index d316fc17e49..78629a3dbd0 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_AddressableLED.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_AddressableLED.cpp @@ -4,6 +4,8 @@ #include "WSProvider_AddressableLED.h" +#include + #include #include diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_BuiltInAccelerometer.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_BuiltInAccelerometer.cpp index fefbcd547a3..1928b5df3ac 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_BuiltInAccelerometer.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_BuiltInAccelerometer.cpp @@ -4,6 +4,8 @@ #include "WSProvider_BuiltInAccelerometer.h" +#include + #include #include diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_DriverStation.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_DriverStation.cpp index 27495263b92..3c3989eac10 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_DriverStation.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_DriverStation.cpp @@ -4,8 +4,8 @@ #include "WSProvider_DriverStation.h" -#include #include +#include #include #include diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_Joystick.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_Joystick.cpp index 3c1602646b1..8e35d56b502 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_Joystick.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_Joystick.cpp @@ -4,7 +4,9 @@ #include "WSProvider_Joystick.h" +#include #include +#include #include #include diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_SimDevice.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_SimDevice.cpp index 7c3d710f47c..cad7e22b9b0 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_SimDevice.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_SimDevice.cpp @@ -6,6 +6,9 @@ #include #include +#include +#include +#include #include #include diff --git a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_Solenoid.cpp b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_Solenoid.cpp index a26a4e59ab3..944367b7af6 100644 --- a/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_Solenoid.cpp +++ b/simulation/halsim_ws_core/src/main/native/cpp/WSProvider_Solenoid.cpp @@ -4,6 +4,10 @@ #include "WSProvider_Solenoid.h" +#include +#include +#include + #include #include #include diff --git a/simulation/halsim_ws_server/src/main/native/cpp/HALSimHttpConnection.cpp b/simulation/halsim_ws_server/src/main/native/cpp/HALSimHttpConnection.cpp index 3567b720096..cb6b43715ae 100644 --- a/simulation/halsim_ws_server/src/main/native/cpp/HALSimHttpConnection.cpp +++ b/simulation/halsim_ws_server/src/main/native/cpp/HALSimHttpConnection.cpp @@ -6,6 +6,8 @@ #include +#include +#include #include #include @@ -125,9 +127,8 @@ void HALSimHttpConnection::SendFileResponse(int code, std::string_view codeText, } // open file - std::unique_ptr fileBuffer = - wpi::MemoryBuffer::GetFile(filename, ec); - if (fileBuffer == nullptr || ec) { + auto fileBuffer = wpi::MemoryBuffer::GetFile(filename); + if (!fileBuffer) { MySendError(404, "error opening file"); return; } @@ -143,7 +144,7 @@ void HALSimHttpConnection::SendFileResponse(int code, std::string_view codeText, wpi::SmallVector bodyData; wpi::raw_uv_ostream bodyOs{bodyData, 4096}; - bodyOs << fileBuffer->GetBuffer(); + bodyOs << fileBuffer.value()->GetBuffer(); SendData(bodyOs.bufs(), false); if (!m_keepAlive) { diff --git a/simulation/halsim_ws_server/src/main/native/cpp/HALSimWSServer.cpp b/simulation/halsim_ws_server/src/main/native/cpp/HALSimWSServer.cpp index 9ecccb049c9..0661b975d6c 100644 --- a/simulation/halsim_ws_server/src/main/native/cpp/HALSimWSServer.cpp +++ b/simulation/halsim_ws_server/src/main/native/cpp/HALSimWSServer.cpp @@ -4,6 +4,8 @@ #include "HALSimWSServer.h" +#include + #include #include #include diff --git a/simulation/halsim_ws_server/src/main/native/cpp/HALSimWeb.cpp b/simulation/halsim_ws_server/src/main/native/cpp/HALSimWeb.cpp index 163af753f21..f231cf44878 100644 --- a/simulation/halsim_ws_server/src/main/native/cpp/HALSimWeb.cpp +++ b/simulation/halsim_ws_server/src/main/native/cpp/HALSimWeb.cpp @@ -4,6 +4,9 @@ #include "HALSimWeb.h" +#include +#include + #include #include #include diff --git a/simulation/halsim_ws_server/src/test/native/cpp/WebServerClientTest.cpp b/simulation/halsim_ws_server/src/test/native/cpp/WebServerClientTest.cpp index cd38f7b39a2..3a7429127fe 100644 --- a/simulation/halsim_ws_server/src/test/native/cpp/WebServerClientTest.cpp +++ b/simulation/halsim_ws_server/src/test/native/cpp/WebServerClientTest.cpp @@ -5,6 +5,8 @@ #include "WebServerClientTest.h" #include +#include +#include #include #include diff --git a/simulation/halsim_ws_server/src/test/native/cpp/main.cpp b/simulation/halsim_ws_server/src/test/native/cpp/main.cpp index 254cc092b76..2ff9a5aaf98 100644 --- a/simulation/halsim_ws_server/src/test/native/cpp/main.cpp +++ b/simulation/halsim_ws_server/src/test/native/cpp/main.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include #include #include diff --git a/simulation/halsim_xrp/src/main/native/cpp/HALSimXRP.cpp b/simulation/halsim_xrp/src/main/native/cpp/HALSimXRP.cpp index 8a85bfaac8d..704e172c828 100644 --- a/simulation/halsim_xrp/src/main/native/cpp/HALSimXRP.cpp +++ b/simulation/halsim_xrp/src/main/native/cpp/HALSimXRP.cpp @@ -5,6 +5,7 @@ #include "HALSimXRP.h" #include +#include #include #include diff --git a/simulation/halsim_xrp/src/main/native/cpp/HALSimXRPClient.cpp b/simulation/halsim_xrp/src/main/native/cpp/HALSimXRPClient.cpp index 2cd36c39be6..adc4e26a46c 100644 --- a/simulation/halsim_xrp/src/main/native/cpp/HALSimXRPClient.cpp +++ b/simulation/halsim_xrp/src/main/native/cpp/HALSimXRPClient.cpp @@ -4,6 +4,8 @@ #include "HALSimXRPClient.h" +#include + #include #include #include diff --git a/simulation/halsim_xrp/src/main/native/cpp/XRP.cpp b/simulation/halsim_xrp/src/main/native/cpp/XRP.cpp index bc84b881efe..ffa1a5e56c1 100644 --- a/simulation/halsim_xrp/src/main/native/cpp/XRP.cpp +++ b/simulation/halsim_xrp/src/main/native/cpp/XRP.cpp @@ -4,6 +4,8 @@ #include "XRP.h" +#include + #include #include #include @@ -388,8 +390,9 @@ void XRP::ReadEncoderTag(std::span packet) { static_cast(period_numerator >> 1) / period_denominator; // If direction is not forward, return negative value for period. - if (!(period_numerator & 1)) + if (!(period_numerator & 1)) { period = -period; + } encJson["data"].push_back({wpi::json(">period"), wpi::json(period)}); } diff --git a/sysid/src/main/native/cpp/App.cpp b/sysid/src/main/native/cpp/App.cpp index 8b35dca2d3d..e9b058f57e3 100644 --- a/sysid/src/main/native/cpp/App.cpp +++ b/sysid/src/main/native/cpp/App.cpp @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include diff --git a/sysid/src/main/native/cpp/Util.cpp b/sysid/src/main/native/cpp/Util.cpp index c4dc7803046..fcd27c49486 100644 --- a/sysid/src/main/native/cpp/Util.cpp +++ b/sysid/src/main/native/cpp/Util.cpp @@ -83,6 +83,7 @@ void sysid::SaveFile(std::string_view contents, // Open a fd_ostream to write to file. std::error_code ec; + // NOLINTNEXTLINE(build/include_what_you_use) wpi::raw_fd_ostream ostream{path.string(), ec}; // Check error code. diff --git a/sysid/src/main/native/cpp/analysis/AnalysisManager.cpp b/sysid/src/main/native/cpp/analysis/AnalysisManager.cpp index b76b4414e5c..11137a31861 100644 --- a/sysid/src/main/native/cpp/analysis/AnalysisManager.cpp +++ b/sysid/src/main/native/cpp/analysis/AnalysisManager.cpp @@ -5,12 +5,13 @@ #include "sysid/analysis/AnalysisManager.h" #include -#include +#include +#include +#include #include #include #include -#include #include #include diff --git a/sysid/src/main/native/cpp/analysis/FeedforwardAnalysis.cpp b/sysid/src/main/native/cpp/analysis/FeedforwardAnalysis.cpp index 110ff9463f1..3f517d9da2d 100644 --- a/sysid/src/main/native/cpp/analysis/FeedforwardAnalysis.cpp +++ b/sysid/src/main/native/cpp/analysis/FeedforwardAnalysis.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -14,8 +16,6 @@ #include #include -#include "sysid/analysis/AnalysisManager.h" -#include "sysid/analysis/FilteringUtils.h" #include "sysid/analysis/OLS.h" namespace sysid { diff --git a/sysid/src/main/native/cpp/analysis/FilteringUtils.cpp b/sysid/src/main/native/cpp/analysis/FilteringUtils.cpp index 8432e7c8ff7..43eb8e244b0 100644 --- a/sysid/src/main/native/cpp/analysis/FilteringUtils.cpp +++ b/sysid/src/main/native/cpp/analysis/FilteringUtils.cpp @@ -4,10 +4,13 @@ #include "sysid/analysis/FilteringUtils.h" +#include +#include #include #include #include -#include +#include +#include #include #include diff --git a/sysid/src/main/native/cpp/view/Analyzer.cpp b/sysid/src/main/native/cpp/view/Analyzer.cpp index 7efca4e16f5..748a1e358c8 100644 --- a/sysid/src/main/native/cpp/view/Analyzer.cpp +++ b/sysid/src/main/native/cpp/view/Analyzer.cpp @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include diff --git a/sysid/src/main/native/cpp/view/AnalyzerPlot.cpp b/sysid/src/main/native/cpp/view/AnalyzerPlot.cpp index 6963f2c1b8f..bc640d9c7eb 100644 --- a/sysid/src/main/native/cpp/view/AnalyzerPlot.cpp +++ b/sysid/src/main/native/cpp/view/AnalyzerPlot.cpp @@ -6,7 +6,10 @@ #include #include +#include #include +#include +#include #include #include diff --git a/sysid/src/main/native/cpp/view/DataSelector.cpp b/sysid/src/main/native/cpp/view/DataSelector.cpp index 75b12e5e3ab..ecb1c012171 100644 --- a/sysid/src/main/native/cpp/view/DataSelector.cpp +++ b/sysid/src/main/native/cpp/view/DataSelector.cpp @@ -4,6 +4,11 @@ #include "sysid/view/DataSelector.h" +#include +#include +#include +#include + #include #include #include diff --git a/sysid/src/main/native/cpp/view/LogLoader.cpp b/sysid/src/main/native/cpp/view/LogLoader.cpp index fdaa3af11be..6884519a6d2 100644 --- a/sysid/src/main/native/cpp/view/LogLoader.cpp +++ b/sysid/src/main/native/cpp/view/LogLoader.cpp @@ -7,7 +7,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -35,15 +38,15 @@ void LogLoader::Display() { if (!m_opener->result().empty()) { m_filename = m_opener->result()[0]; - std::error_code ec; - auto buf = wpi::MemoryBuffer::GetFile(m_filename, ec); - if (ec) { + auto fileBuffer = wpi::MemoryBuffer::GetFile(m_filename); + if (!fileBuffer) { ImGui::OpenPopup("Error"); - m_error = fmt::format("Could not open file: {}", ec.message()); + m_error = fmt::format("Could not open file: {}", + fileBuffer.error().message()); return; } - wpi::log::DataLogReader reader{std::move(buf)}; + wpi::log::DataLogReader reader{std::move(*fileBuffer)}; if (!reader.IsValid()) { ImGui::OpenPopup("Error"); m_error = "Not a valid datalog file"; diff --git a/upstream_utils/argparse_lib.py b/upstream_utils/argparse_lib.py new file mode 100755 index 00000000000..6adfd39e640 --- /dev/null +++ b/upstream_utils/argparse_lib.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import os +import shutil + +from upstream_utils import Lib + + +def copy_upstream_src(wpilib_root): + wpiutil = os.path.join(wpilib_root, "wpiutil") + + # Copy header into allwpilib + dest_filename = os.path.join( + wpiutil, + f"src/main/native/thirdparty/argparse/include/wpi/argparse.h", + ) + shutil.copyfile("include/argparse/argparse.hpp", dest_filename) + # Rename namespace from argparse to wpi + with open(dest_filename) as f: + content = f.read() + content = content.replace("namespace argparse", "namespace wpi") + content = content.replace("argparse::", "wpi::") + content = content.replace("ARGPARSE_", "WPI_") + with open(dest_filename, "w") as f: + f.write(content) + + +def main(): + name = "argparse" + url = "https://github.com/p-ranav/argparse" + # master on 2024-09-11 + tag = "fd13c2859131ab463e617a5a8abcc69eb7e1d897" + + expected = Lib(name, url, tag, copy_upstream_src) + expected.main() + + +if __name__ == "__main__": + main() diff --git a/upstream_utils/concurrentqueue.py b/upstream_utils/concurrentqueue.py new file mode 100755 index 00000000000..81c3306721a --- /dev/null +++ b/upstream_utils/concurrentqueue.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +import os +import shutil + +from upstream_utils import Lib + + +def copy_upstream_src(wpilib_root): + wpiutil = os.path.join(wpilib_root, "wpiutil") + + # Copy header into allwpilib + dest_filename = os.path.join( + wpiutil, + f"src/main/native/thirdparty/concurrentqueue/include/wpi/concurrentqueue.h", + ) + shutil.copyfile("concurrentqueue.h", dest_filename) + # Rename namespace from moodycamel to wpi + with open(dest_filename) as f: + content = f.read() + content = content.replace("namespace moodycamel", "namespace wpi") + content = content.replace("moodycamel::", "wpi::") + # The upstream library has macros that would conflict with other thirdparty WPI_ macros + content = content.replace("MOODYCAMEL_", "WPI_CQ_") + with open(dest_filename, "w") as f: + f.write(content) + + +def main(): + name = "concurrentqueue" + url = "https://github.com/cameron314/concurrentqueue" + # master on 2024-09-10 + tag = "6dd38b8a1dbaa7863aa907045f32308a56a6ff5d" + + expected = Lib(name, url, tag, copy_upstream_src) + expected.main() + + +if __name__ == "__main__": + main() diff --git a/upstream_utils/sleipnir.py b/upstream_utils/sleipnir.py index fba7a712924..28d2fb38e5a 100755 --- a/upstream_utils/sleipnir.py +++ b/upstream_utils/sleipnir.py @@ -51,8 +51,8 @@ def copy_upstream_src(wpilib_root): def main(): name = "sleipnir" url = "https://github.com/SleipnirGroup/Sleipnir" - # main on 2024-08-03 - tag = "4f182964d9bbb1c703260bddbfaa0c4435097675" + # main on 2024-09-18 + tag = "8bbce85252bc351c5aacb0de9f50fa31b8b9e1ae" sleipnir = Lib(name, url, tag, copy_upstream_src) sleipnir.main() diff --git a/upstream_utils/sleipnir_patches/0002-Use-fmtlib.patch b/upstream_utils/sleipnir_patches/0002-Use-fmtlib.patch index 6a5c679c12e..e5779dc71f0 100644 --- a/upstream_utils/sleipnir_patches/0002-Use-fmtlib.patch +++ b/upstream_utils/sleipnir_patches/0002-Use-fmtlib.patch @@ -19,13 +19,13 @@ index 8fb61fdf9cc5ceff633d3126f0579eef25a1326f..6a7f8ed28f9cb037c9746a7e0ef5e110 + ^fmt/ } diff --git a/include/sleipnir/util/Print.hpp b/include/sleipnir/util/Print.hpp -index 339320bce6d017ca85025060ba445b2f025bb225..a9220cdaadcb9b88862542935bc72781d8389239 100644 +index a746cb77b70f095bb15f4c493295cb925bc74cd3..c01fd4ac679df854b885293d681ea1e0984626fa 100644 --- a/include/sleipnir/util/Print.hpp +++ b/include/sleipnir/util/Print.hpp -@@ -2,52 +2,57 @@ - +@@ -3,52 +3,57 @@ #pragma once + #include -#include #include #include diff --git a/upstream_utils/sleipnir_patches/0004-Use-wpi-SmallVector.patch b/upstream_utils/sleipnir_patches/0004-Use-wpi-SmallVector.patch index 7dcbdf5eb60..550983549db 100644 --- a/upstream_utils/sleipnir_patches/0004-Use-wpi-SmallVector.patch +++ b/upstream_utils/sleipnir_patches/0004-Use-wpi-SmallVector.patch @@ -408,7 +408,7 @@ index f3b2f0cf9e60b3a86b9654ff2b381f9c48734ff6..ad739cea6dce6f6cb586f538d1d30b92 + ^wpi/ } diff --git a/src/optimization/solver/InteriorPoint.cpp b/src/optimization/solver/InteriorPoint.cpp -index 817e3d1dcb808c36192ea5b483eee1a08dbb5e2f..1470eb235bfdac363557c207ac0eaedb6c73d295 100644 +index dcd8b56dc08516b80f89550c43cb7002745b93d8..892d2dd20f7fe92c2c91518a4ecb487425643585 100644 --- a/src/optimization/solver/InteriorPoint.cpp +++ b/src/optimization/solver/InteriorPoint.cpp @@ -9,6 +9,7 @@ diff --git a/upstream_utils/upstream_utils.py b/upstream_utils/upstream_utils.py index f750139f5ea..72ad63eb51e 100644 --- a/upstream_utils/upstream_utils.py +++ b/upstream_utils/upstream_utils.py @@ -7,59 +7,6 @@ import tempfile -def clone_repo(url, treeish, shallow=True): - """Clones a Git repo at the given URL into a temp folder, checks out the - given tree-ish (either branch or tag), then returns the repo root. - - Keyword argument: - url -- The URL of the Git repo - treeish -- The tree-ish to check out (branch or tag) - shallow -- Whether to do a shallow clone - - Returns: - root -- root directory of the cloned Git repository - """ - cwd = os.getcwd() - if url.startswith("file://"): - os.chdir(os.path.dirname(url[7:])) - else: - os.chdir(tempfile.gettempdir()) - - repo = os.path.basename(url) - dest = os.path.join(os.getcwd(), repo) - if dest.endswith(".git"): - dest = dest[:-4] - - # Clone Git repository into current directory or update it - if not os.path.exists(dest): - cmd = ["git", "clone"] - if shallow: - cmd += ["--branch", treeish, "--depth", "1"] - subprocess.run(cmd + [url, dest]) - os.chdir(dest) - else: - os.chdir(dest) - subprocess.run(["git", "fetch", "origin", treeish]) - - # Get list of heads - # Example output of "git ls-remote --heads": - # From https://gitlab.com/libeigen/eigen.git - # 77c66e368c7e355f8be299659f57b0ffcaedb505 refs/heads/3.4 - # 3e006bfd31e4389e8c5718c30409cddb65a73b04 refs/heads/master - ls_out = subprocess.check_output(["git", "ls-remote", "--heads"]).decode().rstrip() - heads = [x.split()[1] for x in ls_out.split("\n")[1:]] - - if f"refs/heads/{treeish}" in heads: - # Checking out the remote branch avoids needing to handle syncing a - # preexisting local one - subprocess.run(["git", "checkout", f"origin/{treeish}"]) - else: - subprocess.run(["git", "checkout", treeish]) - - os.chdir(cwd) - return dest - - def get_repo_root(): """Returns the Git repository root as an absolute path. @@ -558,7 +505,7 @@ def main(self, argv=sys.argv[1:]): ) parser_rebase.add_argument("new_tag", help="The tag to rebase onto") - parser_format_patch = subparsers.add_parser( + subparsers.add_parser( "format-patch", help="Generates patch files for the upstream repository and moves them into the upstream_utils patch directory", ) diff --git a/vcpkg.json b/vcpkg.json index fc499d086bd..ea1d2a9b5b4 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -5,7 +5,8 @@ "opencv", "fmt", "libuv", - "protobuf" + "protobuf", + "libssh" ], "builtin-baseline": "37c3e63a1306562f7f59c4c3c8892ddd50fdf992" } diff --git a/wpigui/src/main/native/cpp/wpigui.cpp b/wpigui/src/main/native/cpp/wpigui.cpp index e2e05ce0674..b50540ff6b5 100644 --- a/wpigui/src/main/native/cpp/wpigui.cpp +++ b/wpigui/src/main/native/cpp/wpigui.cpp @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include diff --git a/wpigui/src/main/native/cpp/wpigui_openurl.cpp b/wpigui/src/main/native/cpp/wpigui_openurl.cpp index f6095670fc5..0a071b17910 100644 --- a/wpigui/src/main/native/cpp/wpigui_openurl.cpp +++ b/wpigui/src/main/native/cpp/wpigui_openurl.cpp @@ -14,6 +14,8 @@ #include #endif +#include + void wpi::gui::OpenURL(const std::string& url) { #ifdef _WIN32 ShellExecuteA(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL); diff --git a/wpilibNewCommands/WPILibNewCommands.json b/wpilibNewCommands/WPILibNewCommands.json index 67bf3898d54..3718e0acd7c 100644 --- a/wpilibNewCommands/WPILibNewCommands.json +++ b/wpilibNewCommands/WPILibNewCommands.json @@ -3,7 +3,7 @@ "name": "WPILib-New-Commands", "version": "1.0.0", "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266", - "frcYear": "2024", + "frcYear": "2025", "mavenUrls": [], "jsonUrl": "", "javaDependencies": [ diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/Command.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/Command.cpp index ff5e8f6aa51..365cf80a4ea 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/Command.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/Command.cpp @@ -4,22 +4,15 @@ #include "frc2/command/Command.h" +#include +#include + #include #include #include -#include "frc2/command/CommandHelper.h" +#include "frc2/command/CommandPtr.h" #include "frc2/command/CommandScheduler.h" -#include "frc2/command/ConditionalCommand.h" -#include "frc2/command/InstantCommand.h" -#include "frc2/command/ParallelCommandGroup.h" -#include "frc2/command/ParallelDeadlineGroup.h" -#include "frc2/command/ParallelRaceGroup.h" -#include "frc2/command/RepeatCommand.h" -#include "frc2/command/SequentialCommandGroup.h" -#include "frc2/command/WaitCommand.h" -#include "frc2/command/WaitUntilCommand.h" -#include "frc2/command/WrapperCommand.h" using namespace frc2; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandPtr.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandPtr.cpp index ee7182a7847..298cc2e50ca 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandPtr.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandPtr.cpp @@ -4,6 +4,10 @@ #include "frc2/command/CommandPtr.h" +#include +#include +#include + #include #include "frc2/command/CommandScheduler.h" @@ -12,7 +16,6 @@ #include "frc2/command/ParallelCommandGroup.h" #include "frc2/command/ParallelDeadlineGroup.h" #include "frc2/command/ParallelRaceGroup.h" -#include "frc2/command/PrintCommand.h" #include "frc2/command/ProxyCommand.h" #include "frc2/command/RepeatCommand.h" #include "frc2/command/SequentialCommandGroup.h" diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp index f845cbc0533..aa57bf00d08 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/CommandScheduler.cpp @@ -5,6 +5,10 @@ #include "frc2/command/CommandScheduler.h" #include +#include +#include +#include +#include #include #include diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/Commands.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/Commands.cpp index 15458083d69..bc4bd39da73 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/Commands.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/Commands.cpp @@ -4,6 +4,9 @@ #include "frc2/command/Commands.h" +#include +#include + #include #include "frc2/command/ConditionalCommand.h" diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ConditionalCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ConditionalCommand.cpp index 6ce33b75486..753eb85a70a 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ConditionalCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/ConditionalCommand.cpp @@ -4,6 +4,10 @@ #include "frc2/command/ConditionalCommand.h" +#include +#include +#include + #include using namespace frc2; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/DeferredCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/DeferredCommand.cpp index 2a7f16280a9..0bb0e14176e 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/DeferredCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/DeferredCommand.cpp @@ -4,6 +4,8 @@ #include "frc2/command/DeferredCommand.h" +#include + #include #include "frc2/command/Commands.h" diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/FunctionalCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/FunctionalCommand.cpp index e4ff6ea4174..e28c7c4709d 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/FunctionalCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/FunctionalCommand.cpp @@ -4,6 +4,8 @@ #include "frc2/command/FunctionalCommand.h" +#include + using namespace frc2; FunctionalCommand::FunctionalCommand(std::function onInit, diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/InstantCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/InstantCommand.cpp index b78d30e0e88..c8a189e99fb 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/InstantCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/InstantCommand.cpp @@ -4,6 +4,8 @@ #include "frc2/command/InstantCommand.h" +#include + using namespace frc2; InstantCommand::InstantCommand(std::function toRun, diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/MecanumControllerCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/MecanumControllerCommand.cpp index c22ac99ce8a..742a37d9597 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/MecanumControllerCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/MecanumControllerCommand.cpp @@ -4,6 +4,7 @@ #include "frc2/command/MecanumControllerCommand.h" +#include #include #include diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/NotifierCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/NotifierCommand.cpp index 5dc5add96f5..a49ead9eef4 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/NotifierCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/NotifierCommand.cpp @@ -4,6 +4,8 @@ #include "frc2/command/NotifierCommand.h" +#include + using namespace frc2; NotifierCommand::NotifierCommand(std::function toRun, diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelCommandGroup.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelCommandGroup.cpp index 4a234b14756..b433eb445a1 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelCommandGroup.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelCommandGroup.cpp @@ -4,6 +4,9 @@ #include "frc2/command/ParallelCommandGroup.h" +#include +#include + using namespace frc2; ParallelCommandGroup::ParallelCommandGroup( diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelDeadlineGroup.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelDeadlineGroup.cpp index 1c9b7005345..90669fe20be 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelDeadlineGroup.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelDeadlineGroup.cpp @@ -4,6 +4,10 @@ #include "frc2/command/ParallelDeadlineGroup.h" +#include +#include +#include + #include using namespace frc2; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelRaceGroup.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelRaceGroup.cpp index 334286f8e37..5896dd88aaa 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelRaceGroup.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/ParallelRaceGroup.cpp @@ -4,6 +4,9 @@ #include "frc2/command/ParallelRaceGroup.h" +#include +#include + using namespace frc2; ParallelRaceGroup::ParallelRaceGroup( diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/PrintCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/PrintCommand.cpp index 8032dada7ea..d08f53ef88e 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/PrintCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/PrintCommand.cpp @@ -4,6 +4,8 @@ #include "frc2/command/PrintCommand.h" +#include + #include using namespace frc2; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyCommand.cpp index fa72906b622..92999ea691e 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/ProxyCommand.cpp @@ -4,6 +4,9 @@ #include "frc2/command/ProxyCommand.h" +#include +#include + #include #include #include diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/RepeatCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/RepeatCommand.cpp index 2a08f1b0438..15097af843e 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/RepeatCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/RepeatCommand.cpp @@ -4,6 +4,9 @@ #include "frc2/command/RepeatCommand.h" +#include +#include + #include using namespace frc2; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/RunCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/RunCommand.cpp index c3378eaf1f0..633715393d8 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/RunCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/RunCommand.cpp @@ -4,6 +4,8 @@ #include "frc2/command/RunCommand.h" +#include + using namespace frc2; RunCommand::RunCommand(std::function toRun, Requirements requirements) diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/SequentialCommandGroup.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/SequentialCommandGroup.cpp index 173b9d93c8e..fa873654589 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/SequentialCommandGroup.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/SequentialCommandGroup.cpp @@ -4,6 +4,9 @@ #include "frc2/command/SequentialCommandGroup.h" +#include +#include + #include using namespace frc2; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/StartEndCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/StartEndCommand.cpp index 2d257a3bc7e..90d1961df6d 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/StartEndCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/StartEndCommand.cpp @@ -4,6 +4,8 @@ #include "frc2/command/StartEndCommand.h" +#include + using namespace frc2; StartEndCommand::StartEndCommand(std::function onInit, diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/Subsystem.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/Subsystem.cpp index 5800c440692..876269a1b47 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/Subsystem.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/Subsystem.cpp @@ -4,6 +4,9 @@ #include "frc2/command/Subsystem.h" +#include +#include + #include #include "frc2/command/CommandPtr.h" diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/SubsystemBase.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/SubsystemBase.cpp index e5a40388e4a..e0638263642 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/SubsystemBase.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/SubsystemBase.cpp @@ -4,6 +4,8 @@ #include "frc2/command/SubsystemBase.h" +#include + #include #include diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/WaitUntilCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/WaitUntilCommand.cpp index 9ccd94eda8a..9ea6fbfae9d 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/WaitUntilCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/WaitUntilCommand.cpp @@ -4,6 +4,8 @@ #include "frc2/command/WaitUntilCommand.h" +#include + #include using namespace frc2; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/WrapperCommand.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/WrapperCommand.cpp index 2e1b280d693..775e84a30c5 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/WrapperCommand.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/WrapperCommand.cpp @@ -4,6 +4,8 @@ #include "frc2/command/WrapperCommand.h" +#include + #include "frc2/command/Command.h" using namespace frc2; diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/NetworkButton.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/NetworkButton.cpp index a0923a3ba50..a5234c92a65 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/NetworkButton.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/NetworkButton.cpp @@ -4,6 +4,9 @@ #include "frc2/command/button/NetworkButton.h" +#include +#include + using namespace frc2; NetworkButton::NetworkButton(nt::BooleanTopic topic) diff --git a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp index 78fd0b3f769..a3b02d18f3a 100644 --- a/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp +++ b/wpilibNewCommands/src/main/native/cpp/frc2/command/button/Trigger.cpp @@ -4,9 +4,11 @@ #include "frc2/command/button/Trigger.h" +#include + #include -#include "frc2/command/InstantCommand.h" +#include "frc2/command/CommandPtr.h" using namespace frc; using namespace frc2; diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandDecoratorTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandDecoratorTest.cpp index a5059b16e11..3a31308a3f0 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandDecoratorTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandDecoratorTest.cpp @@ -2,6 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include + #include #include "CommandTestBase.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandPtrTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandPtrTest.cpp index 75ec0409649..1dae951bea7 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandPtrTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandPtrTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "CommandTestBase.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandRequirementsTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandRequirementsTest.cpp index b46bb8bbde9..e8d3c16ff4f 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandRequirementsTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/CommandRequirementsTest.cpp @@ -2,17 +2,13 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "CommandTestBase.h" #include "frc2/command/CommandScheduler.h" -#include "frc2/command/ConditionalCommand.h" #include "frc2/command/FunctionalCommand.h" -#include "frc2/command/InstantCommand.h" -#include "frc2/command/ParallelCommandGroup.h" -#include "frc2/command/ParallelDeadlineGroup.h" -#include "frc2/command/ParallelRaceGroup.h" -#include "frc2/command/SequentialCommandGroup.h" using namespace frc2; class CommandRequirementsTest : public CommandTestBase {}; diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/ConditionalCommandTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/ConditionalCommandTest.cpp index d7bbd26b20c..7896a1aa326 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/ConditionalCommandTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/ConditionalCommandTest.cpp @@ -2,6 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include + #include "CommandTestBase.h" #include "frc2/command/Commands.h" #include "frc2/command/ConditionalCommand.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/DefaultCommandTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/DefaultCommandTest.cpp index a9e3fc681ca..a024a2f1955 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/DefaultCommandTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/DefaultCommandTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include "CommandTestBase.h" #include "frc2/command/RunCommand.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelCommandGroupTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelCommandGroupTest.cpp index ff5384c8f98..21457d024cd 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelCommandGroupTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelCommandGroupTest.cpp @@ -2,6 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include + #include "CommandTestBase.h" #include "CompositionTestBase.h" #include "frc2/command/InstantCommand.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelDeadlineGroupTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelDeadlineGroupTest.cpp index f35bd000c28..d36b97ad6c6 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelDeadlineGroupTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelDeadlineGroupTest.cpp @@ -2,6 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include +#include + #include "CommandTestBase.h" #include "CompositionTestBase.h" #include "frc2/command/InstantCommand.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelRaceGroupTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelRaceGroupTest.cpp index be18fc30490..032c3c1dd33 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelRaceGroupTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/ParallelRaceGroupTest.cpp @@ -2,6 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include + #include "CommandTestBase.h" #include "CompositionTestBase.h" #include "frc2/command/InstantCommand.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulingRecursionTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulingRecursionTest.cpp index 37353032a12..52436b97ac6 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulingRecursionTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/SchedulingRecursionTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "CommandTestBase.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/SelectCommandTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/SelectCommandTest.cpp index dfea0d336ac..eb05034da28 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/SelectCommandTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/SelectCommandTest.cpp @@ -2,9 +2,12 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include +#include + #include "CommandTestBase.h" #include "CompositionTestBase.h" -#include "frc2/command/ConditionalCommand.h" #include "frc2/command/InstantCommand.h" #include "frc2/command/SelectCommand.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/SequentialCommandGroupTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/SequentialCommandGroupTest.cpp index e1283136e8f..b8920c733f9 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/SequentialCommandGroupTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/SequentialCommandGroupTest.cpp @@ -2,6 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include + #include "CommandTestBase.h" #include "CompositionTestBase.h" #include "frc2/command/InstantCommand.h" diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/button/TriggerTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/button/TriggerTest.cpp index a97b4f566c3..9b0899edb78 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/button/TriggerTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/button/TriggerTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include diff --git a/wpilibNewCommands/src/test/native/cpp/frc2/command/sysid/SysIdRoutineTest.cpp b/wpilibNewCommands/src/test/native/cpp/frc2/command/sysid/SysIdRoutineTest.cpp index 1cfe39c6ee8..ae0b9a2241e 100644 --- a/wpilibNewCommands/src/test/native/cpp/frc2/command/sysid/SysIdRoutineTest.cpp +++ b/wpilibNewCommands/src/test/native/cpp/frc2/command/sysid/SysIdRoutineTest.cpp @@ -5,7 +5,8 @@ #include #include -#include +#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/ADIS16448_IMU.cpp b/wpilibc/src/main/native/cpp/ADIS16448_IMU.cpp index 74a3e420662..ea768e3120a 100644 --- a/wpilibc/src/main/native/cpp/ADIS16448_IMU.cpp +++ b/wpilibc/src/main/native/cpp/ADIS16448_IMU.cpp @@ -13,23 +13,21 @@ #include "frc/ADIS16448_IMU.h" -#include -#include -#include -#include -#include -#include - #include #include #include +#include #include #include #include +#include "frc/DigitalInput.h" +#include "frc/DigitalOutput.h" #include "frc/Errors.h" #include "frc/MathUtil.h" +#include "frc/SPI.h" +#include "frc/Timer.h" /* Helpful conversion functions */ static inline uint16_t BuffToUShort(const uint32_t* buf) { diff --git a/wpilibc/src/main/native/cpp/ADIS16470_IMU.cpp b/wpilibc/src/main/native/cpp/ADIS16470_IMU.cpp index b29c498ad17..5f99e300c08 100644 --- a/wpilibc/src/main/native/cpp/ADIS16470_IMU.cpp +++ b/wpilibc/src/main/native/cpp/ADIS16470_IMU.cpp @@ -13,11 +13,6 @@ #include "frc/ADIS16470_IMU.h" -#include -#include -#include -#include - #include #include #include @@ -26,8 +21,10 @@ #include #include +#include "frc/DigitalInput.h" #include "frc/Errors.h" #include "frc/MathUtil.h" +#include "frc/Timer.h" /* Helpful conversion functions */ static inline int32_t ToInt(const uint32_t* buf) { diff --git a/wpilibc/src/main/native/cpp/Alert.cpp b/wpilibc/src/main/native/cpp/Alert.cpp index 86bfd68cb92..c9523fab555 100644 --- a/wpilibc/src/main/native/cpp/Alert.cpp +++ b/wpilibc/src/main/native/cpp/Alert.cpp @@ -4,11 +4,15 @@ #include "frc/Alert.h" -#include -#include +#include +#include +#include #include +#include "frc/Timer.h" +#include "frc/smartdashboard/SmartDashboard.h" + using namespace frc; Alert::Alert(std::string_view text, AlertType type) diff --git a/wpilibc/src/main/native/cpp/AnalogEncoder.cpp b/wpilibc/src/main/native/cpp/AnalogEncoder.cpp index 152b34f98c5..13a788788cb 100644 --- a/wpilibc/src/main/native/cpp/AnalogEncoder.cpp +++ b/wpilibc/src/main/native/cpp/AnalogEncoder.cpp @@ -4,11 +4,12 @@ #include "frc/AnalogEncoder.h" +#include + #include #include #include "frc/AnalogInput.h" -#include "frc/Errors.h" #include "frc/MathUtil.h" #include "frc/RobotController.h" diff --git a/wpilibc/src/main/native/cpp/AnalogGyro.cpp b/wpilibc/src/main/native/cpp/AnalogGyro.cpp index 36d70b9daad..6362b45b41a 100644 --- a/wpilibc/src/main/native/cpp/AnalogGyro.cpp +++ b/wpilibc/src/main/native/cpp/AnalogGyro.cpp @@ -5,7 +5,8 @@ #include "frc/AnalogGyro.h" #include -#include +#include +#include #include #include @@ -17,7 +18,6 @@ #include "frc/AnalogInput.h" #include "frc/Errors.h" -#include "frc/Timer.h" using namespace frc; diff --git a/wpilibc/src/main/native/cpp/AnalogInput.cpp b/wpilibc/src/main/native/cpp/AnalogInput.cpp index 9960d3704af..15e28ceeffc 100644 --- a/wpilibc/src/main/native/cpp/AnalogInput.cpp +++ b/wpilibc/src/main/native/cpp/AnalogInput.cpp @@ -4,6 +4,8 @@ #include "frc/AnalogInput.h" +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/AnalogOutput.cpp b/wpilibc/src/main/native/cpp/AnalogOutput.cpp index d5857abded2..ca7dec1f397 100644 --- a/wpilibc/src/main/native/cpp/AnalogOutput.cpp +++ b/wpilibc/src/main/native/cpp/AnalogOutput.cpp @@ -4,8 +4,7 @@ #include "frc/AnalogOutput.h" -#include -#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/AnalogPotentiometer.cpp b/wpilibc/src/main/native/cpp/AnalogPotentiometer.cpp index d8b8b1e0a88..31432e9681c 100644 --- a/wpilibc/src/main/native/cpp/AnalogPotentiometer.cpp +++ b/wpilibc/src/main/native/cpp/AnalogPotentiometer.cpp @@ -4,6 +4,7 @@ #include "frc/AnalogPotentiometer.h" +#include #include #include diff --git a/wpilibc/src/main/native/cpp/AnalogTrigger.cpp b/wpilibc/src/main/native/cpp/AnalogTrigger.cpp index 81bd3c5f8e9..6759b61dde6 100644 --- a/wpilibc/src/main/native/cpp/AnalogTrigger.cpp +++ b/wpilibc/src/main/native/cpp/AnalogTrigger.cpp @@ -4,6 +4,7 @@ #include "frc/AnalogTrigger.h" +#include #include #include diff --git a/wpilibc/src/main/native/cpp/AsynchronousInterrupt.cpp b/wpilibc/src/main/native/cpp/AsynchronousInterrupt.cpp index d45d5e4a5cf..20fc761c278 100644 --- a/wpilibc/src/main/native/cpp/AsynchronousInterrupt.cpp +++ b/wpilibc/src/main/native/cpp/AsynchronousInterrupt.cpp @@ -6,6 +6,9 @@ #include +#include +#include + using namespace frc; AsynchronousInterrupt::AsynchronousInterrupt( diff --git a/wpilibc/src/main/native/cpp/Counter.cpp b/wpilibc/src/main/native/cpp/Counter.cpp index f6506b98fb3..1c35923969a 100644 --- a/wpilibc/src/main/native/cpp/Counter.cpp +++ b/wpilibc/src/main/native/cpp/Counter.cpp @@ -4,7 +4,7 @@ #include "frc/Counter.h" -#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/DMA.cpp b/wpilibc/src/main/native/cpp/DMA.cpp index 806e18b4071..5661af28820 100644 --- a/wpilibc/src/main/native/cpp/DMA.cpp +++ b/wpilibc/src/main/native/cpp/DMA.cpp @@ -15,11 +15,6 @@ #include #include -#include "frc/AnalogInput.h" -#include "frc/Counter.h" -#include "frc/DigitalSource.h" -#include "frc/DutyCycle.h" -#include "frc/Encoder.h" #include "frc/Errors.h" using namespace frc; diff --git a/wpilibc/src/main/native/cpp/DataLogManager.cpp b/wpilibc/src/main/native/cpp/DataLogManager.cpp index dc9d3d73875..9ab1211c0ec 100644 --- a/wpilibc/src/main/native/cpp/DataLogManager.cpp +++ b/wpilibc/src/main/native/cpp/DataLogManager.cpp @@ -9,11 +9,14 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include #include @@ -37,6 +40,8 @@ struct Thread final : public wpi::SafeThread { void StartNTLog(); void StopNTLog(); + void StartConsoleLog(); + void StopConsoleLog(); std::string m_logDir; bool m_filenameOverride; @@ -44,6 +49,8 @@ struct Thread final : public wpi::SafeThread { bool m_ntLoggerEnabled = false; NT_DataLogger m_ntEntryLogger = 0; NT_ConnectionDataLogger m_ntConnLogger = 0; + bool m_consoleLoggerEnabled = false; + wpi::FileLogger m_consoleLogger; wpi::log::StringLogEntry m_messageLog; }; @@ -109,10 +116,12 @@ Thread::Thread(std::string_view dir, std::string_view filename, double period) m_log{dir, MakeLogFilename(filename), period}, m_messageLog{m_log, "messages"} { StartNTLog(); + StartConsoleLog(); } Thread::~Thread() { StopNTLog(); + StopConsoleLog(); } void Thread::Main() { @@ -297,6 +306,20 @@ void Thread::StopNTLog() { } } +void Thread::StartConsoleLog() { + if (!m_consoleLoggerEnabled && RobotBase::IsReal()) { + m_consoleLoggerEnabled = true; + m_consoleLogger = {"/home/lvuser/FRC_UserProgram.log", m_log, "output"}; + } +} + +void Thread::StopConsoleLog() { + if (m_consoleLoggerEnabled && RobotBase::IsReal()) { + m_consoleLoggerEnabled = false; + m_consoleLogger = {}; + } +} + Instance::Instance(std::string_view dir, std::string_view filename, double period) { // Delete all previously existing FRC_TBD_*.wpilog files. These only exist @@ -360,3 +383,13 @@ void DataLogManager::LogNetworkTables(bool enabled) { } } } + +void DataLogManager::LogConsoleOutput(bool enabled) { + if (auto thr = GetInstance().owner.GetThread()) { + if (enabled) { + thr->StartConsoleLog(); + } else if (!enabled) { + thr->StopConsoleLog(); + } + } +} diff --git a/wpilibc/src/main/native/cpp/DigitalInput.cpp b/wpilibc/src/main/native/cpp/DigitalInput.cpp index b3c110875ea..f6c2d8b03c6 100644 --- a/wpilibc/src/main/native/cpp/DigitalInput.cpp +++ b/wpilibc/src/main/native/cpp/DigitalInput.cpp @@ -4,7 +4,7 @@ #include "frc/DigitalInput.h" -#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/DigitalOutput.cpp b/wpilibc/src/main/native/cpp/DigitalOutput.cpp index 01d3ef74fd2..6cac8e8f064 100644 --- a/wpilibc/src/main/native/cpp/DigitalOutput.cpp +++ b/wpilibc/src/main/native/cpp/DigitalOutput.cpp @@ -4,7 +4,7 @@ #include "frc/DigitalOutput.h" -#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/DriverStation.cpp b/wpilibc/src/main/native/cpp/DriverStation.cpp index 16032a17d38..862b2464eb4 100644 --- a/wpilibc/src/main/native/cpp/DriverStation.cpp +++ b/wpilibc/src/main/native/cpp/DriverStation.cpp @@ -8,12 +8,10 @@ #include #include -#include +#include #include #include #include -#include -#include #include #include @@ -33,7 +31,6 @@ #include #include "frc/Errors.h" -#include "frc/MotorSafety.h" #include "frc/Timer.h" using namespace frc; diff --git a/wpilibc/src/main/native/cpp/DutyCycle.cpp b/wpilibc/src/main/native/cpp/DutyCycle.cpp index 943baa8b1bf..6ac7a37c8e2 100644 --- a/wpilibc/src/main/native/cpp/DutyCycle.cpp +++ b/wpilibc/src/main/native/cpp/DutyCycle.cpp @@ -4,6 +4,8 @@ #include "frc/DutyCycle.h" +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/DutyCycleEncoder.cpp b/wpilibc/src/main/native/cpp/DutyCycleEncoder.cpp index f127cf2ed1b..41a1b4b987d 100644 --- a/wpilibc/src/main/native/cpp/DutyCycleEncoder.cpp +++ b/wpilibc/src/main/native/cpp/DutyCycleEncoder.cpp @@ -4,13 +4,15 @@ #include "frc/DutyCycleEncoder.h" +#include +#include + #include #include #include "frc/DigitalInput.h" #include "frc/DigitalSource.h" #include "frc/DutyCycle.h" -#include "frc/Errors.h" #include "frc/MathUtil.h" using namespace frc; diff --git a/wpilibc/src/main/native/cpp/Encoder.cpp b/wpilibc/src/main/native/cpp/Encoder.cpp index 795183f3ab8..b7eda548fea 100644 --- a/wpilibc/src/main/native/cpp/Encoder.cpp +++ b/wpilibc/src/main/native/cpp/Encoder.cpp @@ -4,6 +4,7 @@ #include "frc/Encoder.h" +#include #include #include diff --git a/wpilibc/src/main/native/cpp/Errors.cpp b/wpilibc/src/main/native/cpp/Errors.cpp index 0ff4dc1699a..f29a420e4a4 100644 --- a/wpilibc/src/main/native/cpp/Errors.cpp +++ b/wpilibc/src/main/native/cpp/Errors.cpp @@ -4,7 +4,8 @@ #include "frc/Errors.h" -#include +#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/Filesystem.cpp b/wpilibc/src/main/native/cpp/Filesystem.cpp index 7947d750733..7add0e8f8e6 100644 --- a/wpilibc/src/main/native/cpp/Filesystem.cpp +++ b/wpilibc/src/main/native/cpp/Filesystem.cpp @@ -4,6 +4,8 @@ #include "frc/Filesystem.h" +#include + #include #include "frc/RobotBase.h" diff --git a/wpilibc/src/main/native/cpp/GenericHID.cpp b/wpilibc/src/main/native/cpp/GenericHID.cpp index f4d26b64def..6e9e0e0b0db 100644 --- a/wpilibc/src/main/native/cpp/GenericHID.cpp +++ b/wpilibc/src/main/native/cpp/GenericHID.cpp @@ -4,6 +4,8 @@ #include "frc/GenericHID.h" +#include + #include #include "frc/DriverStation.h" diff --git a/wpilibc/src/main/native/cpp/LEDPattern.cpp b/wpilibc/src/main/native/cpp/LEDPattern.cpp index c5ce8a7754f..537b459603c 100644 --- a/wpilibc/src/main/native/cpp/LEDPattern.cpp +++ b/wpilibc/src/main/native/cpp/LEDPattern.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/PneumaticHub.cpp b/wpilibc/src/main/native/cpp/PneumaticHub.cpp index 06e37a4a3aa..7169438d9e2 100644 --- a/wpilibc/src/main/native/cpp/PneumaticHub.cpp +++ b/wpilibc/src/main/native/cpp/PneumaticHub.cpp @@ -5,6 +5,9 @@ #include "frc/PneumaticHub.h" #include +#include +#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/PneumaticsBase.cpp b/wpilibc/src/main/native/cpp/PneumaticsBase.cpp index bd9e033bda2..78c5f0dd72a 100644 --- a/wpilibc/src/main/native/cpp/PneumaticsBase.cpp +++ b/wpilibc/src/main/native/cpp/PneumaticsBase.cpp @@ -4,6 +4,8 @@ #include "frc/PneumaticsBase.h" +#include + #include #include "frc/Errors.h" diff --git a/wpilibc/src/main/native/cpp/PneumaticsControlModule.cpp b/wpilibc/src/main/native/cpp/PneumaticsControlModule.cpp index e34e85097d2..e743e5e6f43 100644 --- a/wpilibc/src/main/native/cpp/PneumaticsControlModule.cpp +++ b/wpilibc/src/main/native/cpp/PneumaticsControlModule.cpp @@ -4,6 +4,9 @@ #include "frc/PneumaticsControlModule.h" +#include +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/PowerDistribution.cpp b/wpilibc/src/main/native/cpp/PowerDistribution.cpp index df5f6ddeed0..14a4cec49d8 100644 --- a/wpilibc/src/main/native/cpp/PowerDistribution.cpp +++ b/wpilibc/src/main/native/cpp/PowerDistribution.cpp @@ -4,6 +4,8 @@ #include "frc/PowerDistribution.h" +#include + #include #include #include @@ -13,7 +15,6 @@ #include #include "frc/Errors.h" -#include "frc/SensorUtil.h" static_assert(static_cast( frc::PowerDistribution::ModuleType::kCTRE) == diff --git a/wpilibc/src/main/native/cpp/Preferences.cpp b/wpilibc/src/main/native/cpp/Preferences.cpp index 07d79cb57c5..9706f90b019 100644 --- a/wpilibc/src/main/native/cpp/Preferences.cpp +++ b/wpilibc/src/main/native/cpp/Preferences.cpp @@ -4,7 +4,9 @@ #include "frc/Preferences.h" -#include +#include +#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/Relay.cpp b/wpilibc/src/main/native/cpp/Relay.cpp index 7c523711a50..0cd2dac86b1 100644 --- a/wpilibc/src/main/native/cpp/Relay.cpp +++ b/wpilibc/src/main/native/cpp/Relay.cpp @@ -4,7 +4,7 @@ #include "frc/Relay.h" -#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/Resource.cpp b/wpilibc/src/main/native/cpp/Resource.cpp index de32e11631f..34aeba5861f 100644 --- a/wpilibc/src/main/native/cpp/Resource.cpp +++ b/wpilibc/src/main/native/cpp/Resource.cpp @@ -4,6 +4,11 @@ #include "frc/Resource.h" +#include +#include +#include +#include + #include #include "frc/Errors.h" diff --git a/wpilibc/src/main/native/cpp/RobotController.cpp b/wpilibc/src/main/native/cpp/RobotController.cpp index 5c0f7fd7826..31258f1234e 100644 --- a/wpilibc/src/main/native/cpp/RobotController.cpp +++ b/wpilibc/src/main/native/cpp/RobotController.cpp @@ -4,7 +4,7 @@ #include "frc/RobotController.h" -#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/SerialPort.cpp b/wpilibc/src/main/native/cpp/SerialPort.cpp index 0d96a9e9e64..8c6fdb380ca 100644 --- a/wpilibc/src/main/native/cpp/SerialPort.cpp +++ b/wpilibc/src/main/native/cpp/SerialPort.cpp @@ -4,7 +4,7 @@ #include "frc/SerialPort.h" -#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/SharpIR.cpp b/wpilibc/src/main/native/cpp/SharpIR.cpp index db9b9b9a89d..67e00f6a67e 100644 --- a/wpilibc/src/main/native/cpp/SharpIR.cpp +++ b/wpilibc/src/main/native/cpp/SharpIR.cpp @@ -4,6 +4,8 @@ #include "frc/SharpIR.h" +#include + #include #include diff --git a/wpilibc/src/main/native/cpp/SynchronousInterrupt.cpp b/wpilibc/src/main/native/cpp/SynchronousInterrupt.cpp index 298ecdd864b..084efd9d1f1 100644 --- a/wpilibc/src/main/native/cpp/SynchronousInterrupt.cpp +++ b/wpilibc/src/main/native/cpp/SynchronousInterrupt.cpp @@ -4,7 +4,9 @@ #include "frc/SynchronousInterrupt.h" +#include #include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/Ultrasonic.cpp b/wpilibc/src/main/native/cpp/Ultrasonic.cpp index ec4c9c3c140..640a56c4f41 100644 --- a/wpilibc/src/main/native/cpp/Ultrasonic.cpp +++ b/wpilibc/src/main/native/cpp/Ultrasonic.cpp @@ -4,7 +4,9 @@ #include "frc/Ultrasonic.h" +#include #include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/Watchdog.cpp b/wpilibc/src/main/native/cpp/Watchdog.cpp index 91d999d6c41..063ed5a09b0 100644 --- a/wpilibc/src/main/native/cpp/Watchdog.cpp +++ b/wpilibc/src/main/native/cpp/Watchdog.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/counter/ExternalDirectionCounter.cpp b/wpilibc/src/main/native/cpp/counter/ExternalDirectionCounter.cpp index 3bea166ec66..d518a2f0fc5 100644 --- a/wpilibc/src/main/native/cpp/counter/ExternalDirectionCounter.cpp +++ b/wpilibc/src/main/native/cpp/counter/ExternalDirectionCounter.cpp @@ -4,6 +4,8 @@ #include "frc/counter/ExternalDirectionCounter.h" +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/counter/UpDownCounter.cpp b/wpilibc/src/main/native/cpp/counter/UpDownCounter.cpp index 30b9ea6afea..7da57924777 100644 --- a/wpilibc/src/main/native/cpp/counter/UpDownCounter.cpp +++ b/wpilibc/src/main/native/cpp/counter/UpDownCounter.cpp @@ -4,6 +4,8 @@ #include "frc/counter/UpDownCounter.h" +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp b/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp index e3a0a8c4945..85232193a41 100644 --- a/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp +++ b/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/drive/MecanumDrive.cpp b/wpilibc/src/main/native/cpp/drive/MecanumDrive.cpp index aeec27d0ded..d40d02c6343 100644 --- a/wpilibc/src/main/native/cpp/drive/MecanumDrive.cpp +++ b/wpilibc/src/main/native/cpp/drive/MecanumDrive.cpp @@ -5,6 +5,8 @@ #include "frc/drive/MecanumDrive.h" #include +#include +#include #include #include diff --git a/wpilibc/src/main/native/cpp/event/BooleanEvent.cpp b/wpilibc/src/main/native/cpp/event/BooleanEvent.cpp index 0f6cdfe22cc..d108a0fd141 100644 --- a/wpilibc/src/main/native/cpp/event/BooleanEvent.cpp +++ b/wpilibc/src/main/native/cpp/event/BooleanEvent.cpp @@ -4,6 +4,9 @@ #include "frc/event/BooleanEvent.h" +#include +#include + using namespace frc; BooleanEvent::BooleanEvent(EventLoop* loop, std::function condition) diff --git a/wpilibc/src/main/native/cpp/event/EventLoop.cpp b/wpilibc/src/main/native/cpp/event/EventLoop.cpp index c85286ba371..cf2b3f3d7c8 100644 --- a/wpilibc/src/main/native/cpp/event/EventLoop.cpp +++ b/wpilibc/src/main/native/cpp/event/EventLoop.cpp @@ -4,6 +4,8 @@ #include "frc/event/EventLoop.h" +#include + #include "frc/Errors.h" using namespace frc; diff --git a/wpilibc/src/main/native/cpp/event/NetworkBooleanEvent.cpp b/wpilibc/src/main/native/cpp/event/NetworkBooleanEvent.cpp index d910361b64b..0f8576d8ff9 100644 --- a/wpilibc/src/main/native/cpp/event/NetworkBooleanEvent.cpp +++ b/wpilibc/src/main/native/cpp/event/NetworkBooleanEvent.cpp @@ -4,6 +4,9 @@ #include "frc/event/NetworkBooleanEvent.h" +#include +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/livewindow/LiveWindow.cpp b/wpilibc/src/main/native/cpp/livewindow/LiveWindow.cpp index aff42a4efc6..04f66c723e5 100644 --- a/wpilibc/src/main/native/cpp/livewindow/LiveWindow.cpp +++ b/wpilibc/src/main/native/cpp/livewindow/LiveWindow.cpp @@ -4,6 +4,8 @@ #include "frc/livewindow/LiveWindow.h" +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/motorcontrol/MotorControllerGroup.cpp b/wpilibc/src/main/native/cpp/motorcontrol/MotorControllerGroup.cpp index cf57f7c55b2..c5a0e0316f4 100644 --- a/wpilibc/src/main/native/cpp/motorcontrol/MotorControllerGroup.cpp +++ b/wpilibc/src/main/native/cpp/motorcontrol/MotorControllerGroup.cpp @@ -4,6 +4,9 @@ #include "frc/motorcontrol/MotorControllerGroup.h" +#include +#include + #include #include diff --git a/wpilibc/src/main/native/cpp/motorcontrol/NidecBrushless.cpp b/wpilibc/src/main/native/cpp/motorcontrol/NidecBrushless.cpp index a05b7cc8416..5acf3c818d0 100644 --- a/wpilibc/src/main/native/cpp/motorcontrol/NidecBrushless.cpp +++ b/wpilibc/src/main/native/cpp/motorcontrol/NidecBrushless.cpp @@ -4,6 +4,8 @@ #include "frc/motorcontrol/NidecBrushless.h" +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/motorcontrol/PWMMotorController.cpp b/wpilibc/src/main/native/cpp/motorcontrol/PWMMotorController.cpp index 1f1d2628ab3..28ef00fbef5 100644 --- a/wpilibc/src/main/native/cpp/motorcontrol/PWMMotorController.cpp +++ b/wpilibc/src/main/native/cpp/motorcontrol/PWMMotorController.cpp @@ -4,6 +4,8 @@ #include "frc/motorcontrol/PWMMotorController.h" +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/shuffleboard/ComplexWidget.cpp b/wpilibc/src/main/native/cpp/shuffleboard/ComplexWidget.cpp index eaac17366f5..adc015c914f 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/ComplexWidget.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/ComplexWidget.cpp @@ -4,6 +4,8 @@ #include "frc/shuffleboard/ComplexWidget.h" +#include + #include #include "frc/smartdashboard/SendableBuilderImpl.h" diff --git a/wpilibc/src/main/native/cpp/shuffleboard/RecordingController.cpp b/wpilibc/src/main/native/cpp/shuffleboard/RecordingController.cpp index fb1ef9c6ac0..90adca62085 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/RecordingController.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/RecordingController.cpp @@ -4,6 +4,8 @@ #include "frc/shuffleboard/RecordingController.h" +#include + #include "frc/Errors.h" using namespace frc; diff --git a/wpilibc/src/main/native/cpp/shuffleboard/Shuffleboard.cpp b/wpilibc/src/main/native/cpp/shuffleboard/Shuffleboard.cpp index 913501278fd..0fff070d50a 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/Shuffleboard.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/Shuffleboard.cpp @@ -4,6 +4,8 @@ #include "frc/shuffleboard/Shuffleboard.h" +#include + #include #include "frc/shuffleboard/ShuffleboardTab.h" diff --git a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardComponentBase.cpp b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardComponentBase.cpp index c43fc90890f..4ef59fdd56b 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardComponentBase.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardComponentBase.cpp @@ -4,6 +4,9 @@ #include "frc/shuffleboard/ShuffleboardComponentBase.h" +#include +#include + using namespace frc; ShuffleboardComponentBase::ShuffleboardComponentBase( diff --git a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardContainer.cpp b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardContainer.cpp index ca3c6d69dee..b8f4ccae341 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardContainer.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardContainer.cpp @@ -4,6 +4,11 @@ #include "frc/shuffleboard/ShuffleboardContainer.h" +#include +#include +#include +#include + #include #include diff --git a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardInstance.cpp b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardInstance.cpp index 8c0880a5884..e443e82e8c6 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardInstance.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardInstance.cpp @@ -4,6 +4,9 @@ #include "frc/shuffleboard/ShuffleboardInstance.h" +#include +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardLayout.cpp b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardLayout.cpp index fb7d35bfe4b..da2f71460cc 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardLayout.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardLayout.cpp @@ -4,6 +4,8 @@ #include "frc/shuffleboard/ShuffleboardLayout.h" +#include + #include using namespace frc; diff --git a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardTab.cpp b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardTab.cpp index 6cd1c3878bb..359a63c753b 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardTab.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/ShuffleboardTab.cpp @@ -4,6 +4,8 @@ #include "frc/shuffleboard/ShuffleboardTab.h" +#include + #include using namespace frc; diff --git a/wpilibc/src/main/native/cpp/shuffleboard/SimpleWidget.cpp b/wpilibc/src/main/native/cpp/shuffleboard/SimpleWidget.cpp index c62b76de929..5550136d6d3 100644 --- a/wpilibc/src/main/native/cpp/shuffleboard/SimpleWidget.cpp +++ b/wpilibc/src/main/native/cpp/shuffleboard/SimpleWidget.cpp @@ -4,6 +4,8 @@ #include "frc/shuffleboard/SimpleWidget.h" +#include + #include "frc/shuffleboard/Shuffleboard.h" #include "frc/shuffleboard/ShuffleboardLayout.h" #include "frc/shuffleboard/ShuffleboardTab.h" diff --git a/wpilibc/src/main/native/cpp/simulation/DoubleSolenoidSim.cpp b/wpilibc/src/main/native/cpp/simulation/DoubleSolenoidSim.cpp index da99867b2e4..c6a8d55e59f 100644 --- a/wpilibc/src/main/native/cpp/simulation/DoubleSolenoidSim.cpp +++ b/wpilibc/src/main/native/cpp/simulation/DoubleSolenoidSim.cpp @@ -4,6 +4,9 @@ #include "frc/simulation/DoubleSolenoidSim.h" +#include +#include + #include "frc/PneumaticsBase.h" using namespace frc; diff --git a/wpilibc/src/main/native/cpp/simulation/PneumaticsBaseSim.cpp b/wpilibc/src/main/native/cpp/simulation/PneumaticsBaseSim.cpp index 04aef3a6699..88fed272771 100644 --- a/wpilibc/src/main/native/cpp/simulation/PneumaticsBaseSim.cpp +++ b/wpilibc/src/main/native/cpp/simulation/PneumaticsBaseSim.cpp @@ -4,6 +4,8 @@ #include "frc/simulation/PneumaticsBaseSim.h" +#include + #include "frc/Errors.h" #include "frc/PneumaticsModuleType.h" #include "frc/simulation/CTREPCMSim.h" diff --git a/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp b/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp index 3717128d99e..4973080b546 100644 --- a/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp +++ b/wpilibc/src/main/native/cpp/simulation/RoboRioSim.cpp @@ -5,7 +5,7 @@ #include "frc/simulation/RoboRioSim.h" #include -#include +#include #include diff --git a/wpilibc/src/main/native/cpp/simulation/SolenoidSim.cpp b/wpilibc/src/main/native/cpp/simulation/SolenoidSim.cpp index 29d820783e5..5ad5c20a344 100644 --- a/wpilibc/src/main/native/cpp/simulation/SolenoidSim.cpp +++ b/wpilibc/src/main/native/cpp/simulation/SolenoidSim.cpp @@ -4,6 +4,9 @@ #include "frc/simulation/SolenoidSim.h" +#include +#include + #include "frc/PneumaticsBase.h" using namespace frc; diff --git a/wpilibc/src/main/native/cpp/smartdashboard/Field2d.cpp b/wpilibc/src/main/native/cpp/smartdashboard/Field2d.cpp index ec52e9ccee1..5decef99e23 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/Field2d.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/Field2d.cpp @@ -4,6 +4,9 @@ #include "frc/smartdashboard/Field2d.h" +#include +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/smartdashboard/FieldObject2d.cpp b/wpilibc/src/main/native/cpp/smartdashboard/FieldObject2d.cpp index 3895e870f96..10a027024e3 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/FieldObject2d.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/FieldObject2d.cpp @@ -4,6 +4,7 @@ #include "frc/smartdashboard/FieldObject2d.h" +#include #include #include "frc/trajectory/Trajectory.h" diff --git a/wpilibc/src/main/native/cpp/smartdashboard/ListenerExecutor.cpp b/wpilibc/src/main/native/cpp/smartdashboard/ListenerExecutor.cpp index 2a531969355..0e19026b47f 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/ListenerExecutor.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/ListenerExecutor.cpp @@ -4,6 +4,8 @@ #include "frc/smartdashboard/ListenerExecutor.h" +#include + using namespace frc::detail; void ListenerExecutor::Execute(std::function task) { diff --git a/wpilibc/src/main/native/cpp/smartdashboard/Mechanism2d.cpp b/wpilibc/src/main/native/cpp/smartdashboard/Mechanism2d.cpp index 1bee916c91c..e060e49bf64 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/Mechanism2d.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/Mechanism2d.cpp @@ -4,6 +4,7 @@ #include "frc/smartdashboard/Mechanism2d.h" +#include #include #include diff --git a/wpilibc/src/main/native/cpp/smartdashboard/MechanismLigament2d.cpp b/wpilibc/src/main/native/cpp/smartdashboard/MechanismLigament2d.cpp index 85f112d86a5..bd44a723e32 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/MechanismLigament2d.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/MechanismLigament2d.cpp @@ -4,6 +4,9 @@ #include "frc/smartdashboard/MechanismLigament2d.h" +#include +#include + #include #include diff --git a/wpilibc/src/main/native/cpp/smartdashboard/MechanismObject2d.cpp b/wpilibc/src/main/native/cpp/smartdashboard/MechanismObject2d.cpp index 15d24a38c17..c6419d14031 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/MechanismObject2d.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/MechanismObject2d.cpp @@ -4,6 +4,8 @@ #include "frc/smartdashboard/MechanismObject2d.h" +#include + using namespace frc; MechanismObject2d::MechanismObject2d(std::string_view name) : m_name{name} {} diff --git a/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp b/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp index a49689b81dc..0098eae7367 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp @@ -4,6 +4,10 @@ #include "frc/smartdashboard/SendableBuilderImpl.h" +#include +#include +#include + #include #include #include @@ -18,8 +22,6 @@ #include #include -#include "frc/smartdashboard/SmartDashboard.h" - using namespace frc; template diff --git a/wpilibc/src/main/native/cpp/smartdashboard/SendableChooserBase.cpp b/wpilibc/src/main/native/cpp/smartdashboard/SendableChooserBase.cpp index f19d9e4612a..5375346321b 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/SendableChooserBase.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/SendableChooserBase.cpp @@ -4,6 +4,8 @@ #include "frc/smartdashboard/SendableChooserBase.h" +#include + #include using namespace frc; diff --git a/wpilibc/src/main/native/cpp/smartdashboard/SmartDashboard.cpp b/wpilibc/src/main/native/cpp/smartdashboard/SmartDashboard.cpp index d57473fbe04..30b542b81b4 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/SmartDashboard.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/SmartDashboard.cpp @@ -4,6 +4,11 @@ #include "frc/smartdashboard/SmartDashboard.h" +#include +#include +#include +#include + #include #include #include diff --git a/wpilibc/src/main/native/cpp/sysid/SysIdRoutineLog.cpp b/wpilibc/src/main/native/cpp/sysid/SysIdRoutineLog.cpp index 1ee35b8863b..594aeb76c77 100644 --- a/wpilibc/src/main/native/cpp/sysid/SysIdRoutineLog.cpp +++ b/wpilibc/src/main/native/cpp/sysid/SysIdRoutineLog.cpp @@ -4,6 +4,8 @@ #include "frc/sysid/SysIdRoutineLog.h" +#include + #include #include "frc/DataLogManager.h" diff --git a/wpilibc/src/main/native/cppcs/RobotBase.cpp b/wpilibc/src/main/native/cppcs/RobotBase.cpp index da75ad4c87d..04af2fe3a4c 100644 --- a/wpilibc/src/main/native/cppcs/RobotBase.cpp +++ b/wpilibc/src/main/native/cppcs/RobotBase.cpp @@ -9,6 +9,8 @@ #endif #include +#include +#include #include #include @@ -22,7 +24,6 @@ #include "frc/DriverStation.h" #include "frc/Errors.h" #include "frc/Notifier.h" -#include "frc/RobotState.h" #include "frc/livewindow/LiveWindow.h" #include "frc/smartdashboard/SmartDashboard.h" diff --git a/wpilibc/src/main/native/include/frc/DataLogManager.h b/wpilibc/src/main/native/include/frc/DataLogManager.h index f171cd380a6..a624b5a0120 100644 --- a/wpilibc/src/main/native/include/frc/DataLogManager.h +++ b/wpilibc/src/main/native/include/frc/DataLogManager.h @@ -85,6 +85,12 @@ class DataLogManager final { * @param enabled true to enable, false to disable */ static void LogNetworkTables(bool enabled); + + /** + * Enable or disable logging of the console output. Defaults to enabled. + * @param enabled true to enable, false to disable + */ + static void LogConsoleOutput(bool enabled); }; } // namespace frc diff --git a/wpilibc/src/main/native/include/frc/DoubleSolenoid.h b/wpilibc/src/main/native/include/frc/DoubleSolenoid.h index 57c2c11d82a..e31fb8a290d 100644 --- a/wpilibc/src/main/native/include/frc/DoubleSolenoid.h +++ b/wpilibc/src/main/native/include/frc/DoubleSolenoid.h @@ -70,14 +70,14 @@ class DoubleSolenoid : public wpi::Sendable, * * @param value The value to set (Off, Forward or Reverse) */ - virtual void Set(Value value); + void Set(Value value); /** * Read the current value of the solenoid. * * @return The current value of the solenoid. */ - virtual Value Get() const; + Value Get() const; /** * Toggle the value of the solenoid. diff --git a/wpilibc/src/main/native/include/frc/Solenoid.h b/wpilibc/src/main/native/include/frc/Solenoid.h index 7fa49530a17..ba10a73f205 100644 --- a/wpilibc/src/main/native/include/frc/Solenoid.h +++ b/wpilibc/src/main/native/include/frc/Solenoid.h @@ -52,14 +52,14 @@ class Solenoid : public wpi::Sendable, public wpi::SendableHelper { * * @param on Turn the solenoid output off or on. */ - virtual void Set(bool on); + void Set(bool on); /** * Read the current value of the solenoid. * * @return The current value of the solenoid. */ - virtual bool Get() const; + bool Get() const; /** * Toggle the value of the solenoid. diff --git a/wpilibc/src/main/native/include/frc/simulation/SolenoidSim.h b/wpilibc/src/main/native/include/frc/simulation/SolenoidSim.h index dd2e8e79cc1..0bb471a0938 100644 --- a/wpilibc/src/main/native/include/frc/simulation/SolenoidSim.h +++ b/wpilibc/src/main/native/include/frc/simulation/SolenoidSim.h @@ -16,7 +16,7 @@ class SolenoidSim { SolenoidSim(std::shared_ptr moduleSim, int channel); SolenoidSim(int module, PneumaticsModuleType type, int channel); SolenoidSim(PneumaticsModuleType type, int channel); - virtual ~SolenoidSim() = default; + ~SolenoidSim() = default; bool GetOutput() const; void SetOutput(bool output); @@ -31,8 +31,8 @@ class SolenoidSim { * callback. */ [[nodiscard]] - virtual std::unique_ptr RegisterOutputCallback( - NotifyCallback callback, bool initialNotify); + std::unique_ptr RegisterOutputCallback(NotifyCallback callback, + bool initialNotify); std::shared_ptr GetModuleSim() const; diff --git a/wpilibc/src/test/native/cpp/ScopedTracerTest.cpp b/wpilibc/src/test/native/cpp/ScopedTracerTest.cpp index f4107e72fec..4899a4a63d8 100644 --- a/wpilibc/src/test/native/cpp/ScopedTracerTest.cpp +++ b/wpilibc/src/test/native/cpp/ScopedTracerTest.cpp @@ -24,5 +24,5 @@ TEST(ScopedTracerTest, Timing) { frc::sim::ResumeTiming(); std::string_view out = os.str(); - EXPECT_TRUE(wpi::starts_with(out, " timing_test: 1.5")); + EXPECT_TRUE(wpi::starts_with(out, "\ttiming_test: 1.5")); } diff --git a/wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardInstanceTest.cpp b/wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardInstanceTest.cpp index cb2e0023e86..6354713d5d4 100644 --- a/wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardInstanceTest.cpp +++ b/wpilibc/src/test/native/cpp/shuffleboard/ShuffleboardInstanceTest.cpp @@ -11,7 +11,6 @@ #include #include -#include "frc/shuffleboard/ShuffleboardInstance.h" #include "shuffleboard/MockActuatorSendable.h" class NTWrapper { diff --git a/wpilibc/src/test/native/cpp/shuffleboard/SuppliedValueWidgetTest.cpp b/wpilibc/src/test/native/cpp/shuffleboard/SuppliedValueWidgetTest.cpp index 37185dd27a8..91c68db79aa 100644 --- a/wpilibc/src/test/native/cpp/shuffleboard/SuppliedValueWidgetTest.cpp +++ b/wpilibc/src/test/native/cpp/shuffleboard/SuppliedValueWidgetTest.cpp @@ -2,6 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include +#include + #include #include #include diff --git a/wpilibc/src/test/native/cpp/simulation/AnalogGyroSimTest.cpp b/wpilibc/src/test/native/cpp/simulation/AnalogGyroSimTest.cpp index e82fa0480f0..6352491d36e 100644 --- a/wpilibc/src/test/native/cpp/simulation/AnalogGyroSimTest.cpp +++ b/wpilibc/src/test/native/cpp/simulation/AnalogGyroSimTest.cpp @@ -4,6 +4,8 @@ #include "frc/simulation/AnalogGyroSim.h" // NOLINT(build/include_order) +#include + #include #include diff --git a/wpilibc/src/test/native/cpp/simulation/PDPSimTest.cpp b/wpilibc/src/test/native/cpp/simulation/PDPSimTest.cpp index fc61ebfe613..99652a94968 100644 --- a/wpilibc/src/test/native/cpp/simulation/PDPSimTest.cpp +++ b/wpilibc/src/test/native/cpp/simulation/PDPSimTest.cpp @@ -4,6 +4,8 @@ #include "frc/simulation/PowerDistributionSim.h" // NOLINT(build/include_order) +#include + #include #include diff --git a/wpilibc/src/test/native/cpp/simulation/RoboRioSimTest.cpp b/wpilibc/src/test/native/cpp/simulation/RoboRioSimTest.cpp index 3b74a9157a8..c713005659a 100644 --- a/wpilibc/src/test/native/cpp/simulation/RoboRioSimTest.cpp +++ b/wpilibc/src/test/native/cpp/simulation/RoboRioSimTest.cpp @@ -4,6 +4,8 @@ #include "frc/simulation/RoboRioSim.h" // NOLINT(build/include_order) +#include + #include #include #include diff --git a/wpilibcExamples/src/main/cpp/examples/AprilTagsVision/cpp/Robot.cpp b/wpilibcExamples/src/main/cpp/examples/AprilTagsVision/cpp/Robot.cpp index b5df25d5973..9d060712929 100644 --- a/wpilibcExamples/src/main/cpp/examples/AprilTagsVision/cpp/Robot.cpp +++ b/wpilibcExamples/src/main/cpp/examples/AprilTagsVision/cpp/Robot.cpp @@ -4,9 +4,9 @@ #include #include -#include #include #include +#include #include #include diff --git a/wpilibcExamples/src/main/cpp/examples/ArmBotOffboard/cpp/subsystems/DriveSubsystem.cpp b/wpilibcExamples/src/main/cpp/examples/ArmBotOffboard/cpp/subsystems/DriveSubsystem.cpp index 236d4682357..e5705f1b704 100644 --- a/wpilibcExamples/src/main/cpp/examples/ArmBotOffboard/cpp/subsystems/DriveSubsystem.cpp +++ b/wpilibcExamples/src/main/cpp/examples/ArmBotOffboard/cpp/subsystems/DriveSubsystem.cpp @@ -4,6 +4,8 @@ #include "subsystems/DriveSubsystem.h" +#include + using namespace DriveConstants; DriveSubsystem::DriveSubsystem() diff --git a/wpilibcExamples/src/main/cpp/examples/DifferentialDrivePoseEstimator/cpp/Drivetrain.cpp b/wpilibcExamples/src/main/cpp/examples/DifferentialDrivePoseEstimator/cpp/Drivetrain.cpp index caba17d9e93..3683e9cf422 100644 --- a/wpilibcExamples/src/main/cpp/examples/DifferentialDrivePoseEstimator/cpp/Drivetrain.cpp +++ b/wpilibcExamples/src/main/cpp/examples/DifferentialDrivePoseEstimator/cpp/Drivetrain.cpp @@ -4,7 +4,7 @@ #include "Drivetrain.h" -#include "ExampleGlobalMeasurementSensor.h" +#include Drivetrain::Drivetrain() { m_leftLeader.AddFollower(m_leftFollower); diff --git a/wpilibcExamples/src/main/cpp/examples/Frisbeebot/cpp/RobotContainer.cpp b/wpilibcExamples/src/main/cpp/examples/Frisbeebot/cpp/RobotContainer.cpp index 3841118cc59..449defdb28d 100644 --- a/wpilibcExamples/src/main/cpp/examples/Frisbeebot/cpp/RobotContainer.cpp +++ b/wpilibcExamples/src/main/cpp/examples/Frisbeebot/cpp/RobotContainer.cpp @@ -4,6 +4,8 @@ #include "RobotContainer.h" +#include + RobotContainer::RobotContainer() { // Initialize all of your commands and subsystems here diff --git a/wpilibcExamples/src/main/cpp/examples/I2CCommunication/cpp/Robot.cpp b/wpilibcExamples/src/main/cpp/examples/I2CCommunication/cpp/Robot.cpp index ecfb4802f84..5f4a1a892f9 100644 --- a/wpilibcExamples/src/main/cpp/examples/I2CCommunication/cpp/Robot.cpp +++ b/wpilibcExamples/src/main/cpp/examples/I2CCommunication/cpp/Robot.cpp @@ -4,6 +4,8 @@ #include "Robot.h" +#include + #include #include #include diff --git a/wpilibcIntegrationTests/src/main/native/cpp/AnalogLoopTest.cpp b/wpilibcIntegrationTests/src/main/native/cpp/AnalogLoopTest.cpp index cf3f30fb241..7a7af84f6e2 100644 --- a/wpilibcIntegrationTests/src/main/native/cpp/AnalogLoopTest.cpp +++ b/wpilibcIntegrationTests/src/main/native/cpp/AnalogLoopTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include diff --git a/wpilibcIntegrationTests/src/main/native/cpp/DMATest.cpp b/wpilibcIntegrationTests/src/main/native/cpp/DMATest.cpp index 30a1caf558a..35d94b5549e 100644 --- a/wpilibcIntegrationTests/src/main/native/cpp/DMATest.cpp +++ b/wpilibcIntegrationTests/src/main/native/cpp/DMATest.cpp @@ -2,17 +2,18 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. -#include -#include -#include -#include -#include +#include #include #include "TestBench.h" +#include "frc/AnalogInput.h" +#include "frc/AnalogOutput.h" #include "frc/DMA.h" #include "frc/DMASample.h" +#include "frc/DigitalOutput.h" +#include "frc/Timer.h" +#include "frc/motorcontrol/Jaguar.h" using namespace frc; diff --git a/wpilibcIntegrationTests/src/main/native/cpp/FakeEncoderTest.cpp b/wpilibcIntegrationTests/src/main/native/cpp/FakeEncoderTest.cpp index 0d4999fe19b..44033fe515c 100644 --- a/wpilibcIntegrationTests/src/main/native/cpp/FakeEncoderTest.cpp +++ b/wpilibcIntegrationTests/src/main/native/cpp/FakeEncoderTest.cpp @@ -4,6 +4,8 @@ #include "frc/Encoder.h" // NOLINT(build/include_order) +#include + #include #include diff --git a/wpilibcIntegrationTests/src/main/native/cpp/PreferencesTest.cpp b/wpilibcIntegrationTests/src/main/native/cpp/PreferencesTest.cpp index cdc8ecbd42a..03c6819185b 100644 --- a/wpilibcIntegrationTests/src/main/native/cpp/PreferencesTest.cpp +++ b/wpilibcIntegrationTests/src/main/native/cpp/PreferencesTest.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DataLogManager.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DataLogManager.java index 3b6bbd61c6e..b0143e0fc4d 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/DataLogManager.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/DataLogManager.java @@ -5,6 +5,7 @@ package edu.wpi.first.wpilibj; import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.util.FileLogger; import edu.wpi.first.util.WPIUtilJNI; import edu.wpi.first.util.concurrent.Event; import edu.wpi.first.util.datalog.DataLog; @@ -52,6 +53,8 @@ public final class DataLogManager { private static boolean m_ntLoggerEnabled = true; private static int m_ntEntryLogger; private static int m_ntConnLogger; + private static boolean m_consoleLoggerEnabled = true; + private static FileLogger m_consoleLogger; private static StringLogEntry m_messageLog; // if less than this much free space, delete log files until there is this much free space @@ -121,6 +124,10 @@ public static synchronized void start(String dir, String filename, double period if (m_ntLoggerEnabled) { startNtLog(); } + // Log console output + if (m_consoleLoggerEnabled) { + startConsoleLog(); + } } else if (m_stopped) { m_log.setFilename(makeLogFilename(filename)); m_log.resume(); @@ -205,6 +212,25 @@ public static synchronized void logNetworkTables(boolean enabled) { } } + /** + * Enable or disable logging of the console output. Defaults to enabled. + * + * @param enabled true to enable, false to disable + */ + public static synchronized void logConsoleOutput(boolean enabled) { + boolean wasEnabled = m_consoleLoggerEnabled; + m_consoleLoggerEnabled = enabled; + if (m_log == null) { + start(); + return; + } + if (enabled && !wasEnabled) { + startConsoleLog(); + } else if (!enabled && wasEnabled) { + stopConsoleLog(); + } + } + private static String makeLogDir(String dir) { if (!dir.isEmpty()) { return dir; @@ -266,6 +292,18 @@ private static void stopNtLog() { NetworkTableInstance.stopConnectionDataLog(m_ntConnLogger); } + private static void startConsoleLog() { + if (RobotBase.isReal()) { + m_consoleLogger = new FileLogger("/home/lvuser/FRC_UserProgram.log", m_log, "console"); + } + } + + private static void stopConsoleLog() { + if (RobotBase.isReal()) { + m_consoleLogger.close(); + } + } + private static void logMain() { // based on free disk space, scan for "old" FRC_*.wpilog files and remove { diff --git a/wpimath/.styleguide b/wpimath/.styleguide index 00437ce869e..3e67f48eec5 100644 --- a/wpimath/.styleguide +++ b/wpimath/.styleguide @@ -38,6 +38,7 @@ includeOtherLibs { ^Eigen/ ^fmt/ ^gcem/ + ^google/ ^gtest/ ^unsupported/ ^wpi/ diff --git a/wpimath/CMakeLists.txt b/wpimath/CMakeLists.txt index 52624ed9d52..2b75f8d14ba 100644 --- a/wpimath/CMakeLists.txt +++ b/wpimath/CMakeLists.txt @@ -6,9 +6,11 @@ include(AddTest) include(DownloadAndCheck) include(WpiProtobuf) -# workaround for makefiles - for some reason parent directories aren't created. -file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/protobuf") -file(GLOB wpimath_proto_src src/main/proto/*.proto) +if(WITH_PROTOBUF) + # workaround for makefiles - for some reason parent directories aren't created. + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/protobuf") + file(GLOB wpimath_proto_src src/main/proto/*.proto) +endif() file( GLOB wpimath_jni_src @@ -120,21 +122,28 @@ file( src/main/native/thirdparty/sleipnir/src/*.cpp ) list(REMOVE_ITEM wpimath_native_src ${wpimath_jni_src}) +if(NOT WITH_PROTOBUF) + list(FILTER wpimath_native_src EXCLUDE REGEX "/proto/") +endif() set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS FALSE) -add_library(protobuf OBJECT) -target_link_libraries(protobuf wpiutil) +if(WITH_PROTOBUF) + add_library(protobuf OBJECT) + target_link_libraries(protobuf wpiutil) -add_library(wpimath ${wpimath_native_src} $) + add_library(wpimath ${wpimath_native_src} $) -wpi_protobuf_generate( - TARGET - protobuf - PROTOS ${wpimath_proto_src} - PLUGIN ${PROTOC_WPILIB_PLUGIN} - PROTOC_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/protobuf" -) + wpi_protobuf_generate( + TARGET + protobuf + PROTOS ${wpimath_proto_src} + PLUGIN ${PROTOC_WPILIB_PLUGIN} + PROTOC_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/protobuf" + ) +else() + add_library(wpimath ${wpimath_native_src}) +endif() if(MSVC) get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) @@ -164,12 +173,18 @@ set_target_properties(wpimath PROPERTIES DEBUG_POSTFIX "d") set_property(TARGET wpimath PROPERTY FOLDER "libraries") target_compile_definitions(wpimath PRIVATE WPILIB_EXPORTS SLEIPNIR_EXPORTS) -target_compile_features(protobuf PUBLIC cxx_std_20) target_compile_features(wpimath PUBLIC cxx_std_20) if(MSVC) target_compile_options(wpimath PUBLIC /utf-8 /bigobj) - target_compile_options(protobuf PUBLIC /utf-8 /bigobj) endif() + +if(WITH_PROTOBUF) + target_compile_features(protobuf PUBLIC cxx_std_20) + if(MSVC) + target_compile_options(protobuf PUBLIC /utf-8 /bigobj) + endif() +endif() + wpilib_target_warnings(wpimath) target_link_libraries(wpimath wpiutil) diff --git a/wpimath/src/main/native/cpp/MathShared.cpp b/wpimath/src/main/native/cpp/MathShared.cpp index b53d080ac06..5b2d14671f6 100644 --- a/wpimath/src/main/native/cpp/MathShared.cpp +++ b/wpimath/src/main/native/cpp/MathShared.cpp @@ -4,6 +4,9 @@ #include "wpimath/MathShared.h" +#include +#include + #include #include diff --git a/wpimath/src/main/native/cpp/controller/ArmFeedforward.cpp b/wpimath/src/main/native/cpp/controller/ArmFeedforward.cpp index 57a7f45ed4f..4cfaf89157b 100644 --- a/wpimath/src/main/native/cpp/controller/ArmFeedforward.cpp +++ b/wpimath/src/main/native/cpp/controller/ArmFeedforward.cpp @@ -4,6 +4,7 @@ #include "frc/controller/ArmFeedforward.h" +#include #include #include diff --git a/wpimath/src/main/native/cpp/estimator/DifferentialDrivePoseEstimator.cpp b/wpimath/src/main/native/cpp/estimator/DifferentialDrivePoseEstimator.cpp index 213ba991760..bf844a12aa8 100644 --- a/wpimath/src/main/native/cpp/estimator/DifferentialDrivePoseEstimator.cpp +++ b/wpimath/src/main/native/cpp/estimator/DifferentialDrivePoseEstimator.cpp @@ -4,6 +4,8 @@ #include "frc/estimator/DifferentialDrivePoseEstimator.h" +#include + using namespace frc; DifferentialDrivePoseEstimator::DifferentialDrivePoseEstimator( diff --git a/wpimath/src/main/native/cpp/geometry/Ellipse2d.cpp b/wpimath/src/main/native/cpp/geometry/Ellipse2d.cpp index 4288b8b44bf..6f8afa636a2 100644 --- a/wpimath/src/main/native/cpp/geometry/Ellipse2d.cpp +++ b/wpimath/src/main/native/cpp/geometry/Ellipse2d.cpp @@ -6,8 +6,6 @@ #include -#include "geometry2d.pb.h" - using namespace frc; units::meter_t Ellipse2d::Distance(const Translation2d& point) const { diff --git a/wpimath/src/main/native/cpp/geometry/Pose3d.cpp b/wpimath/src/main/native/cpp/geometry/Pose3d.cpp index bd7ab8681e8..66c5bab910b 100644 --- a/wpimath/src/main/native/cpp/geometry/Pose3d.cpp +++ b/wpimath/src/main/native/cpp/geometry/Pose3d.cpp @@ -5,12 +5,11 @@ #include "frc/geometry/Pose3d.h" #include +#include #include #include -#include "geometry3d.pb.h" - using namespace frc; namespace { diff --git a/wpimath/src/main/native/cpp/geometry/Rectangle2d.cpp b/wpimath/src/main/native/cpp/geometry/Rectangle2d.cpp deleted file mode 100644 index 0d1f77bc64f..00000000000 --- a/wpimath/src/main/native/cpp/geometry/Rectangle2d.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -#include "frc/geometry/Rectangle2d.h" - -#include "geometry2d.pb.h" diff --git a/wpimath/src/main/native/cpp/geometry/Rotation2d.cpp b/wpimath/src/main/native/cpp/geometry/Rotation2d.cpp index 69193028f77..921e1f81a09 100644 --- a/wpimath/src/main/native/cpp/geometry/Rotation2d.cpp +++ b/wpimath/src/main/native/cpp/geometry/Rotation2d.cpp @@ -8,7 +8,6 @@ #include -#include "geometry2d.pb.h" #include "units/math.h" using namespace frc; diff --git a/wpimath/src/main/native/cpp/geometry/Rotation3d.cpp b/wpimath/src/main/native/cpp/geometry/Rotation3d.cpp index 072d023cb28..b8c4063eb73 100644 --- a/wpimath/src/main/native/cpp/geometry/Rotation3d.cpp +++ b/wpimath/src/main/native/cpp/geometry/Rotation3d.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -13,7 +14,6 @@ #include #include "frc/fmt/Eigen.h" -#include "geometry3d.pb.h" #include "units/math.h" #include "wpimath/MathShared.h" diff --git a/wpimath/src/main/native/cpp/geometry/Transform2d.cpp b/wpimath/src/main/native/cpp/geometry/Transform2d.cpp index 157359bfbc5..25b05907ed9 100644 --- a/wpimath/src/main/native/cpp/geometry/Transform2d.cpp +++ b/wpimath/src/main/native/cpp/geometry/Transform2d.cpp @@ -5,7 +5,6 @@ #include "frc/geometry/Transform2d.h" #include "frc/geometry/Pose2d.h" -#include "geometry2d.pb.h" using namespace frc; diff --git a/wpimath/src/main/native/cpp/geometry/Transform3d.cpp b/wpimath/src/main/native/cpp/geometry/Transform3d.cpp index 4879bb12ad5..34dad68f277 100644 --- a/wpimath/src/main/native/cpp/geometry/Transform3d.cpp +++ b/wpimath/src/main/native/cpp/geometry/Transform3d.cpp @@ -4,6 +4,8 @@ #include "frc/geometry/Transform3d.h" +#include + #include "frc/geometry/Pose3d.h" using namespace frc; diff --git a/wpimath/src/main/native/cpp/geometry/Translation2d.cpp b/wpimath/src/main/native/cpp/geometry/Translation2d.cpp index c0a349e7aac..3d7d5d7d0bb 100644 --- a/wpimath/src/main/native/cpp/geometry/Translation2d.cpp +++ b/wpimath/src/main/native/cpp/geometry/Translation2d.cpp @@ -4,9 +4,10 @@ #include "frc/geometry/Translation2d.h" +#include + #include -#include "geometry2d.pb.h" #include "units/math.h" using namespace frc; diff --git a/wpimath/src/main/native/cpp/geometry/Translation3d.cpp b/wpimath/src/main/native/cpp/geometry/Translation3d.cpp index c3b8cb4b775..69757f30801 100644 --- a/wpimath/src/main/native/cpp/geometry/Translation3d.cpp +++ b/wpimath/src/main/native/cpp/geometry/Translation3d.cpp @@ -6,7 +6,6 @@ #include -#include "geometry3d.pb.h" #include "units/length.h" #include "units/math.h" diff --git a/wpimath/src/main/native/cpp/jni/TrajectoryUtilJNI.cpp b/wpimath/src/main/native/cpp/jni/TrajectoryUtilJNI.cpp index 1066e037c8c..62abc36e8ed 100644 --- a/wpimath/src/main/native/cpp/jni/TrajectoryUtilJNI.cpp +++ b/wpimath/src/main/native/cpp/jni/TrajectoryUtilJNI.cpp @@ -5,6 +5,7 @@ #include #include +#include #include diff --git a/wpimath/src/main/native/cpp/spline/SplineHelper.cpp b/wpimath/src/main/native/cpp/spline/SplineHelper.cpp index c78a54f4645..cd47ab03834 100644 --- a/wpimath/src/main/native/cpp/spline/SplineHelper.cpp +++ b/wpimath/src/main/native/cpp/spline/SplineHelper.cpp @@ -5,6 +5,7 @@ #include "frc/spline/SplineHelper.h" #include +#include using namespace frc; diff --git a/wpimath/src/main/native/cpp/trajectory/Trajectory.cpp b/wpimath/src/main/native/cpp/trajectory/Trajectory.cpp index 5393f8318ce..467c3a89d09 100644 --- a/wpimath/src/main/native/cpp/trajectory/Trajectory.cpp +++ b/wpimath/src/main/native/cpp/trajectory/Trajectory.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/wpimath/src/main/native/cpp/trajectory/TrajectoryGenerator.cpp b/wpimath/src/main/native/cpp/trajectory/TrajectoryGenerator.cpp index daf6670385a..e12157a43c9 100644 --- a/wpimath/src/main/native/cpp/trajectory/TrajectoryGenerator.cpp +++ b/wpimath/src/main/native/cpp/trajectory/TrajectoryGenerator.cpp @@ -5,6 +5,7 @@ #include "frc/trajectory/TrajectoryGenerator.h" #include +#include #include diff --git a/wpimath/src/main/native/cpp/trajectory/TrajectoryParameterizer.cpp b/wpimath/src/main/native/cpp/trajectory/TrajectoryParameterizer.cpp index 4c0a55e4702..fb2d6cdb6bb 100644 --- a/wpimath/src/main/native/cpp/trajectory/TrajectoryParameterizer.cpp +++ b/wpimath/src/main/native/cpp/trajectory/TrajectoryParameterizer.cpp @@ -28,6 +28,8 @@ #include "frc/trajectory/TrajectoryParameterizer.h" +#include + #include #include "units/math.h" diff --git a/wpimath/src/main/native/cpp/trajectory/TrajectoryUtil.cpp b/wpimath/src/main/native/cpp/trajectory/TrajectoryUtil.cpp index d9cb853a5bf..644af1beb37 100644 --- a/wpimath/src/main/native/cpp/trajectory/TrajectoryUtil.cpp +++ b/wpimath/src/main/native/cpp/trajectory/TrajectoryUtil.cpp @@ -4,6 +4,7 @@ #include "frc/trajectory/TrajectoryUtil.h" +#include #include #include @@ -28,14 +29,12 @@ void TrajectoryUtil::ToPathweaverJson(const Trajectory& trajectory, } Trajectory TrajectoryUtil::FromPathweaverJson(std::string_view path) { - std::error_code ec; - std::unique_ptr fileBuffer = - wpi::MemoryBuffer::GetFile(path, ec); - if (fileBuffer == nullptr || ec) { + auto fileBuffer = wpi::MemoryBuffer::GetFile(path); + if (!fileBuffer) { throw std::runtime_error(fmt::format("Cannot open file: {}", path)); } - wpi::json json = wpi::json::parse(fileBuffer->GetCharBuffer()); + wpi::json json = wpi::json::parse(fileBuffer.value()->GetCharBuffer()); return Trajectory{json.get>()}; } diff --git a/wpimath/src/main/native/cpp/trajectory/constraint/DifferentialDriveKinematicsConstraint.cpp b/wpimath/src/main/native/cpp/trajectory/constraint/DifferentialDriveKinematicsConstraint.cpp index 460ff8b5d7f..8e4093ca70e 100644 --- a/wpimath/src/main/native/cpp/trajectory/constraint/DifferentialDriveKinematicsConstraint.cpp +++ b/wpimath/src/main/native/cpp/trajectory/constraint/DifferentialDriveKinematicsConstraint.cpp @@ -4,6 +4,8 @@ #include "frc/trajectory/constraint/DifferentialDriveKinematicsConstraint.h" +#include + using namespace frc; DifferentialDriveKinematicsConstraint::DifferentialDriveKinematicsConstraint( diff --git a/wpimath/src/main/native/cpp/trajectory/constraint/DifferentialDriveVoltageConstraint.cpp b/wpimath/src/main/native/cpp/trajectory/constraint/DifferentialDriveVoltageConstraint.cpp index 46c306e09f7..f18012804c5 100644 --- a/wpimath/src/main/native/cpp/trajectory/constraint/DifferentialDriveVoltageConstraint.cpp +++ b/wpimath/src/main/native/cpp/trajectory/constraint/DifferentialDriveVoltageConstraint.cpp @@ -6,6 +6,7 @@ #include #include +#include #include diff --git a/wpimath/src/main/native/cpp/trajectory/proto/TrajectoryProto.cpp b/wpimath/src/main/native/cpp/trajectory/proto/TrajectoryProto.cpp index f4f5eb92d14..3190719d597 100644 --- a/wpimath/src/main/native/cpp/trajectory/proto/TrajectoryProto.cpp +++ b/wpimath/src/main/native/cpp/trajectory/proto/TrajectoryProto.cpp @@ -4,6 +4,8 @@ #include "frc/trajectory/proto/TrajectoryProto.h" +#include + #include #include "trajectory.pb.h" diff --git a/wpimath/src/main/native/include/frc/controller/ArmFeedforward.h b/wpimath/src/main/native/include/frc/controller/ArmFeedforward.h index ab5ba920fcb..f5647324ac7 100644 --- a/wpimath/src/main/native/include/frc/controller/ArmFeedforward.h +++ b/wpimath/src/main/native/include/frc/controller/ArmFeedforward.h @@ -235,5 +235,7 @@ class WPILIB_DLLEXPORT ArmFeedforward { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/controller/proto/ArmFeedforwardProto.h" +#endif #include "frc/controller/struct/ArmFeedforwardStruct.h" diff --git a/wpimath/src/main/native/include/frc/controller/DifferentialDriveFeedforward.h b/wpimath/src/main/native/include/frc/controller/DifferentialDriveFeedforward.h index be7e5b4facc..ff4ed61015f 100644 --- a/wpimath/src/main/native/include/frc/controller/DifferentialDriveFeedforward.h +++ b/wpimath/src/main/native/include/frc/controller/DifferentialDriveFeedforward.h @@ -87,5 +87,7 @@ class WPILIB_DLLEXPORT DifferentialDriveFeedforward { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/controller/proto/DifferentialDriveFeedforwardProto.h" +#endif #include "frc/controller/struct/DifferentialDriveFeedforwardStruct.h" diff --git a/wpimath/src/main/native/include/frc/controller/DifferentialDriveWheelVoltages.h b/wpimath/src/main/native/include/frc/controller/DifferentialDriveWheelVoltages.h index 424cd2d1b39..6d9b6dd0562 100644 --- a/wpimath/src/main/native/include/frc/controller/DifferentialDriveWheelVoltages.h +++ b/wpimath/src/main/native/include/frc/controller/DifferentialDriveWheelVoltages.h @@ -21,5 +21,7 @@ struct DifferentialDriveWheelVoltages { } // namespace frc +#ifndef NO_PROTOBUF #include "frc/controller/proto/DifferentialDriveWheelVoltagesProto.h" +#endif #include "frc/controller/struct/DifferentialDriveWheelVoltagesStruct.h" diff --git a/wpimath/src/main/native/include/frc/controller/ElevatorFeedforward.h b/wpimath/src/main/native/include/frc/controller/ElevatorFeedforward.h index 2180ab0b7b8..6c7f9279797 100644 --- a/wpimath/src/main/native/include/frc/controller/ElevatorFeedforward.h +++ b/wpimath/src/main/native/include/frc/controller/ElevatorFeedforward.h @@ -225,5 +225,7 @@ class ElevatorFeedforward { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/controller/proto/ElevatorFeedforwardProto.h" +#endif #include "frc/controller/struct/ElevatorFeedforwardStruct.h" diff --git a/wpimath/src/main/native/include/frc/geometry/Ellipse2d.h b/wpimath/src/main/native/include/frc/geometry/Ellipse2d.h index f57303d1e87..e1731105ebb 100644 --- a/wpimath/src/main/native/include/frc/geometry/Ellipse2d.h +++ b/wpimath/src/main/native/include/frc/geometry/Ellipse2d.h @@ -208,5 +208,7 @@ class WPILIB_DLLEXPORT Ellipse2d { } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Ellipse2dProto.h" +#endif #include "frc/geometry/struct/Ellipse2dStruct.h" diff --git a/wpimath/src/main/native/include/frc/geometry/Pose2d.h b/wpimath/src/main/native/include/frc/geometry/Pose2d.h index 65a146c3dd7..7f8f47cafe3 100644 --- a/wpimath/src/main/native/include/frc/geometry/Pose2d.h +++ b/wpimath/src/main/native/include/frc/geometry/Pose2d.h @@ -213,6 +213,8 @@ void from_json(const wpi::json& json, Pose2d& pose); } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Pose2dProto.h" +#endif #include "frc/geometry/struct/Pose2dStruct.h" #include "frc/geometry/Pose2d.inc" diff --git a/wpimath/src/main/native/include/frc/geometry/Pose3d.h b/wpimath/src/main/native/include/frc/geometry/Pose3d.h index 526dced399d..f077a610109 100644 --- a/wpimath/src/main/native/include/frc/geometry/Pose3d.h +++ b/wpimath/src/main/native/include/frc/geometry/Pose3d.h @@ -215,5 +215,7 @@ void from_json(const wpi::json& json, Pose3d& pose); } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Pose3dProto.h" +#endif #include "frc/geometry/struct/Pose3dStruct.h" diff --git a/wpimath/src/main/native/include/frc/geometry/Quaternion.h b/wpimath/src/main/native/include/frc/geometry/Quaternion.h index 4fe694cf25e..4a4927632b8 100644 --- a/wpimath/src/main/native/include/frc/geometry/Quaternion.h +++ b/wpimath/src/main/native/include/frc/geometry/Quaternion.h @@ -191,5 +191,7 @@ void from_json(const wpi::json& json, Quaternion& quaternion); } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/QuaternionProto.h" +#endif #include "frc/geometry/struct/QuaternionStruct.h" diff --git a/wpimath/src/main/native/include/frc/geometry/Rectangle2d.h b/wpimath/src/main/native/include/frc/geometry/Rectangle2d.h index f03ca98c448..22ee80f22e6 100644 --- a/wpimath/src/main/native/include/frc/geometry/Rectangle2d.h +++ b/wpimath/src/main/native/include/frc/geometry/Rectangle2d.h @@ -206,5 +206,7 @@ class WPILIB_DLLEXPORT Rectangle2d { } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Rectangle2dProto.h" +#endif #include "frc/geometry/struct/Rectangle2dStruct.h" diff --git a/wpimath/src/main/native/include/frc/geometry/Rotation2d.h b/wpimath/src/main/native/include/frc/geometry/Rotation2d.h index 6e9cd8e2a88..4e5357e9bb8 100644 --- a/wpimath/src/main/native/include/frc/geometry/Rotation2d.h +++ b/wpimath/src/main/native/include/frc/geometry/Rotation2d.h @@ -169,6 +169,8 @@ void from_json(const wpi::json& json, Rotation2d& rotation); } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Rotation2dProto.h" +#endif #include "frc/geometry/struct/Rotation2dStruct.h" #include "frc/geometry/Rotation2d.inc" diff --git a/wpimath/src/main/native/include/frc/geometry/Rotation3d.h b/wpimath/src/main/native/include/frc/geometry/Rotation3d.h index bc01f2b8ee2..632f2ba29f9 100644 --- a/wpimath/src/main/native/include/frc/geometry/Rotation3d.h +++ b/wpimath/src/main/native/include/frc/geometry/Rotation3d.h @@ -195,5 +195,7 @@ void from_json(const wpi::json& json, Rotation3d& rotation); } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Rotation3dProto.h" +#endif #include "frc/geometry/struct/Rotation3dStruct.h" diff --git a/wpimath/src/main/native/include/frc/geometry/Transform2d.h b/wpimath/src/main/native/include/frc/geometry/Transform2d.h index dccc0e1eeec..af984eadb4a 100644 --- a/wpimath/src/main/native/include/frc/geometry/Transform2d.h +++ b/wpimath/src/main/native/include/frc/geometry/Transform2d.h @@ -124,6 +124,8 @@ class WPILIB_DLLEXPORT Transform2d { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Transform2dProto.h" +#endif #include "frc/geometry/struct/Transform2dStruct.h" #include "frc/geometry/Transform2d.inc" diff --git a/wpimath/src/main/native/include/frc/geometry/Transform3d.h b/wpimath/src/main/native/include/frc/geometry/Transform3d.h index 94ecfe37eda..9f42d185812 100644 --- a/wpimath/src/main/native/include/frc/geometry/Transform3d.h +++ b/wpimath/src/main/native/include/frc/geometry/Transform3d.h @@ -130,5 +130,7 @@ class WPILIB_DLLEXPORT Transform3d { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Transform3dProto.h" +#endif #include "frc/geometry/struct/Transform3dStruct.h" diff --git a/wpimath/src/main/native/include/frc/geometry/Translation2d.h b/wpimath/src/main/native/include/frc/geometry/Translation2d.h index 674bd9efe16..5c91e9d8fde 100644 --- a/wpimath/src/main/native/include/frc/geometry/Translation2d.h +++ b/wpimath/src/main/native/include/frc/geometry/Translation2d.h @@ -232,6 +232,8 @@ void from_json(const wpi::json& json, Translation2d& state); } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Translation2dProto.h" +#endif #include "frc/geometry/struct/Translation2dStruct.h" #include "frc/geometry/Translation2d.inc" diff --git a/wpimath/src/main/native/include/frc/geometry/Translation3d.h b/wpimath/src/main/native/include/frc/geometry/Translation3d.h index b83b661fd98..75e5bf3dcf3 100644 --- a/wpimath/src/main/native/include/frc/geometry/Translation3d.h +++ b/wpimath/src/main/native/include/frc/geometry/Translation3d.h @@ -199,6 +199,8 @@ void from_json(const wpi::json& json, Translation3d& state); } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Translation3dProto.h" +#endif #include "frc/geometry/struct/Translation3dStruct.h" #include "frc/geometry/Translation3d.inc" diff --git a/wpimath/src/main/native/include/frc/geometry/Twist2d.h b/wpimath/src/main/native/include/frc/geometry/Twist2d.h index d13cc4ec80b..4d61501d998 100644 --- a/wpimath/src/main/native/include/frc/geometry/Twist2d.h +++ b/wpimath/src/main/native/include/frc/geometry/Twist2d.h @@ -58,5 +58,7 @@ struct WPILIB_DLLEXPORT Twist2d { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Twist2dProto.h" +#endif #include "frc/geometry/struct/Twist2dStruct.h" diff --git a/wpimath/src/main/native/include/frc/geometry/Twist3d.h b/wpimath/src/main/native/include/frc/geometry/Twist3d.h index 3262367dc0f..2ce4a964e3f 100644 --- a/wpimath/src/main/native/include/frc/geometry/Twist3d.h +++ b/wpimath/src/main/native/include/frc/geometry/Twist3d.h @@ -78,5 +78,7 @@ struct WPILIB_DLLEXPORT Twist3d { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/geometry/proto/Twist3dProto.h" +#endif #include "frc/geometry/struct/Twist3dStruct.h" diff --git a/wpimath/src/main/native/include/frc/kinematics/ChassisSpeeds.h b/wpimath/src/main/native/include/frc/kinematics/ChassisSpeeds.h index 299e18a28b2..4e8302b154a 100644 --- a/wpimath/src/main/native/include/frc/kinematics/ChassisSpeeds.h +++ b/wpimath/src/main/native/include/frc/kinematics/ChassisSpeeds.h @@ -279,5 +279,7 @@ struct WPILIB_DLLEXPORT ChassisSpeeds { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/kinematics/proto/ChassisSpeedsProto.h" +#endif #include "frc/kinematics/struct/ChassisSpeedsStruct.h" diff --git a/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveKinematics.h b/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveKinematics.h index fbbb519182f..11c04be7a49 100644 --- a/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveKinematics.h +++ b/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveKinematics.h @@ -99,5 +99,7 @@ class WPILIB_DLLEXPORT DifferentialDriveKinematics }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/kinematics/proto/DifferentialDriveKinematicsProto.h" +#endif #include "frc/kinematics/struct/DifferentialDriveKinematicsStruct.h" diff --git a/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveWheelPositions.h b/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveWheelPositions.h index f22d6874f66..60575cf8c73 100644 --- a/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveWheelPositions.h +++ b/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveWheelPositions.h @@ -50,5 +50,7 @@ struct WPILIB_DLLEXPORT DifferentialDriveWheelPositions { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/kinematics/proto/DifferentialDriveWheelPositionsProto.h" +#endif #include "frc/kinematics/struct/DifferentialDriveWheelPositionsStruct.h" diff --git a/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveWheelSpeeds.h b/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveWheelSpeeds.h index 676b8ad59c6..98db2b861aa 100644 --- a/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveWheelSpeeds.h +++ b/wpimath/src/main/native/include/frc/kinematics/DifferentialDriveWheelSpeeds.h @@ -113,5 +113,7 @@ struct WPILIB_DLLEXPORT DifferentialDriveWheelSpeeds { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/kinematics/proto/DifferentialDriveWheelSpeedsProto.h" +#endif #include "frc/kinematics/struct/DifferentialDriveWheelSpeedsStruct.h" diff --git a/wpimath/src/main/native/include/frc/kinematics/MecanumDriveKinematics.h b/wpimath/src/main/native/include/frc/kinematics/MecanumDriveKinematics.h index 218908fd31a..e23e7e3adbd 100644 --- a/wpimath/src/main/native/include/frc/kinematics/MecanumDriveKinematics.h +++ b/wpimath/src/main/native/include/frc/kinematics/MecanumDriveKinematics.h @@ -200,5 +200,7 @@ class WPILIB_DLLEXPORT MecanumDriveKinematics } // namespace frc +#ifndef NO_PROTOBUF #include "frc/kinematics/proto/MecanumDriveKinematicsProto.h" +#endif #include "frc/kinematics/struct/MecanumDriveKinematicsStruct.h" diff --git a/wpimath/src/main/native/include/frc/kinematics/MecanumDriveWheelPositions.h b/wpimath/src/main/native/include/frc/kinematics/MecanumDriveWheelPositions.h index 77d79192b9d..8a9943bcc80 100644 --- a/wpimath/src/main/native/include/frc/kinematics/MecanumDriveWheelPositions.h +++ b/wpimath/src/main/native/include/frc/kinematics/MecanumDriveWheelPositions.h @@ -61,5 +61,7 @@ struct WPILIB_DLLEXPORT MecanumDriveWheelPositions { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/kinematics/proto/MecanumDriveWheelPositionsProto.h" +#endif #include "frc/kinematics/struct/MecanumDriveWheelPositionsStruct.h" diff --git a/wpimath/src/main/native/include/frc/kinematics/MecanumDriveWheelSpeeds.h b/wpimath/src/main/native/include/frc/kinematics/MecanumDriveWheelSpeeds.h index 5df198c8018..10f971e988a 100644 --- a/wpimath/src/main/native/include/frc/kinematics/MecanumDriveWheelSpeeds.h +++ b/wpimath/src/main/native/include/frc/kinematics/MecanumDriveWheelSpeeds.h @@ -121,5 +121,7 @@ struct WPILIB_DLLEXPORT MecanumDriveWheelSpeeds { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/kinematics/proto/MecanumDriveWheelSpeedsProto.h" +#endif #include "frc/kinematics/struct/MecanumDriveWheelSpeedsStruct.h" diff --git a/wpimath/src/main/native/include/frc/kinematics/SwerveModulePosition.h b/wpimath/src/main/native/include/frc/kinematics/SwerveModulePosition.h index 576bfcf00f9..4cbe97fcb57 100644 --- a/wpimath/src/main/native/include/frc/kinematics/SwerveModulePosition.h +++ b/wpimath/src/main/native/include/frc/kinematics/SwerveModulePosition.h @@ -43,5 +43,7 @@ struct WPILIB_DLLEXPORT SwerveModulePosition { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/kinematics/proto/SwerveModulePositionProto.h" +#endif #include "frc/kinematics/struct/SwerveModulePositionStruct.h" diff --git a/wpimath/src/main/native/include/frc/kinematics/SwerveModuleState.h b/wpimath/src/main/native/include/frc/kinematics/SwerveModuleState.h index 3060d35fc24..adfeebbbbfc 100644 --- a/wpimath/src/main/native/include/frc/kinematics/SwerveModuleState.h +++ b/wpimath/src/main/native/include/frc/kinematics/SwerveModuleState.h @@ -48,5 +48,7 @@ struct WPILIB_DLLEXPORT SwerveModuleState { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/kinematics/proto/SwerveModuleStateProto.h" +#endif #include "frc/kinematics/struct/SwerveModuleStateStruct.h" diff --git a/wpimath/src/main/native/include/frc/spline/CubicHermiteSpline.h b/wpimath/src/main/native/include/frc/spline/CubicHermiteSpline.h index 420566b3d5b..2580b1be7e5 100644 --- a/wpimath/src/main/native/include/frc/spline/CubicHermiteSpline.h +++ b/wpimath/src/main/native/include/frc/spline/CubicHermiteSpline.h @@ -115,5 +115,7 @@ class WPILIB_DLLEXPORT CubicHermiteSpline : public Spline<3> { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/spline/proto/CubicHermiteSplineProto.h" +#endif #include "frc/spline/struct/CubicHermiteSplineStruct.h" diff --git a/wpimath/src/main/native/include/frc/spline/QuinticHermiteSpline.h b/wpimath/src/main/native/include/frc/spline/QuinticHermiteSpline.h index fb0d227e291..1c592eb2fa8 100644 --- a/wpimath/src/main/native/include/frc/spline/QuinticHermiteSpline.h +++ b/wpimath/src/main/native/include/frc/spline/QuinticHermiteSpline.h @@ -125,5 +125,7 @@ class WPILIB_DLLEXPORT QuinticHermiteSpline : public Spline<5> { }; } // namespace frc +#ifndef NO_PROTOBUF #include "frc/spline/proto/QuinticHermiteSplineProto.h" +#endif #include "frc/spline/struct/QuinticHermiteSplineStruct.h" diff --git a/wpimath/src/main/native/include/frc/system/proto/LinearSystemProto.h b/wpimath/src/main/native/include/frc/system/proto/LinearSystemProto.h index 6d5452fc72a..f47f63e67c0 100644 --- a/wpimath/src/main/native/include/frc/system/proto/LinearSystemProto.h +++ b/wpimath/src/main/native/include/frc/system/proto/LinearSystemProto.h @@ -6,7 +6,6 @@ #include -#include "frc/proto/MatrixProto.h" #include "frc/system/LinearSystem.h" template diff --git a/wpimath/src/main/native/include/frc/system/proto/LinearSystemProto.inc b/wpimath/src/main/native/include/frc/system/proto/LinearSystemProto.inc index f41d8e91ec9..5151f4e17b8 100644 --- a/wpimath/src/main/native/include/frc/system/proto/LinearSystemProto.inc +++ b/wpimath/src/main/native/include/frc/system/proto/LinearSystemProto.inc @@ -9,6 +9,7 @@ #include #include +#include "frc/proto/MatrixProto.h" #include "frc/system/proto/LinearSystemProto.h" #include "system.pb.h" diff --git a/wpimath/src/main/native/include/frc/trajectory/Trajectory.h b/wpimath/src/main/native/include/frc/trajectory/Trajectory.h index 753bf9e2d14..ba29617ee16 100644 --- a/wpimath/src/main/native/include/frc/trajectory/Trajectory.h +++ b/wpimath/src/main/native/include/frc/trajectory/Trajectory.h @@ -146,5 +146,7 @@ void from_json(const wpi::json& json, Trajectory::State& state); } // namespace frc +#ifndef NO_PROTOBUF #include "frc/trajectory/proto/TrajectoryProto.h" #include "frc/trajectory/proto/TrajectoryStateProto.h" +#endif diff --git a/wpimath/src/main/native/thirdparty/sleipnir/include/sleipnir/util/Print.hpp b/wpimath/src/main/native/thirdparty/sleipnir/include/sleipnir/util/Print.hpp index a9220cdaadc..c01fd4ac679 100644 --- a/wpimath/src/main/native/thirdparty/sleipnir/include/sleipnir/util/Print.hpp +++ b/wpimath/src/main/native/thirdparty/sleipnir/include/sleipnir/util/Print.hpp @@ -2,6 +2,7 @@ #pragma once +#include #include #include diff --git a/wpimath/src/main/native/thirdparty/sleipnir/src/optimization/solver/InteriorPoint.cpp b/wpimath/src/main/native/thirdparty/sleipnir/src/optimization/solver/InteriorPoint.cpp index 1470eb235bf..892d2dd20f7 100644 --- a/wpimath/src/main/native/thirdparty/sleipnir/src/optimization/solver/InteriorPoint.cpp +++ b/wpimath/src/main/native/thirdparty/sleipnir/src/optimization/solver/InteriorPoint.cpp @@ -240,11 +240,16 @@ void InteriorPoint(std::span decisionVariables, // Error estimate double E_0 = std::numeric_limits::infinity(); - iterationsStartTime = std::chrono::system_clock::now(); + if (config.diagnostics) { + iterationsStartTime = std::chrono::system_clock::now(); + } while (E_0 > config.tolerance && acceptableIterCounter < config.maxAcceptableIterations) { - auto innerIterStartTime = std::chrono::system_clock::now(); + std::chrono::system_clock::time_point innerIterStartTime; + if (config.diagnostics) { + innerIterStartTime = std::chrono::system_clock::now(); + } // Check for local equality constraint infeasibility if (IsEqualityLocallyInfeasible(A_e, c_e)) { diff --git a/wpimath/src/test/native/cpp/ProtoTestBase.h b/wpimath/src/test/native/cpp/ProtoTestBase.h index 88e149e3e0a..5a5affd812c 100644 --- a/wpimath/src/test/native/cpp/ProtoTestBase.h +++ b/wpimath/src/test/native/cpp/ProtoTestBase.h @@ -4,15 +4,10 @@ #pragma once +#include #include #include -#include "controller.pb.h" -#include "kinematics.pb.h" -#include "spline.pb.h" -#include "system.pb.h" -#include "wpimath.pb.h" - template class ProtoTest : public testing::Test {}; diff --git a/wpimath/src/test/native/cpp/controller/proto/ArmFeedforwardProtoTest.cpp b/wpimath/src/test/native/cpp/controller/proto/ArmFeedforwardProtoTest.cpp index 4df8566db27..6ad9579a745 100644 --- a/wpimath/src/test/native/cpp/controller/proto/ArmFeedforwardProtoTest.cpp +++ b/wpimath/src/test/native/cpp/controller/proto/ArmFeedforwardProtoTest.cpp @@ -2,9 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include -#include "controller.pb.h" #include "frc/controller/ArmFeedforward.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/controller/proto/DifferentialDriveWheelVoltagesProtoTest.cpp b/wpimath/src/test/native/cpp/controller/proto/DifferentialDriveWheelVoltagesProtoTest.cpp index 1adad90fd76..466aa50f399 100644 --- a/wpimath/src/test/native/cpp/controller/proto/DifferentialDriveWheelVoltagesProtoTest.cpp +++ b/wpimath/src/test/native/cpp/controller/proto/DifferentialDriveWheelVoltagesProtoTest.cpp @@ -2,9 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include -#include "controller.pb.h" #include "frc/controller/DifferentialDriveWheelVoltages.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/controller/proto/ElevatorFeedforwardProtoTest.cpp b/wpimath/src/test/native/cpp/controller/proto/ElevatorFeedforwardProtoTest.cpp index 5ec136f6aab..62d8bdb4c85 100644 --- a/wpimath/src/test/native/cpp/controller/proto/ElevatorFeedforwardProtoTest.cpp +++ b/wpimath/src/test/native/cpp/controller/proto/ElevatorFeedforwardProtoTest.cpp @@ -2,9 +2,9 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include -#include "controller.pb.h" #include "frc/controller/ElevatorFeedforward.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/estimator/DifferentialDrivePoseEstimatorTest.cpp b/wpimath/src/test/native/cpp/estimator/DifferentialDrivePoseEstimatorTest.cpp index fbc2d212331..f6d229ec653 100644 --- a/wpimath/src/test/native/cpp/estimator/DifferentialDrivePoseEstimatorTest.cpp +++ b/wpimath/src/test/native/cpp/estimator/DifferentialDrivePoseEstimatorTest.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include diff --git a/wpimath/src/test/native/cpp/estimator/ExtendedKalmanFilterTest.cpp b/wpimath/src/test/native/cpp/estimator/ExtendedKalmanFilterTest.cpp index d631cfc7f8c..362de8b699e 100644 --- a/wpimath/src/test/native/cpp/estimator/ExtendedKalmanFilterTest.cpp +++ b/wpimath/src/test/native/cpp/estimator/ExtendedKalmanFilterTest.cpp @@ -2,8 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. -#include #include +#include #include #include diff --git a/wpimath/src/test/native/cpp/estimator/MecanumDrivePoseEstimatorTest.cpp b/wpimath/src/test/native/cpp/estimator/MecanumDrivePoseEstimatorTest.cpp index 8ba38c23256..ae2f573874d 100644 --- a/wpimath/src/test/native/cpp/estimator/MecanumDrivePoseEstimatorTest.cpp +++ b/wpimath/src/test/native/cpp/estimator/MecanumDrivePoseEstimatorTest.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff --git a/wpimath/src/test/native/cpp/estimator/SwerveDrivePoseEstimatorTest.cpp b/wpimath/src/test/native/cpp/estimator/SwerveDrivePoseEstimatorTest.cpp index 9619e6a30f3..11938246981 100644 --- a/wpimath/src/test/native/cpp/estimator/SwerveDrivePoseEstimatorTest.cpp +++ b/wpimath/src/test/native/cpp/estimator/SwerveDrivePoseEstimatorTest.cpp @@ -3,9 +3,9 @@ // the WPILib BSD license file in the root directory of this project. #include -#include #include #include +#include #include #include diff --git a/wpimath/src/test/native/cpp/estimator/UnscentedKalmanFilterTest.cpp b/wpimath/src/test/native/cpp/estimator/UnscentedKalmanFilterTest.cpp index 66be5083098..c2c6f824d8d 100644 --- a/wpimath/src/test/native/cpp/estimator/UnscentedKalmanFilterTest.cpp +++ b/wpimath/src/test/native/cpp/estimator/UnscentedKalmanFilterTest.cpp @@ -2,8 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. -#include #include +#include #include #include diff --git a/wpimath/src/test/native/cpp/geometry/proto/Ellipse2dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Ellipse2dProtoTest.cpp index 47819002b53..810d368e638 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Ellipse2dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Ellipse2dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Ellipse2d.h" -#include "geometry2d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Pose2dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Pose2dProtoTest.cpp index c6e9d49ec5c..64067dde4b5 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Pose2dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Pose2dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Pose2d.h" -#include "geometry2d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Pose3dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Pose3dProtoTest.cpp index d8847cab88e..f685f9b8e17 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Pose3dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Pose3dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Pose3d.h" -#include "geometry3d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/QuaternionProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/QuaternionProtoTest.cpp index 92338df8327..13c206e6aad 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/QuaternionProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/QuaternionProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Quaternion.h" -#include "geometry3d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Rectangle2dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Rectangle2dProtoTest.cpp index 4949c0bb14d..04f2d774f2c 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Rectangle2dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Rectangle2dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Rectangle2d.h" -#include "geometry2d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Rotation2dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Rotation2dProtoTest.cpp index 3ab9e1bb26f..4a10988ab75 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Rotation2dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Rotation2dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Rotation2d.h" -#include "geometry2d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Rotation3dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Rotation3dProtoTest.cpp index a83b78c2a08..7850894b0ae 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Rotation3dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Rotation3dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Rotation3d.h" -#include "geometry3d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Transform2dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Transform2dProtoTest.cpp index 4b975f3e142..6225426f328 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Transform2dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Transform2dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Transform2d.h" -#include "geometry2d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Transform3dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Transform3dProtoTest.cpp index 3a86421cfa3..c5731eea0d1 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Transform3dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Transform3dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Transform3d.h" -#include "geometry3d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Translation2dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Translation2dProtoTest.cpp index e6a895969dd..37ec61b3b1a 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Translation2dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Translation2dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Translation2d.h" -#include "geometry2d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Translation3dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Translation3dProtoTest.cpp index 3f6d59f9cfb..732b1a62afe 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Translation3dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Translation3dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Translation3d.h" -#include "geometry3d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Twist2dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Twist2dProtoTest.cpp index d9f4faeb213..305d3297d87 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Twist2dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Twist2dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Twist2d.h" -#include "geometry2d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/geometry/proto/Twist3dProtoTest.cpp b/wpimath/src/test/native/cpp/geometry/proto/Twist3dProtoTest.cpp index b4e7bf0730b..9c454840a06 100644 --- a/wpimath/src/test/native/cpp/geometry/proto/Twist3dProtoTest.cpp +++ b/wpimath/src/test/native/cpp/geometry/proto/Twist3dProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/geometry/Twist3d.h" -#include "geometry3d.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/kinematics/proto/ChassisSpeedsProtoTest.cpp b/wpimath/src/test/native/cpp/kinematics/proto/ChassisSpeedsProtoTest.cpp index 375909a330c..9d91a5b2ffa 100644 --- a/wpimath/src/test/native/cpp/kinematics/proto/ChassisSpeedsProtoTest.cpp +++ b/wpimath/src/test/native/cpp/kinematics/proto/ChassisSpeedsProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/kinematics/ChassisSpeeds.h" -#include "kinematics.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/kinematics/proto/DifferentialDriveKinematicsProtoTest.cpp b/wpimath/src/test/native/cpp/kinematics/proto/DifferentialDriveKinematicsProtoTest.cpp index 4d57108833e..47ed61fea6a 100644 --- a/wpimath/src/test/native/cpp/kinematics/proto/DifferentialDriveKinematicsProtoTest.cpp +++ b/wpimath/src/test/native/cpp/kinematics/proto/DifferentialDriveKinematicsProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/kinematics/DifferentialDriveKinematics.h" -#include "kinematics.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/kinematics/proto/DifferentialDriveWheelSpeedsProtoTest.cpp b/wpimath/src/test/native/cpp/kinematics/proto/DifferentialDriveWheelSpeedsProtoTest.cpp index 83e317f2060..35ac5aebce3 100644 --- a/wpimath/src/test/native/cpp/kinematics/proto/DifferentialDriveWheelSpeedsProtoTest.cpp +++ b/wpimath/src/test/native/cpp/kinematics/proto/DifferentialDriveWheelSpeedsProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/kinematics/DifferentialDriveWheelSpeeds.h" -#include "kinematics.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveKinematicsProtoTest.cpp b/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveKinematicsProtoTest.cpp index c601fc3b4d4..fd1b4d15269 100644 --- a/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveKinematicsProtoTest.cpp +++ b/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveKinematicsProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/kinematics/MecanumDriveKinematics.h" -#include "kinematics.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveWheelPositionsProtoTest.cpp b/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveWheelPositionsProtoTest.cpp index e63ffbeadd6..fae1f0b33e7 100644 --- a/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveWheelPositionsProtoTest.cpp +++ b/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveWheelPositionsProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/kinematics/MecanumDriveWheelPositions.h" -#include "kinematics.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveWheelSpeedsProtoTest.cpp b/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveWheelSpeedsProtoTest.cpp index ae91c3a1eb5..26a98b4cb6d 100644 --- a/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveWheelSpeedsProtoTest.cpp +++ b/wpimath/src/test/native/cpp/kinematics/proto/MecanumDriveWheelSpeedsProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/kinematics/MecanumDriveWheelSpeeds.h" -#include "kinematics.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/kinematics/proto/SwerveDriveKinematicsProtoTest.cpp b/wpimath/src/test/native/cpp/kinematics/proto/SwerveDriveKinematicsProtoTest.cpp index 80af48935f5..776d2b4756f 100644 --- a/wpimath/src/test/native/cpp/kinematics/proto/SwerveDriveKinematicsProtoTest.cpp +++ b/wpimath/src/test/native/cpp/kinematics/proto/SwerveDriveKinematicsProtoTest.cpp @@ -2,6 +2,7 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "../../ProtoTestBase.h" diff --git a/wpimath/src/test/native/cpp/kinematics/proto/SwerveModulePositionProtoTest.cpp b/wpimath/src/test/native/cpp/kinematics/proto/SwerveModulePositionProtoTest.cpp index c511b9f840a..4a3013e6f8e 100644 --- a/wpimath/src/test/native/cpp/kinematics/proto/SwerveModulePositionProtoTest.cpp +++ b/wpimath/src/test/native/cpp/kinematics/proto/SwerveModulePositionProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/kinematics/SwerveModulePosition.h" -#include "kinematics.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/kinematics/proto/SwerveModuleStateProtoTest.cpp b/wpimath/src/test/native/cpp/kinematics/proto/SwerveModuleStateProtoTest.cpp index e210db94790..c86152d93a7 100644 --- a/wpimath/src/test/native/cpp/kinematics/proto/SwerveModuleStateProtoTest.cpp +++ b/wpimath/src/test/native/cpp/kinematics/proto/SwerveModuleStateProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/kinematics/SwerveModuleState.h" -#include "kinematics.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/system/LinearSystemIDTest.cpp b/wpimath/src/test/native/cpp/system/LinearSystemIDTest.cpp index 7b59f59f70c..39e8a8c2564 100644 --- a/wpimath/src/test/native/cpp/system/LinearSystemIDTest.cpp +++ b/wpimath/src/test/native/cpp/system/LinearSystemIDTest.cpp @@ -8,7 +8,6 @@ #include -#include "frc/system/plant/LinearSystemId.h" #include "units/length.h" #include "units/mass.h" diff --git a/wpimath/src/test/native/cpp/system/plant/proto/DCMotorProtoTest.cpp b/wpimath/src/test/native/cpp/system/plant/proto/DCMotorProtoTest.cpp index d977cf4e715..2c4a6747dfc 100644 --- a/wpimath/src/test/native/cpp/system/plant/proto/DCMotorProtoTest.cpp +++ b/wpimath/src/test/native/cpp/system/plant/proto/DCMotorProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/system/plant/DCMotor.h" -#include "plant.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/trajectory/proto/TrajectoryProtoTest.cpp b/wpimath/src/test/native/cpp/trajectory/proto/TrajectoryProtoTest.cpp index 400689bf847..eb60c9dd01f 100644 --- a/wpimath/src/test/native/cpp/trajectory/proto/TrajectoryProtoTest.cpp +++ b/wpimath/src/test/native/cpp/trajectory/proto/TrajectoryProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/trajectory/Trajectory.h" -#include "trajectory.pb.h" using namespace frc; diff --git a/wpimath/src/test/native/cpp/trajectory/proto/TrajectoryStateProtoTest.cpp b/wpimath/src/test/native/cpp/trajectory/proto/TrajectoryStateProtoTest.cpp index 1d0b0497de9..4f3e42c0971 100644 --- a/wpimath/src/test/native/cpp/trajectory/proto/TrajectoryStateProtoTest.cpp +++ b/wpimath/src/test/native/cpp/trajectory/proto/TrajectoryStateProtoTest.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include #include #include "frc/trajectory/Trajectory.h" -#include "trajectory.pb.h" using namespace frc; diff --git a/wpinet/examples/dsclient/dsclient.cpp b/wpinet/examples/dsclient/dsclient.cpp index 596f617ac32..7f8b74e36d3 100644 --- a/wpinet/examples/dsclient/dsclient.cpp +++ b/wpinet/examples/dsclient/dsclient.cpp @@ -3,13 +3,13 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include #include #include "wpinet/DsClient.h" #include "wpinet/EventLoopRunner.h" -#include "wpinet/uv/Error.h" namespace uv = wpi::uv; diff --git a/wpinet/examples/parallelconnect/parallelconnect.cpp b/wpinet/examples/parallelconnect/parallelconnect.cpp index fecdac84737..adcc74e4621 100644 --- a/wpinet/examples/parallelconnect/parallelconnect.cpp +++ b/wpinet/examples/parallelconnect/parallelconnect.cpp @@ -3,6 +3,7 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include diff --git a/wpinet/examples/webserver/webserver.cpp b/wpinet/examples/webserver/webserver.cpp index 53dd6ea1b47..0579c3fd653 100644 --- a/wpinet/examples/webserver/webserver.cpp +++ b/wpinet/examples/webserver/webserver.cpp @@ -3,6 +3,7 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include diff --git a/wpinet/src/main/native/cpp/DsClient.cpp b/wpinet/src/main/native/cpp/DsClient.cpp index 97509cb323a..02a19c60088 100644 --- a/wpinet/src/main/native/cpp/DsClient.cpp +++ b/wpinet/src/main/native/cpp/DsClient.cpp @@ -4,6 +4,8 @@ #include "wpinet/DsClient.h" +#include + #include #include #include diff --git a/wpinet/src/main/native/cpp/EventLoopRunner.cpp b/wpinet/src/main/native/cpp/EventLoopRunner.cpp index 6c143ac674f..8ee976c0d66 100644 --- a/wpinet/src/main/native/cpp/EventLoopRunner.cpp +++ b/wpinet/src/main/native/cpp/EventLoopRunner.cpp @@ -4,6 +4,9 @@ #include "wpinet/EventLoopRunner.h" +#include +#include + #include #include #include diff --git a/wpinet/src/main/native/cpp/HttpServerConnection.cpp b/wpinet/src/main/native/cpp/HttpServerConnection.cpp index 765173e2ce2..8e8b5d0ffe0 100644 --- a/wpinet/src/main/native/cpp/HttpServerConnection.cpp +++ b/wpinet/src/main/native/cpp/HttpServerConnection.cpp @@ -4,6 +4,8 @@ #include "wpinet/HttpServerConnection.h" +#include + #include #include #include diff --git a/wpinet/src/main/native/cpp/HttpUtil.cpp b/wpinet/src/main/native/cpp/HttpUtil.cpp index 12ff0841bfe..c17f68288f3 100644 --- a/wpinet/src/main/native/cpp/HttpUtil.cpp +++ b/wpinet/src/main/native/cpp/HttpUtil.cpp @@ -5,14 +5,14 @@ #include "wpinet/HttpUtil.h" #include +#include +#include #include #include #include #include -#include "wpinet/TCPConnector.h" - namespace wpi { std::string_view UnescapeURI(std::string_view str, SmallVectorImpl& buf, diff --git a/wpinet/src/main/native/cpp/MulticastServiceAnnouncer.cpp b/wpinet/src/main/native/cpp/MulticastServiceAnnouncer.cpp index daa7e8df038..3885d93f283 100644 --- a/wpinet/src/main/native/cpp/MulticastServiceAnnouncer.cpp +++ b/wpinet/src/main/native/cpp/MulticastServiceAnnouncer.cpp @@ -4,6 +4,9 @@ #include "wpinet/MulticastServiceAnnouncer.h" +#include +#include + #include #include "MulticastHandleManager.h" diff --git a/wpinet/src/main/native/cpp/MulticastServiceResolver.cpp b/wpinet/src/main/native/cpp/MulticastServiceResolver.cpp index c16db2e2e80..4a320899452 100644 --- a/wpinet/src/main/native/cpp/MulticastServiceResolver.cpp +++ b/wpinet/src/main/native/cpp/MulticastServiceResolver.cpp @@ -4,6 +4,10 @@ #include "wpinet/MulticastServiceResolver.h" +#include +#include +#include + #include #include "MulticastHandleManager.h" diff --git a/wpinet/src/main/native/cpp/ParallelTcpConnector.cpp b/wpinet/src/main/native/cpp/ParallelTcpConnector.cpp index 5fb1dd5ea29..30663fc7325 100644 --- a/wpinet/src/main/native/cpp/ParallelTcpConnector.cpp +++ b/wpinet/src/main/native/cpp/ParallelTcpConnector.cpp @@ -5,6 +5,10 @@ #include "wpinet/ParallelTcpConnector.h" #include +#include +#include +#include +#include #include #include diff --git a/wpinet/src/main/native/cpp/PortForwarder.cpp b/wpinet/src/main/native/cpp/PortForwarder.cpp index 7ba9ac485d6..d0e085df031 100644 --- a/wpinet/src/main/native/cpp/PortForwarder.cpp +++ b/wpinet/src/main/native/cpp/PortForwarder.cpp @@ -4,6 +4,9 @@ #include "wpinet/PortForwarder.h" +#include +#include + #include #include #include diff --git a/wpinet/src/main/native/cpp/SocketError.cpp b/wpinet/src/main/native/cpp/SocketError.cpp index 233c5de366c..26a43efe2a2 100644 --- a/wpinet/src/main/native/cpp/SocketError.cpp +++ b/wpinet/src/main/native/cpp/SocketError.cpp @@ -4,6 +4,8 @@ #include "wpinet/SocketError.h" +#include + #ifdef _WIN32 #include #else diff --git a/wpinet/src/main/native/cpp/UDPClient.cpp b/wpinet/src/main/native/cpp/UDPClient.cpp index 1e9bc872ddf..6a438b15f3c 100644 --- a/wpinet/src/main/native/cpp/UDPClient.cpp +++ b/wpinet/src/main/native/cpp/UDPClient.cpp @@ -16,6 +16,8 @@ #include #endif +#include + #include #include diff --git a/wpinet/src/main/native/cpp/WebSocket.cpp b/wpinet/src/main/native/cpp/WebSocket.cpp index 3a6c346ba4d..142369c1da9 100644 --- a/wpinet/src/main/native/cpp/WebSocket.cpp +++ b/wpinet/src/main/native/cpp/WebSocket.cpp @@ -4,10 +4,13 @@ #include "wpinet/WebSocket.h" +#include +#include #include #include #include #include +#include #include #include diff --git a/wpinet/src/main/native/cpp/WebSocketServer.cpp b/wpinet/src/main/native/cpp/WebSocketServer.cpp index 383d8559cc7..9b75aabaeda 100644 --- a/wpinet/src/main/native/cpp/WebSocketServer.cpp +++ b/wpinet/src/main/native/cpp/WebSocketServer.cpp @@ -4,6 +4,7 @@ #include "wpinet/WebSocketServer.h" +#include #include #include diff --git a/wpinet/src/main/native/cpp/jni/WPINetJNI.cpp b/wpinet/src/main/native/cpp/jni/WPINetJNI.cpp index 1528001ea5c..fb59c4d9598 100644 --- a/wpinet/src/main/native/cpp/jni/WPINetJNI.cpp +++ b/wpinet/src/main/native/cpp/jni/WPINetJNI.cpp @@ -4,6 +4,11 @@ #include +#include +#include +#include +#include + #include #include "../MulticastHandleManager.h" diff --git a/wpinet/src/main/native/cpp/uv/Async.cpp b/wpinet/src/main/native/cpp/uv/Async.cpp index 58ef5f392b3..17f7c57f694 100644 --- a/wpinet/src/main/native/cpp/uv/Async.cpp +++ b/wpinet/src/main/native/cpp/uv/Async.cpp @@ -4,6 +4,8 @@ #include "wpinet/uv/Async.h" +#include + #include "wpinet/uv/Loop.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/cpp/uv/Check.cpp b/wpinet/src/main/native/cpp/uv/Check.cpp index 75ff47c7a47..25c3ed41586 100644 --- a/wpinet/src/main/native/cpp/uv/Check.cpp +++ b/wpinet/src/main/native/cpp/uv/Check.cpp @@ -4,6 +4,8 @@ #include "wpinet/uv/Check.h" +#include + #include "wpinet/uv/Loop.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/cpp/uv/FsEvent.cpp b/wpinet/src/main/native/cpp/uv/FsEvent.cpp index d77bf37c4be..65d1af57036 100644 --- a/wpinet/src/main/native/cpp/uv/FsEvent.cpp +++ b/wpinet/src/main/native/cpp/uv/FsEvent.cpp @@ -5,6 +5,8 @@ #include "wpinet/uv/FsEvent.h" #include +#include +#include #include diff --git a/wpinet/src/main/native/cpp/uv/GetAddrInfo.cpp b/wpinet/src/main/native/cpp/uv/GetAddrInfo.cpp index c3ec00010e4..0b547e6ff52 100644 --- a/wpinet/src/main/native/cpp/uv/GetAddrInfo.cpp +++ b/wpinet/src/main/native/cpp/uv/GetAddrInfo.cpp @@ -4,10 +4,13 @@ #include "wpinet/uv/GetAddrInfo.h" +#include +#include +#include + #include #include "wpinet/uv/Loop.h" -#include "wpinet/uv/util.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/cpp/uv/GetNameInfo.cpp b/wpinet/src/main/native/cpp/uv/GetNameInfo.cpp index 9720cc3be7e..0a4b4a4d0e6 100644 --- a/wpinet/src/main/native/cpp/uv/GetNameInfo.cpp +++ b/wpinet/src/main/native/cpp/uv/GetNameInfo.cpp @@ -4,6 +4,10 @@ #include "wpinet/uv/GetNameInfo.h" +#include +#include +#include + #include "wpinet/uv/Loop.h" #include "wpinet/uv/util.h" diff --git a/wpinet/src/main/native/cpp/uv/Idle.cpp b/wpinet/src/main/native/cpp/uv/Idle.cpp index 7b94b3f4a88..665f4f2e2be 100644 --- a/wpinet/src/main/native/cpp/uv/Idle.cpp +++ b/wpinet/src/main/native/cpp/uv/Idle.cpp @@ -4,6 +4,8 @@ #include "wpinet/uv/Idle.h" +#include + #include "wpinet/uv/Loop.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/cpp/uv/Loop.cpp b/wpinet/src/main/native/cpp/uv/Loop.cpp index d48e230dab9..2aee216ed01 100644 --- a/wpinet/src/main/native/cpp/uv/Loop.cpp +++ b/wpinet/src/main/native/cpp/uv/Loop.cpp @@ -4,6 +4,8 @@ #include "wpinet/uv/Loop.h" +#include + using namespace wpi::uv; Loop::Loop(const private_init&) noexcept { diff --git a/wpinet/src/main/native/cpp/uv/NetworkStream.cpp b/wpinet/src/main/native/cpp/uv/NetworkStream.cpp index 12750b2b769..8dc7e544570 100644 --- a/wpinet/src/main/native/cpp/uv/NetworkStream.cpp +++ b/wpinet/src/main/native/cpp/uv/NetworkStream.cpp @@ -4,6 +4,9 @@ #include "wpinet/uv/NetworkStream.h" +#include +#include + namespace wpi::uv { ConnectReq::ConnectReq() { diff --git a/wpinet/src/main/native/cpp/uv/Pipe.cpp b/wpinet/src/main/native/cpp/uv/Pipe.cpp index 799360409e7..ad93687e89e 100644 --- a/wpinet/src/main/native/cpp/uv/Pipe.cpp +++ b/wpinet/src/main/native/cpp/uv/Pipe.cpp @@ -5,6 +5,10 @@ #include "wpinet/uv/Pipe.h" #include +#include +#include +#include +#include #include diff --git a/wpinet/src/main/native/cpp/uv/Poll.cpp b/wpinet/src/main/native/cpp/uv/Poll.cpp index 7d356151182..5967bbd298b 100644 --- a/wpinet/src/main/native/cpp/uv/Poll.cpp +++ b/wpinet/src/main/native/cpp/uv/Poll.cpp @@ -4,6 +4,10 @@ #include "wpinet/uv/Poll.h" +#include +#include +#include + #include "wpinet/uv/Loop.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/cpp/uv/Prepare.cpp b/wpinet/src/main/native/cpp/uv/Prepare.cpp index aa1a89d6e13..88e146e7f0a 100644 --- a/wpinet/src/main/native/cpp/uv/Prepare.cpp +++ b/wpinet/src/main/native/cpp/uv/Prepare.cpp @@ -4,6 +4,8 @@ #include "wpinet/uv/Prepare.h" +#include + #include "wpinet/uv/Loop.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/cpp/uv/Process.cpp b/wpinet/src/main/native/cpp/uv/Process.cpp index c872ff9b85d..7a653078e9d 100644 --- a/wpinet/src/main/native/cpp/uv/Process.cpp +++ b/wpinet/src/main/native/cpp/uv/Process.cpp @@ -4,6 +4,8 @@ #include "wpinet/uv/Process.h" +#include + #include #include "wpinet/uv/Loop.h" diff --git a/wpinet/src/main/native/cpp/uv/Signal.cpp b/wpinet/src/main/native/cpp/uv/Signal.cpp index 8f998e2b486..c8fde756b02 100644 --- a/wpinet/src/main/native/cpp/uv/Signal.cpp +++ b/wpinet/src/main/native/cpp/uv/Signal.cpp @@ -4,6 +4,8 @@ #include "wpinet/uv/Signal.h" +#include + #include "wpinet/uv/Loop.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/cpp/uv/Stream.cpp b/wpinet/src/main/native/cpp/uv/Stream.cpp index 164b30ac2e1..79c333d5e7e 100644 --- a/wpinet/src/main/native/cpp/uv/Stream.cpp +++ b/wpinet/src/main/native/cpp/uv/Stream.cpp @@ -4,6 +4,11 @@ #include "wpinet/uv/Stream.h" +#include +#include +#include +#include + #include #include #include diff --git a/wpinet/src/main/native/cpp/uv/Tcp.cpp b/wpinet/src/main/native/cpp/uv/Tcp.cpp index b163a0efbaa..5b54edd4f16 100644 --- a/wpinet/src/main/native/cpp/uv/Tcp.cpp +++ b/wpinet/src/main/native/cpp/uv/Tcp.cpp @@ -5,6 +5,9 @@ #include "wpinet/uv/Tcp.h" #include +#include +#include +#include #include "wpinet/uv/util.h" diff --git a/wpinet/src/main/native/cpp/uv/Timer.cpp b/wpinet/src/main/native/cpp/uv/Timer.cpp index e9b33fc7c7d..fa5e3bce6e8 100644 --- a/wpinet/src/main/native/cpp/uv/Timer.cpp +++ b/wpinet/src/main/native/cpp/uv/Timer.cpp @@ -4,6 +4,10 @@ #include "wpinet/uv/Timer.h" +#include +#include +#include + #include "wpinet/uv/Loop.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/cpp/uv/Tty.cpp b/wpinet/src/main/native/cpp/uv/Tty.cpp index 5e5756cacc8..58f3a072c02 100644 --- a/wpinet/src/main/native/cpp/uv/Tty.cpp +++ b/wpinet/src/main/native/cpp/uv/Tty.cpp @@ -4,6 +4,8 @@ #include "wpinet/uv/Tty.h" +#include + #include "wpinet/uv/Loop.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/cpp/uv/Udp.cpp b/wpinet/src/main/native/cpp/uv/Udp.cpp index 1922c57596f..f9b9896379e 100644 --- a/wpinet/src/main/native/cpp/uv/Udp.cpp +++ b/wpinet/src/main/native/cpp/uv/Udp.cpp @@ -5,6 +5,9 @@ #include "wpinet/uv/Udp.h" #include +#include +#include +#include #include #include diff --git a/wpinet/src/main/native/cpp/uv/Work.cpp b/wpinet/src/main/native/cpp/uv/Work.cpp index d94619fd211..c19f2f4db05 100644 --- a/wpinet/src/main/native/cpp/uv/Work.cpp +++ b/wpinet/src/main/native/cpp/uv/Work.cpp @@ -4,6 +4,10 @@ #include "wpinet/uv/Work.h" +#include +#include +#include + #include "wpinet/uv/Loop.h" namespace wpi::uv { diff --git a/wpinet/src/main/native/linux/MulticastServiceAnnouncer.cpp b/wpinet/src/main/native/linux/MulticastServiceAnnouncer.cpp index d04711fa57c..d6cbcb83a25 100644 --- a/wpinet/src/main/native/linux/MulticastServiceAnnouncer.cpp +++ b/wpinet/src/main/native/linux/MulticastServiceAnnouncer.cpp @@ -4,6 +4,9 @@ #include "wpinet/MulticastServiceAnnouncer.h" +#include +#include +#include #include #include diff --git a/wpinet/src/main/native/linux/MulticastServiceResolver.cpp b/wpinet/src/main/native/linux/MulticastServiceResolver.cpp index a408639138b..e0598a03681 100644 --- a/wpinet/src/main/native/linux/MulticastServiceResolver.cpp +++ b/wpinet/src/main/native/linux/MulticastServiceResolver.cpp @@ -4,6 +4,10 @@ #include "wpinet/MulticastServiceResolver.h" +#include +#include +#include + #include #include #include diff --git a/wpinet/src/main/native/macOS/MulticastServiceAnnouncer.cpp b/wpinet/src/main/native/macOS/MulticastServiceAnnouncer.cpp index 8c31a3b22fe..3fcb585f8c1 100644 --- a/wpinet/src/main/native/macOS/MulticastServiceAnnouncer.cpp +++ b/wpinet/src/main/native/macOS/MulticastServiceAnnouncer.cpp @@ -6,6 +6,10 @@ #include +#include +#include +#include + #include #include "dns_sd.h" diff --git a/wpinet/src/main/native/macOS/MulticastServiceResolver.cpp b/wpinet/src/main/native/macOS/MulticastServiceResolver.cpp index eecf819814f..dc18dab7399 100644 --- a/wpinet/src/main/native/macOS/MulticastServiceResolver.cpp +++ b/wpinet/src/main/native/macOS/MulticastServiceResolver.cpp @@ -10,7 +10,10 @@ #include #include +#include +#include #include +#include #include #include diff --git a/wpinet/src/main/native/macOS/ResolverThread.cpp b/wpinet/src/main/native/macOS/ResolverThread.cpp index 14526709e1d..b113fd817d9 100644 --- a/wpinet/src/main/native/macOS/ResolverThread.cpp +++ b/wpinet/src/main/native/macOS/ResolverThread.cpp @@ -7,6 +7,9 @@ #include "ResolverThread.h" #include +#include +#include +#include #include diff --git a/wpinet/src/main/native/windows/MulticastServiceAnnouncer.cpp b/wpinet/src/main/native/windows/MulticastServiceAnnouncer.cpp index c1ed58d480a..21a103d712b 100644 --- a/wpinet/src/main/native/windows/MulticastServiceAnnouncer.cpp +++ b/wpinet/src/main/native/windows/MulticastServiceAnnouncer.cpp @@ -8,7 +8,9 @@ #include "wpinet/MulticastServiceAnnouncer.h" +#include #include +#include #include #include diff --git a/wpinet/src/main/native/windows/MulticastServiceResolver.cpp b/wpinet/src/main/native/windows/MulticastServiceResolver.cpp index 79fc7b5ef71..c8a3d793e13 100644 --- a/wpinet/src/main/native/windows/MulticastServiceResolver.cpp +++ b/wpinet/src/main/native/windows/MulticastServiceResolver.cpp @@ -8,7 +8,9 @@ #include "wpinet/MulticastServiceResolver.h" +#include #include +#include #include #include diff --git a/wpinet/src/netconsoleServer/native/cpp/main.cpp b/wpinet/src/netconsoleServer/native/cpp/main.cpp index 4092e7d5f86..f65ada535a0 100644 --- a/wpinet/src/netconsoleServer/native/cpp/main.cpp +++ b/wpinet/src/netconsoleServer/native/cpp/main.cpp @@ -9,6 +9,8 @@ #endif #include +#include +#include #include #include diff --git a/wpinet/src/netconsoleTee/native/cpp/main.cpp b/wpinet/src/netconsoleTee/native/cpp/main.cpp index da1210d9b2a..bd3da809e9a 100644 --- a/wpinet/src/netconsoleTee/native/cpp/main.cpp +++ b/wpinet/src/netconsoleTee/native/cpp/main.cpp @@ -3,6 +3,8 @@ // the WPILib BSD license file in the root directory of this project. #include +#include +#include #include #include diff --git a/wpinet/src/test/native/cpp/HttpWebSocketServerConnectionTest.cpp b/wpinet/src/test/native/cpp/HttpWebSocketServerConnectionTest.cpp index 9c2d8749c9c..d6b10633b1f 100644 --- a/wpinet/src/test/native/cpp/HttpWebSocketServerConnectionTest.cpp +++ b/wpinet/src/test/native/cpp/HttpWebSocketServerConnectionTest.cpp @@ -4,6 +4,8 @@ #include "wpinet/HttpWebSocketServerConnection.h" // NOLINT(build/include_order) +#include + #include namespace wpi { diff --git a/wpinet/src/test/native/cpp/WebSocketClientTest.cpp b/wpinet/src/test/native/cpp/WebSocketClientTest.cpp index a603d9c05ab..c5bff34ff24 100644 --- a/wpinet/src/test/native/cpp/WebSocketClientTest.cpp +++ b/wpinet/src/test/native/cpp/WebSocketClientTest.cpp @@ -4,6 +4,11 @@ #include "wpinet/WebSocket.h" // NOLINT(build/include_order) +#include +#include +#include +#include + #include #include #include diff --git a/wpinet/src/test/native/cpp/WebSocketIntegrationTest.cpp b/wpinet/src/test/native/cpp/WebSocketIntegrationTest.cpp index 6b74d822d22..1105a23076e 100644 --- a/wpinet/src/test/native/cpp/WebSocketIntegrationTest.cpp +++ b/wpinet/src/test/native/cpp/WebSocketIntegrationTest.cpp @@ -4,10 +4,11 @@ #include "wpinet/WebSocketServer.h" // NOLINT(build/include_order) +#include + #include #include "WebSocketTest.h" -#include "wpinet/HttpParser.h" namespace wpi { diff --git a/wpinet/src/test/native/cpp/WebSocketSerializerTest.cpp b/wpinet/src/test/native/cpp/WebSocketSerializerTest.cpp index f1e2629331a..e82f8875511 100644 --- a/wpinet/src/test/native/cpp/WebSocketSerializerTest.cpp +++ b/wpinet/src/test/native/cpp/WebSocketSerializerTest.cpp @@ -6,8 +6,12 @@ #include #include +#include +#include #include #include +#include +#include #include #include diff --git a/wpinet/src/test/native/cpp/WebSocketServerTest.cpp b/wpinet/src/test/native/cpp/WebSocketServerTest.cpp index a051e553111..51b6f3d0808 100644 --- a/wpinet/src/test/native/cpp/WebSocketServerTest.cpp +++ b/wpinet/src/test/native/cpp/WebSocketServerTest.cpp @@ -4,13 +4,16 @@ #include "wpinet/WebSocket.h" // NOLINT(build/include_order) +#include +#include +#include + #include #include #include #include "WebSocketTest.h" #include "wpinet/HttpParser.h" -#include "wpinet/raw_uv_ostream.h" namespace wpi { diff --git a/wpinet/src/test/native/cpp/WebSocketTest.cpp b/wpinet/src/test/native/cpp/WebSocketTest.cpp index e5f03de2254..fad6b3660b2 100644 --- a/wpinet/src/test/native/cpp/WebSocketTest.cpp +++ b/wpinet/src/test/native/cpp/WebSocketTest.cpp @@ -6,6 +6,9 @@ #include "WebSocketTest.h" +#include +#include + #include #include "wpinet/HttpParser.h" diff --git a/wpinet/src/test/native/cpp/uv/UvAsyncFunctionTest.cpp b/wpinet/src/test/native/cpp/uv/UvAsyncFunctionTest.cpp index 4369dc0fc0f..0f488f8d046 100644 --- a/wpinet/src/test/native/cpp/uv/UvAsyncFunctionTest.cpp +++ b/wpinet/src/test/native/cpp/uv/UvAsyncFunctionTest.cpp @@ -4,7 +4,9 @@ #include "wpinet/uv/AsyncFunction.h" // NOLINT(build/include_order) +#include #include +#include #include diff --git a/wpinet/src/test/native/cpp/uv/UvAsyncTest.cpp b/wpinet/src/test/native/cpp/uv/UvAsyncTest.cpp index ed4324c0f11..bfecb7594c5 100644 --- a/wpinet/src/test/native/cpp/uv/UvAsyncTest.cpp +++ b/wpinet/src/test/native/cpp/uv/UvAsyncTest.cpp @@ -26,6 +26,7 @@ #include "wpinet/uv/Async.h" // NOLINT(build/include_order) #include +#include #include #include diff --git a/wpiutil/CMakeLists.txt b/wpiutil/CMakeLists.txt index 7ef5ceae6a6..0362b7880cc 100644 --- a/wpiutil/CMakeLists.txt +++ b/wpiutil/CMakeLists.txt @@ -121,6 +121,9 @@ file( src/main/native/thirdparty/mpack/src/*.cpp ) list(REMOVE_ITEM wpiutil_native_src ${wpiutil_jni_src}) +if(NOT WITH_PROTOBUF) + list(FILTER wpiutil_native_src EXCLUDE REGEX "/protobuf/") +endif() file(GLOB_RECURSE wpiutil_unix_src src/main/native/unix/*.cpp) file(GLOB_RECURSE wpiutil_linux_src src/main/native/linux/*.cpp) file(GLOB_RECURSE wpiutil_macos_src src/main/native/macOS/*.cpp) @@ -143,7 +146,12 @@ if(MSVC) target_compile_definitions(wpiutil PRIVATE -D_CRT_SECURE_NO_WARNINGS) endif() wpilib_target_warnings(wpiutil) -target_link_libraries(wpiutil protobuf::libprotobuf Threads::Threads ${CMAKE_DL_LIBS}) +if(WITH_PROTOBUF) + target_link_libraries(wpiutil protobuf::libprotobuf Threads::Threads ${CMAKE_DL_LIBS}) +else() + target_link_libraries(wpiutil Threads::Threads ${CMAKE_DL_LIBS}) + target_compile_definitions(wpiutil PUBLIC NO_PROTOBUF) +endif() if(ATOMIC) target_link_libraries(wpiutil ${ATOMIC}) @@ -186,6 +194,8 @@ endif() install( DIRECTORY src/main/native/include/ + src/main/native/thirdparty/argparse/include/ + src/main/native/thirdparty/concurrentqueue/include/ src/main/native/thirdparty/expected/include/ src/main/native/thirdparty/json/include/ src/main/native/thirdparty/llvm/include/ @@ -198,6 +208,8 @@ target_include_directories( wpiutil PUBLIC $ + $ + $ $ $ $ diff --git a/wpiutil/build.gradle b/wpiutil/build.gradle index 941fe2ead36..a5a1ab8295b 100644 --- a/wpiutil/build.gradle +++ b/wpiutil/build.gradle @@ -32,7 +32,7 @@ ext { include '*.cpp' } exportedHeaders { - srcDirs 'src/main/native/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/fmtlib/include' + srcDirs 'src/main/native/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/llvm/include' } } llvmCpp(CppSourceSet) { @@ -41,7 +41,7 @@ ext { include '**/*.cpp' } exportedHeaders { - srcDirs 'src/main/native/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/fmtlib/include' + srcDirs 'src/main/native/include', 'src/main/native/thirdparty/expected/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/llvm/include' } } mpackCpp(CppSourceSet) { @@ -180,6 +180,12 @@ nativeUtils.exportsConfigs { } cppHeadersZip { + from('src/main/native/thirdparty/argparse/include/') { + into '/' + } + from('src/main/native/thirdparty/concurrentqueue/include') { + into '/' + } from('src/main/native/thirdparty/expected/include') { into '/' } @@ -235,7 +241,7 @@ model { all { it.sources.each { it.exportedHeaders { - srcDirs 'src/main/native/include', 'src/main/native/thirdparty/expected/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/memory/include', 'src/main/native/thirdparty/mpack/include', 'src/main/native/thirdparty/protobuf/include' + srcDirs 'src/main/native/include', 'src/main/native/thirdparty/argparse/include/', 'src/main/native/thirdparty/concurrentqueue/include', 'src/main/native/thirdparty/expected/include', 'src/main/native/thirdparty/fmtlib/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/sigslot/include', 'src/main/native/thirdparty/json/include', 'src/main/native/thirdparty/memory/include', 'src/main/native/thirdparty/mpack/include', 'src/main/native/thirdparty/protobuf/include' } } } diff --git a/wpiutil/examples/printlog/printlog.cpp b/wpiutil/examples/printlog/printlog.cpp index f89be5f5482..a17d30b3852 100644 --- a/wpiutil/examples/printlog/printlog.cpp +++ b/wpiutil/examples/printlog/printlog.cpp @@ -3,6 +3,8 @@ // the WPILib BSD license file in the root directory of this project. #include +#include +#include #include #include @@ -18,12 +20,13 @@ int main(int argc, const char** argv) { wpi::print(stderr, "Usage: printlog \n"); return EXIT_FAILURE; } - std::error_code ec; - wpi::log::DataLogReader reader{wpi::MemoryBuffer::GetFile(argv[1], ec)}; - if (ec) { - wpi::print(stderr, "could not open file: {}\n", ec.message()); + auto fileBuffer = wpi::MemoryBuffer::GetFile(argv[1]); + if (!fileBuffer) { + wpi::print(stderr, "could not open file: {}\n", + fileBuffer.error().message()); return EXIT_FAILURE; } + wpi::log::DataLogReader reader{std::move(*fileBuffer)}; if (!reader) { wpi::print(stderr, "not a log file\n"); return EXIT_FAILURE; diff --git a/wpiutil/examples/writelog/writelog.cpp b/wpiutil/examples/writelog/writelog.cpp index 0d8283ca121..dd9f8fa33da 100644 --- a/wpiutil/examples/writelog/writelog.cpp +++ b/wpiutil/examples/writelog/writelog.cpp @@ -2,10 +2,10 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. -#include #include #include #include +#include #include #include "wpi/DataLogBackgroundWriter.h" diff --git a/wpiutil/src/main/java/edu/wpi/first/util/FileLogger.java b/wpiutil/src/main/java/edu/wpi/first/util/FileLogger.java new file mode 100644 index 00000000000..438861b53ee --- /dev/null +++ b/wpiutil/src/main/java/edu/wpi/first/util/FileLogger.java @@ -0,0 +1,32 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.first.util; + +import edu.wpi.first.util.datalog.DataLog; + +/** + * A class version of `tail -f`, otherwise known as `tail -f` at home. Watches a file and puts the + * data into a data log. Only works on Linux-based platforms. + */ +public class FileLogger implements AutoCloseable { + private final long m_impl; + + /** + * Construct a FileLogger. When the specified file is modified, appended data will be appended to + * the specified data log. + * + * @param file The path to the file. + * @param log A data log. + * @param key The log key to append data to. + */ + public FileLogger(String file, DataLog log, String key) { + m_impl = WPIUtilJNI.createFileLogger(file, log.getImpl(), key); + } + + @Override + public void close() { + WPIUtilJNI.freeFileLogger(m_impl); + } +} diff --git a/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java b/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java index bc04257091a..136e2c041d6 100644 --- a/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java +++ b/wpiutil/src/main/java/edu/wpi/first/util/WPIUtilJNI.java @@ -217,6 +217,24 @@ public static native boolean waitForObjectTimeout(int handle, double timeout) public static native int[] waitForObjectsTimeout(int[] handles, double timeout) throws InterruptedException; + /** + * Create a native FileLogger. When the specified file is modified, appended data will be appended + * to the specified data log. + * + * @param file path to the file + * @param log data log implementation handle + * @param key log key to append data to + * @return The FileLogger handle. + */ + public static native long createFileLogger(String file, long log, String key); + + /** + * Free a native FileLogger. This causes the FileLogger to stop appending data to the log. + * + * @param fileTail The FileLogger handle. + */ + public static native void freeFileLogger(long fileTail); + /** Utility class. */ protected WPIUtilJNI() {} } diff --git a/wpiutil/src/main/native/cpp/Base64.cpp b/wpiutil/src/main/native/cpp/Base64.cpp index bc1d3bae696..b70298d12d1 100644 --- a/wpiutil/src/main/native/cpp/Base64.cpp +++ b/wpiutil/src/main/native/cpp/Base64.cpp @@ -57,6 +57,9 @@ #include "wpi/Base64.h" +#include +#include + #include "wpi/SmallVector.h" #include "wpi/raw_ostream.h" diff --git a/wpiutil/src/main/native/cpp/DataLog.cpp b/wpiutil/src/main/native/cpp/DataLog.cpp index dd717cc6c0a..45c1844b11d 100644 --- a/wpiutil/src/main/native/cpp/DataLog.cpp +++ b/wpiutil/src/main/native/cpp/DataLog.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include "wpi/Endian.h" diff --git a/wpiutil/src/main/native/cpp/DataLogBackgroundWriter.cpp b/wpiutil/src/main/native/cpp/DataLogBackgroundWriter.cpp index ec01346ef03..b20d4b73908 100644 --- a/wpiutil/src/main/native/cpp/DataLogBackgroundWriter.cpp +++ b/wpiutil/src/main/native/cpp/DataLogBackgroundWriter.cpp @@ -18,6 +18,9 @@ #endif #include +#include +#include +#include #include diff --git a/wpiutil/src/main/native/cpp/DataLogReader.cpp b/wpiutil/src/main/native/cpp/DataLogReader.cpp index c2e1192e14a..17b2c9fa018 100644 --- a/wpiutil/src/main/native/cpp/DataLogReader.cpp +++ b/wpiutil/src/main/native/cpp/DataLogReader.cpp @@ -4,6 +4,8 @@ #include "wpi/DataLogReader.h" +#include + #include "wpi/DataLog.h" #include "wpi/Endian.h" #include "wpi/MathExtras.h" diff --git a/wpiutil/src/main/native/cpp/DataLogWriter.cpp b/wpiutil/src/main/native/cpp/DataLogWriter.cpp index c4e4a501d4b..371a2bf901b 100644 --- a/wpiutil/src/main/native/cpp/DataLogWriter.cpp +++ b/wpiutil/src/main/native/cpp/DataLogWriter.cpp @@ -4,6 +4,10 @@ #include "wpi/DataLogWriter.h" +#include +#include +#include + #include "wpi/raw_ostream.h" using namespace wpi::log; diff --git a/wpiutil/src/main/native/cpp/FileLogger.cpp b/wpiutil/src/main/native/cpp/FileLogger.cpp new file mode 100644 index 00000000000..6e1435673b4 --- /dev/null +++ b/wpiutil/src/main/native/cpp/FileLogger.cpp @@ -0,0 +1,105 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#include "wpi/FileLogger.h" + +#ifdef __linux__ +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "wpi/StringExtras.h" + +namespace wpi { +FileLogger::FileLogger(std::string_view file, + std::function callback) +#ifdef __linux__ + : m_fileHandle{open(file.data(), O_RDONLY)}, + m_inotifyHandle{inotify_init()}, + m_inotifyWatchHandle{ + inotify_add_watch(m_inotifyHandle, file.data(), IN_MODIFY)}, + m_thread{[=, this] { + char buf[4000]; + struct inotify_event ev; + int len = 0; + lseek(m_fileHandle, 0, SEEK_END); + while ((len = read(m_inotifyHandle, &ev, sizeof(ev))) > 0) { + int bufLen = 0; + if ((bufLen = read(m_fileHandle, buf, sizeof(buf)) > 0)) { + callback(std::string_view{buf, static_cast(bufLen)}); + } + } + }} +#endif +{ +} +FileLogger::FileLogger(std::string_view file, log::DataLog& log, + std::string_view key) + : FileLogger(file, LineBuffer([entry = log.Start(key, "string"), + &log](std::string_view line) { + log.AppendString(entry, line, 0); + })) {} +FileLogger::FileLogger(FileLogger&& other) +#ifdef __linux__ + : m_fileHandle{std::exchange(other.m_fileHandle, -1)}, + m_inotifyHandle{std::exchange(other.m_inotifyHandle, -1)}, + m_inotifyWatchHandle{std::exchange(other.m_inotifyWatchHandle, -1)}, + m_thread{std::move(other.m_thread)} +#endif +{ +} +FileLogger& FileLogger::operator=(FileLogger&& rhs) { +#ifdef __linux__ + std::swap(m_fileHandle, rhs.m_fileHandle); + std::swap(m_inotifyHandle, rhs.m_inotifyHandle); + std::swap(m_inotifyWatchHandle, rhs.m_inotifyWatchHandle); + m_thread = std::move(rhs.m_thread); +#endif + return *this; +} +FileLogger::~FileLogger() { +#ifdef __linux__ + if (m_inotifyWatchHandle != -1) { + inotify_rm_watch(m_inotifyHandle, m_inotifyWatchHandle); + } + if (m_inotifyHandle != -1) { + close(m_inotifyHandle); + } + if (m_fileHandle != -1) { + close(m_fileHandle); + } + if (m_thread.joinable()) { + m_thread.join(); + } +#endif +} +std::function FileLogger::LineBuffer( + std::function callback) { + return [callback, + buf = wpi::SmallVector{}](std::string_view data) mutable { + if (!wpi::contains(data, "\n")) { + buf.append(data.begin(), data.end()); + return; + } + std::string_view line; + std::string_view remainingData; + std::tie(line, remainingData) = wpi::split(data, "\n"); + buf.append(line.begin(), line.end()); + callback(std::string_view{buf.data(), buf.size()}); + + while (wpi::contains(remainingData, "\n")) { + std::tie(line, remainingData) = wpi::split(remainingData, "\n"); + callback(line); + } + buf.clear(); + buf.append(remainingData.begin(), remainingData.end()); + }; +} +} // namespace wpi diff --git a/wpiutil/src/main/native/cpp/MessagePack.cpp b/wpiutil/src/main/native/cpp/MessagePack.cpp index 60a2f013ce7..192476bfdc5 100644 --- a/wpiutil/src/main/native/cpp/MessagePack.cpp +++ b/wpiutil/src/main/native/cpp/MessagePack.cpp @@ -4,6 +4,8 @@ #include "wpi/MessagePack.h" +#include + using namespace mpack; mpack_error_t mpack::mpack_expect_str(mpack_reader_t* reader, std::string* out, diff --git a/wpiutil/src/main/native/cpp/SafeThread.cpp b/wpiutil/src/main/native/cpp/SafeThread.cpp index ba1eba3131e..aefbd231c29 100644 --- a/wpiutil/src/main/native/cpp/SafeThread.cpp +++ b/wpiutil/src/main/native/cpp/SafeThread.cpp @@ -5,6 +5,8 @@ #include "wpi/SafeThread.h" #include +#include +#include using namespace wpi; diff --git a/wpiutil/src/main/native/cpp/StackTraceWrap.cpp b/wpiutil/src/main/native/cpp/StackTraceWrap.cpp index 37a83f7ef04..4d52a593987 100644 --- a/wpiutil/src/main/native/cpp/StackTraceWrap.cpp +++ b/wpiutil/src/main/native/cpp/StackTraceWrap.cpp @@ -3,6 +3,7 @@ // the WPILib BSD license file in the root directory of this project. #include +#include #include "wpi/StackTrace.h" diff --git a/wpiutil/src/main/native/cpp/future.cpp b/wpiutil/src/main/native/cpp/future.cpp index 109eeb93ca3..df26872ce1a 100644 --- a/wpiutil/src/main/native/cpp/future.cpp +++ b/wpiutil/src/main/native/cpp/future.cpp @@ -4,6 +4,8 @@ #include "wpi/future.h" +#include + namespace wpi { namespace detail { diff --git a/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp b/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp index e98c13f8dfa..782266874d0 100644 --- a/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp +++ b/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include diff --git a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp index 54b6da26712..15b78958acd 100644 --- a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp +++ b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp @@ -7,6 +7,8 @@ #include #include "edu_wpi_first_util_WPIUtilJNI.h" +#include "wpi/DataLog.h" +#include "wpi/FileLogger.h" #include "wpi/RawFrame.h" #include "wpi/Synchronization.h" #include "wpi/jni_util.h" @@ -414,4 +416,41 @@ Java_edu_wpi_first_util_WPIUtilJNI_setRawFrameInfo f->pixelFormat = pixelFormat; } +/* + * Class: edu_wpi_first_util_WPIUtilJNI + * Method: createFileLogger + * Signature: (Ljava/lang/String;JLjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL +Java_edu_wpi_first_util_WPIUtilJNI_createFileLogger + (JNIEnv* env, jclass, jstring file, jlong log, jstring key) +{ + if (!file) { + wpi::ThrowNullPointerException(env, "file is null"); + return 0; + } + auto* f = reinterpret_cast(log); + if (!f) { + wpi::ThrowNullPointerException(env, "log is null"); + return 0; + } + if (!key) { + wpi::ThrowNullPointerException(env, "key is null"); + return 0; + } + return reinterpret_cast( + new wpi::FileLogger{JStringRef{env, file}, *f, JStringRef{env, key}}); +} + +/* + * Class: edu_wpi_first_util_WPIUtilJNI + * Method: freeFileLogger + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_edu_wpi_first_util_WPIUtilJNI_freeFileLogger + (JNIEnv* env, jclass, jlong fileTail) +{ + delete reinterpret_cast(fileTail); +} } // extern "C" diff --git a/wpiutil/src/main/native/cpp/protobuf/Protobuf.cpp b/wpiutil/src/main/native/cpp/protobuf/Protobuf.cpp index 4dd747098f3..4fc10b26a67 100644 --- a/wpiutil/src/main/native/cpp/protobuf/Protobuf.cpp +++ b/wpiutil/src/main/native/cpp/protobuf/Protobuf.cpp @@ -4,6 +4,9 @@ #include "wpi/protobuf/Protobuf.h" +#include +#include + #include #include #include diff --git a/wpiutil/src/main/native/cpp/protobuf/ProtobufMessageDatabase.cpp b/wpiutil/src/main/native/cpp/protobuf/ProtobufMessageDatabase.cpp index 7583f675f6c..17a22db809d 100644 --- a/wpiutil/src/main/native/cpp/protobuf/ProtobufMessageDatabase.cpp +++ b/wpiutil/src/main/native/cpp/protobuf/ProtobufMessageDatabase.cpp @@ -4,6 +4,9 @@ #include "wpi/protobuf/ProtobufMessageDatabase.h" +#include +#include + #include #include "wpi/ProtoHelper.h" diff --git a/wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp b/wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp index 7a1e0b0b10a..c2b6b8ede77 100644 --- a/wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp +++ b/wpiutil/src/main/native/cpp/sendable/SendableRegistry.cpp @@ -5,6 +5,8 @@ #include "wpi/sendable/SendableRegistry.h" #include +#include +#include #include diff --git a/wpiutil/src/main/native/cpp/sha1.cpp b/wpiutil/src/main/native/cpp/sha1.cpp index 98dc5433cb6..82041144922 100644 --- a/wpiutil/src/main/native/cpp/sha1.cpp +++ b/wpiutil/src/main/native/cpp/sha1.cpp @@ -19,6 +19,8 @@ #include "wpi/sha1.h" +#include + #include "wpi/SmallVector.h" #include "wpi/StringExtras.h" #include "wpi/raw_istream.h" diff --git a/wpiutil/src/main/native/cpp/string.cpp b/wpiutil/src/main/native/cpp/string.cpp index e7a7ea3597b..3c5d47067f5 100644 --- a/wpiutil/src/main/native/cpp/string.cpp +++ b/wpiutil/src/main/native/cpp/string.cpp @@ -2,6 +2,7 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include "string" #include "wpi/string.h" #include diff --git a/wpiutil/src/main/native/cpp/struct/DynamicStruct.cpp b/wpiutil/src/main/native/cpp/struct/DynamicStruct.cpp index 8d43f537444..b2e667b5ad3 100644 --- a/wpiutil/src/main/native/cpp/struct/DynamicStruct.cpp +++ b/wpiutil/src/main/native/cpp/struct/DynamicStruct.cpp @@ -5,6 +5,9 @@ #include "wpi/struct/DynamicStruct.h" #include +#include +#include +#include #include diff --git a/wpiutil/src/main/native/cpp/struct/SchemaParser.cpp b/wpiutil/src/main/native/cpp/struct/SchemaParser.cpp index 347019e9d30..ffce8e62e8a 100644 --- a/wpiutil/src/main/native/cpp/struct/SchemaParser.cpp +++ b/wpiutil/src/main/native/cpp/struct/SchemaParser.cpp @@ -4,6 +4,9 @@ #include "wpi/struct/SchemaParser.h" +#include +#include + #include #include "wpi/StringExtras.h" diff --git a/wpiutil/src/main/native/cpp/timestamp.cpp b/wpiutil/src/main/native/cpp/timestamp.cpp index 3f9e1f3e741..64725eb7fa3 100644 --- a/wpiutil/src/main/native/cpp/timestamp.cpp +++ b/wpiutil/src/main/native/cpp/timestamp.cpp @@ -6,6 +6,7 @@ #include #include +#include #ifdef __FRC_ROBORIO__ #include @@ -21,7 +22,8 @@ using namespace nRoboRIO_FPGANamespace; } // namespace fpga #include -#include "dlfcn.h" +#include "dlfcn.h" // NOLINT(build/include_subdir) + #endif #ifdef _WIN32 diff --git a/wpiutil/src/main/native/include/wpi/DataLog.h b/wpiutil/src/main/native/include/wpi/DataLog.h index 35f0859ec0f..1253b5bc13d 100644 --- a/wpiutil/src/main/native/include/wpi/DataLog.h +++ b/wpiutil/src/main/native/include/wpi/DataLog.h @@ -876,7 +876,7 @@ class StringLogEntry : public DataLogValueEntryImpl { * @param value Value to record * @param timestamp Time stamp (may be 0 to indicate now) */ - void Update(std::string value, int64_t timestamp = 0) { + void Update(std::string_view value, int64_t timestamp = 0) { std::scoped_lock lock{m_mutex}; if (m_lastValue != value) { m_lastValue = value; diff --git a/wpiutil/src/main/native/include/wpi/FileLogger.h b/wpiutil/src/main/native/include/wpi/FileLogger.h new file mode 100644 index 00000000000..72565ebc804 --- /dev/null +++ b/wpiutil/src/main/native/include/wpi/FileLogger.h @@ -0,0 +1,61 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#pragma once + +#include +#include +#include + +#include "wpi/DataLog.h" + +namespace wpi { +/** + * A class version of `tail -f`, otherwise known as `tail -f` at home. Watches + * a file and puts the data somewhere else. Only works on Linux-based platforms. + */ +class FileLogger { + public: + FileLogger() = default; + /** + * Construct a FileLogger. When the specified file is modified, the callback + * will be called with the appended changes. + * + * @param file The path to the file. + * @param callback A callback that accepts the appended file data. + */ + FileLogger(std::string_view file, + std::function callback); + + /** + * Construct a FileLogger. When the specified file is modified, appended data + * will be appended to the specified data log. + * + * @param file The path to the file. + * @param log A data log. + * @param key The log key to append data to. + */ + FileLogger(std::string_view file, log::DataLog& log, std::string_view key); + FileLogger(FileLogger&& other); + FileLogger& operator=(FileLogger&& rhs); + ~FileLogger(); + /** + * Creates a function that chunks incoming data into lines before calling the + * callback with the individual line. + * + * @param callback The callback that logs lines. + * @return The function. + */ + static std::function LineBuffer( + std::function callback); + + private: +#ifdef __linux__ + int m_fileHandle = -1; + int m_inotifyHandle = -1; + int m_inotifyWatchHandle = -1; + std::thread m_thread; +#endif +}; +} // namespace wpi diff --git a/wpiutil/src/main/native/include/wpi/RawFrame.h b/wpiutil/src/main/native/include/wpi/RawFrame.h index 2e925b1e0ba..420f8199792 100644 --- a/wpiutil/src/main/native/include/wpi/RawFrame.h +++ b/wpiutil/src/main/native/include/wpi/RawFrame.h @@ -17,7 +17,7 @@ #endif #ifdef WPI_RAWFRAME_JNI -#include "jni_util.h" +#include "wpi/jni_util.h" #endif // NOLINT diff --git a/wpiutil/src/main/native/include/wpi/mutex.h b/wpiutil/src/main/native/include/wpi/mutex.h index c29509a915b..4bb1377b75d 100644 --- a/wpiutil/src/main/native/include/wpi/mutex.h +++ b/wpiutil/src/main/native/include/wpi/mutex.h @@ -6,7 +6,7 @@ #include -#include "priority_mutex.h" +#include "wpi/priority_mutex.h" namespace wpi { diff --git a/wpiutil/src/main/native/include/wpi/print.h b/wpiutil/src/main/native/include/wpi/print.h index 36bc966f140..422e65dc639 100644 --- a/wpiutil/src/main/native/include/wpi/print.h +++ b/wpiutil/src/main/native/include/wpi/print.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include diff --git a/wpiutil/src/main/native/thirdparty/argparse/include/wpi/argparse.h b/wpiutil/src/main/native/thirdparty/argparse/include/wpi/argparse.h new file mode 100644 index 00000000000..7ce9081150d --- /dev/null +++ b/wpiutil/src/main/native/thirdparty/argparse/include/wpi/argparse.h @@ -0,0 +1,2543 @@ +/* + __ _ _ __ __ _ _ __ __ _ _ __ ___ ___ + / _` | '__/ _` | '_ \ / _` | '__/ __|/ _ \ Argument Parser for Modern C++ +| (_| | | | (_| | |_) | (_| | | \__ \ __/ http://github.com/p-ranav/argparse + \__,_|_| \__, | .__/ \__,_|_| |___/\___| + |___/|_| + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2019-2022 Pranav Srinivas Kumar +and other contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ +#pragma once + +#include + +#ifndef WPI_MODULE_USE_STD_MODULE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#ifndef WPI_CUSTOM_STRTOF +#define WPI_CUSTOM_STRTOF strtof +#endif + +#ifndef WPI_CUSTOM_STRTOD +#define WPI_CUSTOM_STRTOD strtod +#endif + +#ifndef WPI_CUSTOM_STRTOLD +#define WPI_CUSTOM_STRTOLD strtold +#endif + +namespace wpi { + +namespace details { // namespace for helper methods + +template +struct HasContainerTraits : std::false_type {}; + +template <> struct HasContainerTraits : std::false_type {}; + +template <> struct HasContainerTraits : std::false_type {}; + +template +struct HasContainerTraits< + T, std::void_t().begin()), + decltype(std::declval().end()), + decltype(std::declval().size())>> : std::true_type {}; + +template +inline constexpr bool IsContainer = HasContainerTraits::value; + +template +struct HasStreamableTraits : std::false_type {}; + +template +struct HasStreamableTraits< + T, + std::void_t() << std::declval())>> + : std::true_type {}; + +template +inline constexpr bool IsStreamable = HasStreamableTraits::value; + +constexpr std::size_t repr_max_container_size = 5; + +template std::string repr(T const &val) { + if constexpr (std::is_same_v) { + return val ? "true" : "false"; + } else if constexpr (std::is_convertible_v) { + return '"' + std::string{std::string_view{val}} + '"'; + } else if constexpr (IsContainer) { + std::stringstream out; + out << "{"; + const auto size = val.size(); + if (size > 1) { + out << repr(*val.begin()); + std::for_each( + std::next(val.begin()), + std::next( + val.begin(), + static_cast( + std::min(size, repr_max_container_size) - 1)), + [&out](const auto &v) { out << " " << repr(v); }); + if (size <= repr_max_container_size) { + out << " "; + } else { + out << "..."; + } + } + if (size > 0) { + out << repr(*std::prev(val.end())); + } + out << "}"; + return out.str(); + } else if constexpr (IsStreamable) { + std::stringstream out; + out << val; + return out.str(); + } else { + return ""; + } +} + +namespace { + +template constexpr bool standard_signed_integer = false; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; + +template constexpr bool standard_unsigned_integer = false; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> +constexpr bool standard_unsigned_integer = true; + +} // namespace + +constexpr int radix_2 = 2; +constexpr int radix_8 = 8; +constexpr int radix_10 = 10; +constexpr int radix_16 = 16; + +template +constexpr bool standard_integer = + standard_signed_integer || standard_unsigned_integer; + +template +constexpr decltype(auto) +apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, + std::index_sequence /*unused*/) { + return std::invoke(std::forward(f), std::get(std::forward(t))..., + std::forward(x)); +} + +template +constexpr decltype(auto) apply_plus_one(F &&f, Tuple &&t, Extra &&x) { + return details::apply_plus_one_impl( + std::forward(f), std::forward(t), std::forward(x), + std::make_index_sequence< + std::tuple_size_v>>{}); +} + +constexpr auto pointer_range(std::string_view s) noexcept { + return std::tuple(s.data(), s.data() + s.size()); +} + +template +constexpr bool starts_with(std::basic_string_view prefix, + std::basic_string_view s) noexcept { + return s.substr(0, prefix.size()) == prefix; +} + +enum class chars_format { + scientific = 0xf1, + fixed = 0xf2, + hex = 0xf4, + binary = 0xf8, + general = fixed | scientific +}; + +struct ConsumeBinaryPrefixResult { + bool is_binary; + std::string_view rest; +}; + +constexpr auto consume_binary_prefix(std::string_view s) + -> ConsumeBinaryPrefixResult { + if (starts_with(std::string_view{"0b"}, s) || + starts_with(std::string_view{"0B"}, s)) { + s.remove_prefix(2); + return {true, s}; + } + return {false, s}; +} + +struct ConsumeHexPrefixResult { + bool is_hexadecimal; + std::string_view rest; +}; + +using namespace std::literals; + +constexpr auto consume_hex_prefix(std::string_view s) + -> ConsumeHexPrefixResult { + if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { + s.remove_prefix(2); + return {true, s}; + } + return {false, s}; +} + +template +inline auto do_from_chars(std::string_view s) -> T { + T x{0}; + auto [first, last] = pointer_range(s); + auto [ptr, ec] = std::from_chars(first, last, x, Param); + if (ec == std::errc()) { + if (ptr == last) { + return x; + } + throw std::invalid_argument{"pattern '" + std::string(s) + + "' does not match to the end"}; + } + if (ec == std::errc::invalid_argument) { + throw std::invalid_argument{"pattern '" + std::string(s) + "' not found"}; + } + if (ec == std::errc::result_out_of_range) { + throw std::range_error{"'" + std::string(s) + "' not representable"}; + } + return x; // unreachable +} + +template struct parse_number { + auto operator()(std::string_view s) -> T { + return do_from_chars(s); + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + if (auto [ok, rest] = consume_binary_prefix(s); ok) { + return do_from_chars(rest); + } + throw std::invalid_argument{"pattern not found"}; + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { + if (auto [ok, rest] = consume_hex_prefix(s); ok) { + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } + } + } else { + // Allow passing hex numbers without prefix + // Shape 'x' already has to be specified + try { + return do_from_chars(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } + } + + throw std::invalid_argument{"pattern '" + std::string(s) + + "' not identified as hexadecimal"}; + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + auto [ok, rest] = consume_hex_prefix(s); + if (ok) { + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } + } + + auto [ok_binary, rest_binary] = consume_binary_prefix(s); + if (ok_binary) { + try { + return do_from_chars(rest_binary); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as binary: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as binary: " + err.what()); + } + } + + if (starts_with("0"sv, s)) { + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as octal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as octal: " + err.what()); + } + } + + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as decimal integer: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as decimal integer: " + err.what()); + } + } +}; + +namespace { + +template inline const auto generic_strtod = nullptr; +template <> inline const auto generic_strtod = WPI_CUSTOM_STRTOF; +template <> inline const auto generic_strtod = WPI_CUSTOM_STRTOD; +template <> +inline const auto generic_strtod = WPI_CUSTOM_STRTOLD; + +} // namespace + +template inline auto do_strtod(std::string const &s) -> T { + if (isspace(static_cast(s[0])) || s[0] == '+') { + throw std::invalid_argument{"pattern '" + s + "' not found"}; + } + + auto [first, last] = pointer_range(s); + char *ptr; + + errno = 0; + auto x = generic_strtod(first, &ptr); + if (errno == 0) { + if (ptr == last) { + return x; + } + throw std::invalid_argument{"pattern '" + s + + "' does not match to the end"}; + } + if (errno == ERANGE) { + throw std::range_error{"'" + s + "' not representable"}; + } + return x; // unreachable +} + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::general does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{ + "chars_format::general does not parse binfloat"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as number: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as number: " + err.what()); + } + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); !r.is_hexadecimal) { + throw std::invalid_argument{"chars_format::hex parses hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{"chars_format::hex does not parse binfloat"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as hexadecimal: " + err.what()); + } + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::binary does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); !r.is_binary) { + throw std::invalid_argument{"chars_format::binary parses binfloat"}; + } + + return do_strtod(s); + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::scientific does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{ + "chars_format::scientific does not parse binfloat"}; + } + if (s.find_first_of("eE") == std::string::npos) { + throw std::invalid_argument{ + "chars_format::scientific requires exponent part"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as scientific notation: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as scientific notation: " + err.what()); + } + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::fixed does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{ + "chars_format::fixed does not parse binfloat"}; + } + if (s.find_first_of("eE") != std::string::npos) { + throw std::invalid_argument{ + "chars_format::fixed does not parse exponent part"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as fixed notation: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as fixed notation: " + err.what()); + } + } +}; + +template +std::string join(StrIt first, StrIt last, const std::string &separator) { + if (first == last) { + return ""; + } + std::stringstream value; + value << *first; + ++first; + while (first != last) { + value << separator << *first; + ++first; + } + return value.str(); +} + +template struct can_invoke_to_string { + template + static auto test(int) + -> decltype(std::to_string(std::declval()), std::true_type{}); + + template static auto test(...) -> std::false_type; + + static constexpr bool value = decltype(test(0))::value; +}; + +template struct IsChoiceTypeSupported { + using CleanType = typename std::decay::type; + static const bool value = std::is_integral::value || + std::is_same::value || + std::is_same::value || + std::is_same::value; +}; + +template +std::size_t get_levenshtein_distance(const StringType &s1, + const StringType &s2) { + std::vector> dp( + s1.size() + 1, std::vector(s2.size() + 1, 0)); + + for (std::size_t i = 0; i <= s1.size(); ++i) { + for (std::size_t j = 0; j <= s2.size(); ++j) { + if (i == 0) { + dp[i][j] = j; + } else if (j == 0) { + dp[i][j] = i; + } else if (s1[i - 1] == s2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = 1 + std::min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}); + } + } + } + + return dp[s1.size()][s2.size()]; +} + +template +std::string get_most_similar_string(const std::map &map, + const std::string &input) { + std::string most_similar{}; + std::size_t min_distance = (std::numeric_limits::max)(); + + for (const auto &entry : map) { + std::size_t distance = get_levenshtein_distance(entry.first, input); + if (distance < min_distance) { + min_distance = distance; + most_similar = entry.first; + } + } + + return most_similar; +} + +} // namespace details + +enum class nargs_pattern { optional, any, at_least_one }; + +enum class default_arguments : unsigned int { + none = 0, + help = 1, + version = 2, + all = help | version, +}; + +inline default_arguments operator&(const default_arguments &a, + const default_arguments &b) { + return static_cast( + static_cast::type>(a) & + static_cast::type>(b)); +} + +class ArgumentParser; + +class Argument { + friend class ArgumentParser; + friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) + -> std::ostream &; + + template + explicit Argument(std::string_view prefix_chars, + std::array &&a, + std::index_sequence /*unused*/) + : m_accepts_optional_like_value(false), + m_is_optional((is_optional(a[I], prefix_chars) || ...)), + m_is_required(false), m_is_repeatable(false), m_is_used(false), + m_is_hidden(false), m_prefix_chars(prefix_chars) { + ((void)m_names.emplace_back(a[I]), ...); + std::sort( + m_names.begin(), m_names.end(), [](const auto &lhs, const auto &rhs) { + return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); + }); + } + +public: + template + explicit Argument(std::string_view prefix_chars, + std::array &&a) + : Argument(prefix_chars, std::move(a), std::make_index_sequence{}) {} + + Argument &help(std::string help_text) { + m_help = std::move(help_text); + return *this; + } + + Argument &metavar(std::string metavar) { + m_metavar = std::move(metavar); + return *this; + } + + template Argument &default_value(T &&value) { + m_num_args_range = NArgsRange{0, m_num_args_range.get_max()}; + m_default_value_repr = details::repr(value); + + if constexpr (std::is_convertible_v) { + m_default_value_str = std::string{std::string_view{value}}; + } else if constexpr (details::can_invoke_to_string::value) { + m_default_value_str = std::to_string(value); + } + + m_default_value = std::forward(value); + return *this; + } + + Argument &default_value(const char *value) { + return default_value(std::string(value)); + } + + Argument &required() { + m_is_required = true; + return *this; + } + + Argument &implicit_value(std::any value) { + m_implicit_value = std::move(value); + m_num_args_range = NArgsRange{0, 0}; + return *this; + } + + // This is shorthand for: + // program.add_argument("foo") + // .default_value(false) + // .implicit_value(true) + Argument &flag() { + default_value(false); + implicit_value(true); + return *this; + } + + template + auto action(F &&callable, Args &&... bound_args) + -> std::enable_if_t, + Argument &> { + using action_type = std::conditional_t< + std::is_void_v>, + void_action, valued_action>; + if constexpr (sizeof...(Args) == 0) { + m_action.emplace(std::forward(callable)); + } else { + m_action.emplace( + [f = std::forward(callable), + tup = std::make_tuple(std::forward(bound_args)...)]( + std::string const &opt) mutable { + return details::apply_plus_one(f, tup, opt); + }); + } + return *this; + } + + auto &store_into(bool &var) { + flag(); + if (m_default_value.has_value()) { + var = std::any_cast(m_default_value); + } + action([&var](const auto & /*unused*/) { var = true; }); + return *this; + } + + template ::value>::type * = nullptr> + auto &store_into(T &var) { + if (m_default_value.has_value()) { + var = std::any_cast(m_default_value); + } + action([&var](const auto &s) { + var = details::parse_number()(s); + }); + return *this; + } + + auto &store_into(double &var) { + if (m_default_value.has_value()) { + var = std::any_cast(m_default_value); + } + action([&var](const auto &s) { + var = details::parse_number()(s); + }); + return *this; + } + + auto &store_into(std::string &var) { + if (m_default_value.has_value()) { + var = std::any_cast(m_default_value); + } + action([&var](const std::string &s) { var = s; }); + return *this; + } + + auto &store_into(std::vector &var) { + if (m_default_value.has_value()) { + var = std::any_cast>(m_default_value); + } + action([this, &var](const std::string &s) { + if (!m_is_used) { + var.clear(); + } + m_is_used = true; + var.push_back(s); + }); + return *this; + } + + auto &store_into(std::vector &var) { + if (m_default_value.has_value()) { + var = std::any_cast>(m_default_value); + } + action([this, &var](const std::string &s) { + if (!m_is_used) { + var.clear(); + } + m_is_used = true; + var.push_back(details::parse_number()(s)); + }); + return *this; + } + + auto &store_into(std::set &var) { + if (m_default_value.has_value()) { + var = std::any_cast>(m_default_value); + } + action([this, &var](const std::string &s) { + if (!m_is_used) { + var.clear(); + } + m_is_used = true; + var.insert(s); + }); + return *this; + } + + auto &store_into(std::set &var) { + if (m_default_value.has_value()) { + var = std::any_cast>(m_default_value); + } + action([this, &var](const std::string &s) { + if (!m_is_used) { + var.clear(); + } + m_is_used = true; + var.insert(details::parse_number()(s)); + }); + return *this; + } + + auto &append() { + m_is_repeatable = true; + return *this; + } + + // Cause the argument to be invisible in usage and help + auto &hidden() { + m_is_hidden = true; + return *this; + } + + template + auto scan() -> std::enable_if_t, Argument &> { + static_assert(!(std::is_const_v || std::is_volatile_v), + "T should not be cv-qualified"); + auto is_one_of = [](char c, auto... x) constexpr { + return ((c == x) || ...); + }; + + if constexpr (is_one_of(Shape, 'd') && details::standard_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'i') && + details::standard_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'u') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'b') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'o') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'x', 'X') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'a', 'A') && + std::is_floating_point_v) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'e', 'E') && + std::is_floating_point_v) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'f', 'F') && + std::is_floating_point_v) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'g', 'G') && + std::is_floating_point_v) { + action(details::parse_number()); + } else { + static_assert(alignof(T) == 0, "No scan specification for T"); + } + + return *this; + } + + Argument &nargs(std::size_t num_args) { + m_num_args_range = NArgsRange{num_args, num_args}; + return *this; + } + + Argument &nargs(std::size_t num_args_min, std::size_t num_args_max) { + m_num_args_range = NArgsRange{num_args_min, num_args_max}; + return *this; + } + + Argument &nargs(nargs_pattern pattern) { + switch (pattern) { + case nargs_pattern::optional: + m_num_args_range = NArgsRange{0, 1}; + break; + case nargs_pattern::any: + m_num_args_range = + NArgsRange{0, (std::numeric_limits::max)()}; + break; + case nargs_pattern::at_least_one: + m_num_args_range = + NArgsRange{1, (std::numeric_limits::max)()}; + break; + } + return *this; + } + + Argument &remaining() { + m_accepts_optional_like_value = true; + return nargs(nargs_pattern::any); + } + + template void add_choice(T &&choice) { + static_assert(details::IsChoiceTypeSupported::value, + "Only string or integer type supported for choice"); + static_assert(std::is_convertible_v || + details::can_invoke_to_string::value, + "Choice is not convertible to string_type"); + if (!m_choices.has_value()) { + m_choices = std::vector{}; + } + + if constexpr (std::is_convertible_v) { + m_choices.value().push_back( + std::string{std::string_view{std::forward(choice)}}); + } else if constexpr (details::can_invoke_to_string::value) { + m_choices.value().push_back(std::to_string(std::forward(choice))); + } + } + + Argument &choices() { + if (!m_choices.has_value()) { + throw std::runtime_error("Zero choices provided"); + } + return *this; + } + + template + Argument &choices(T &&first, U &&... rest) { + add_choice(std::forward(first)); + choices(std::forward(rest)...); + return *this; + } + + void find_default_value_in_choices_or_throw() const { + + const auto &choices = m_choices.value(); + + if (m_default_value.has_value()) { + if (std::find(choices.begin(), choices.end(), m_default_value_str) == + choices.end()) { + // provided arg not in list of allowed choices + // report error + + std::string choices_as_csv = + std::accumulate(choices.begin(), choices.end(), std::string(), + [](const std::string &a, const std::string &b) { + return a + (a.empty() ? "" : ", ") + b; + }); + + throw std::runtime_error( + std::string{"Invalid default value "} + m_default_value_repr + + " - allowed options: {" + choices_as_csv + "}"); + } + } + } + + template + void find_value_in_choices_or_throw(Iterator it) const { + + const auto &choices = m_choices.value(); + + if (std::find(choices.begin(), choices.end(), *it) == choices.end()) { + // provided arg not in list of allowed choices + // report error + + std::string choices_as_csv = + std::accumulate(choices.begin(), choices.end(), std::string(), + [](const std::string &a, const std::string &b) { + return a + (a.empty() ? "" : ", ") + b; + }); + + throw std::runtime_error(std::string{"Invalid argument "} + + details::repr(*it) + " - allowed options: {" + + choices_as_csv + "}"); + } + } + + /* The dry_run parameter can be set to true to avoid running the actions, + * and setting m_is_used. This may be used by a pre-processing step to do + * a first iteration over arguments. + */ + template + Iterator consume(Iterator start, Iterator end, + std::string_view used_name = {}, bool dry_run = false) { + if (!m_is_repeatable && m_is_used) { + throw std::runtime_error( + std::string("Duplicate argument ").append(used_name)); + } + m_used_name = used_name; + + if (m_choices.has_value()) { + // Check each value in (start, end) and make sure + // it is in the list of allowed choices/options + std::size_t i = 0; + auto max_number_of_args = m_num_args_range.get_max(); + for (auto it = start; it != end; ++it) { + if (i == max_number_of_args) { + break; + } + find_value_in_choices_or_throw(it); + i += 1; + } + } + + const auto num_args_max = m_num_args_range.get_max(); + const auto num_args_min = m_num_args_range.get_min(); + std::size_t dist = 0; + if (num_args_max == 0) { + if (!dry_run) { + m_values.emplace_back(m_implicit_value); + std::visit([](const auto &f) { f({}); }, m_action); + m_is_used = true; + } + return start; + } + if ((dist = static_cast(std::distance(start, end))) >= + num_args_min) { + if (num_args_max < dist) { + end = std::next(start, static_cast( + num_args_max)); + } + if (!m_accepts_optional_like_value) { + end = std::find_if( + start, end, + std::bind(is_optional, std::placeholders::_1, m_prefix_chars)); + dist = static_cast(std::distance(start, end)); + if (dist < num_args_min) { + throw std::runtime_error("Too few arguments for '" + + std::string(m_used_name) + "'."); + } + } + + struct ActionApply { + void operator()(valued_action &f) { + std::transform(first, last, std::back_inserter(self.m_values), f); + } + + void operator()(void_action &f) { + std::for_each(first, last, f); + if (!self.m_default_value.has_value()) { + if (!self.m_accepts_optional_like_value) { + self.m_values.resize( + static_cast(std::distance(first, last))); + } + } + } + + Iterator first, last; + Argument &self; + }; + if (!dry_run) { + std::visit(ActionApply{start, end, *this}, m_action); + m_is_used = true; + } + return end; + } + if (m_default_value.has_value()) { + if (!dry_run) { + m_is_used = true; + } + return start; + } + throw std::runtime_error("Too few arguments for '" + + std::string(m_used_name) + "'."); + } + + /* + * @throws std::runtime_error if argument values are not valid + */ + void validate() const { + if (m_is_optional) { + // TODO: check if an implicit value was programmed for this argument + if (!m_is_used && !m_default_value.has_value() && m_is_required) { + throw_required_arg_not_used_error(); + } + if (m_is_used && m_is_required && m_values.empty()) { + throw_required_arg_no_value_provided_error(); + } + } else { + if (!m_num_args_range.contains(m_values.size()) && + !m_default_value.has_value()) { + throw_nargs_range_validation_error(); + } + } + + if (m_choices.has_value()) { + // Make sure the default value (if provided) + // is in the list of choices + find_default_value_in_choices_or_throw(); + } + } + + std::string get_names_csv(char separator = ',') const { + return std::accumulate( + m_names.begin(), m_names.end(), std::string{""}, + [&](const std::string &result, const std::string &name) { + return result.empty() ? name : result + separator + name; + }); + } + + std::string get_usage_full() const { + std::stringstream usage; + + usage << get_names_csv('/'); + const std::string metavar = !m_metavar.empty() ? m_metavar : "VAR"; + if (m_num_args_range.get_max() > 0) { + usage << " " << metavar; + if (m_num_args_range.get_max() > 1) { + usage << "..."; + } + } + return usage.str(); + } + + std::string get_inline_usage() const { + std::stringstream usage; + // Find the longest variant to show in the usage string + std::string longest_name = m_names.front(); + for (const auto &s : m_names) { + if (s.size() > longest_name.size()) { + longest_name = s; + } + } + if (!m_is_required) { + usage << "["; + } + usage << longest_name; + const std::string metavar = !m_metavar.empty() ? m_metavar : "VAR"; + if (m_num_args_range.get_max() > 0) { + usage << " " << metavar; + if (m_num_args_range.get_max() > 1 && + m_metavar.find("> <") == std::string::npos) { + usage << "..."; + } + } + if (!m_is_required) { + usage << "]"; + } + if (m_is_repeatable) { + usage << "..."; + } + return usage.str(); + } + + std::size_t get_arguments_length() const { + + std::size_t names_size = std::accumulate( + std::begin(m_names), std::end(m_names), std::size_t(0), + [](const auto &sum, const auto &s) { return sum + s.size(); }); + + if (is_positional(m_names.front(), m_prefix_chars)) { + // A set metavar means this replaces the names + if (!m_metavar.empty()) { + // Indent and metavar + return 2 + m_metavar.size(); + } + + // Indent and space-separated + return 2 + names_size + (m_names.size() - 1); + } + // Is an option - include both names _and_ metavar + // size = text + (", " between names) + std::size_t size = names_size + 2 * (m_names.size() - 1); + if (!m_metavar.empty() && m_num_args_range == NArgsRange{1, 1}) { + size += m_metavar.size() + 1; + } + return size + 2; // indent + } + + friend std::ostream &operator<<(std::ostream &stream, + const Argument &argument) { + std::stringstream name_stream; + name_stream << " "; // indent + if (argument.is_positional(argument.m_names.front(), + argument.m_prefix_chars)) { + if (!argument.m_metavar.empty()) { + name_stream << argument.m_metavar; + } else { + name_stream << details::join(argument.m_names.begin(), + argument.m_names.end(), " "); + } + } else { + name_stream << details::join(argument.m_names.begin(), + argument.m_names.end(), ", "); + // If we have a metavar, and one narg - print the metavar + if (!argument.m_metavar.empty() && + argument.m_num_args_range == NArgsRange{1, 1}) { + name_stream << " " << argument.m_metavar; + } + else if (!argument.m_metavar.empty() && + argument.m_num_args_range.get_min() == argument.m_num_args_range.get_max() && + argument.m_metavar.find("> <") != std::string::npos) { + name_stream << " " << argument.m_metavar; + } + } + + // align multiline help message + auto stream_width = stream.width(); + auto name_padding = std::string(name_stream.str().size(), ' '); + auto pos = std::string::size_type{}; + auto prev = std::string::size_type{}; + auto first_line = true; + auto hspace = " "; // minimal space between name and help message + stream << name_stream.str(); + std::string_view help_view(argument.m_help); + while ((pos = argument.m_help.find('\n', prev)) != std::string::npos) { + auto line = help_view.substr(prev, pos - prev + 1); + if (first_line) { + stream << hspace << line; + first_line = false; + } else { + stream.width(stream_width); + stream << name_padding << hspace << line; + } + prev += pos - prev + 1; + } + if (first_line) { + stream << hspace << argument.m_help; + } else { + auto leftover = help_view.substr(prev, argument.m_help.size() - prev); + if (!leftover.empty()) { + stream.width(stream_width); + stream << name_padding << hspace << leftover; + } + } + + // print nargs spec + if (!argument.m_help.empty()) { + stream << " "; + } + stream << argument.m_num_args_range; + + bool add_space = false; + if (argument.m_default_value.has_value() && + argument.m_num_args_range != NArgsRange{0, 0}) { + stream << "[default: " << argument.m_default_value_repr << "]"; + add_space = true; + } else if (argument.m_is_required) { + stream << "[required]"; + add_space = true; + } + if (argument.m_is_repeatable) { + if (add_space) { + stream << " "; + } + stream << "[may be repeated]"; + } + stream << "\n"; + return stream; + } + + template bool operator!=(const T &rhs) const { + return !(*this == rhs); + } + + /* + * Compare to an argument value of known type + * @throws std::logic_error in case of incompatible types + */ + template bool operator==(const T &rhs) const { + if constexpr (!details::IsContainer) { + return get() == rhs; + } else { + using ValueType = typename T::value_type; + auto lhs = get(); + return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), + std::end(rhs), [](const auto &a, const auto &b) { + return std::any_cast(a) == b; + }); + } + } + + /* + * positional: + * _empty_ + * '-' + * '-' decimal-literal + * !'-' anything + */ + static bool is_positional(std::string_view name, + std::string_view prefix_chars) { + auto first = lookahead(name); + + if (first == eof) { + return true; + } + if (prefix_chars.find(static_cast(first)) != + std::string_view::npos) { + name.remove_prefix(1); + if (name.empty()) { + return true; + } + return is_decimal_literal(name); + } + return true; + } + +private: + class NArgsRange { + std::size_t m_min; + std::size_t m_max; + + public: + NArgsRange(std::size_t minimum, std::size_t maximum) + : m_min(minimum), m_max(maximum) { + if (minimum > maximum) { + throw std::logic_error("Range of number of arguments is invalid"); + } + } + + bool contains(std::size_t value) const { + return value >= m_min && value <= m_max; + } + + bool is_exact() const { return m_min == m_max; } + + bool is_right_bounded() const { + return m_max < (std::numeric_limits::max)(); + } + + std::size_t get_min() const { return m_min; } + + std::size_t get_max() const { return m_max; } + + // Print help message + friend auto operator<<(std::ostream &stream, const NArgsRange &range) + -> std::ostream & { + if (range.m_min == range.m_max) { + if (range.m_min != 0 && range.m_min != 1) { + stream << "[nargs: " << range.m_min << "] "; + } + } else { + if (range.m_max == (std::numeric_limits::max)()) { + stream << "[nargs: " << range.m_min << " or more] "; + } else { + stream << "[nargs=" << range.m_min << ".." << range.m_max << "] "; + } + } + return stream; + } + + bool operator==(const NArgsRange &rhs) const { + return rhs.m_min == m_min && rhs.m_max == m_max; + } + + bool operator!=(const NArgsRange &rhs) const { return !(*this == rhs); } + }; + + void throw_nargs_range_validation_error() const { + std::stringstream stream; + if (!m_used_name.empty()) { + stream << m_used_name << ": "; + } else { + stream << m_names.front() << ": "; + } + if (m_num_args_range.is_exact()) { + stream << m_num_args_range.get_min(); + } else if (m_num_args_range.is_right_bounded()) { + stream << m_num_args_range.get_min() << " to " + << m_num_args_range.get_max(); + } else { + stream << m_num_args_range.get_min() << " or more"; + } + stream << " argument(s) expected. " << m_values.size() << " provided."; + throw std::runtime_error(stream.str()); + } + + void throw_required_arg_not_used_error() const { + std::stringstream stream; + stream << m_names.front() << ": required."; + throw std::runtime_error(stream.str()); + } + + void throw_required_arg_no_value_provided_error() const { + std::stringstream stream; + stream << m_used_name << ": no value provided."; + throw std::runtime_error(stream.str()); + } + + static constexpr int eof = std::char_traits::eof(); + + static auto lookahead(std::string_view s) -> int { + if (s.empty()) { + return eof; + } + return static_cast(static_cast(s[0])); + } + + /* + * decimal-literal: + * '0' + * nonzero-digit digit-sequence_opt + * integer-part fractional-part + * fractional-part + * integer-part '.' exponent-part_opt + * integer-part exponent-part + * + * integer-part: + * digit-sequence + * + * fractional-part: + * '.' post-decimal-point + * + * post-decimal-point: + * digit-sequence exponent-part_opt + * + * exponent-part: + * 'e' post-e + * 'E' post-e + * + * post-e: + * sign_opt digit-sequence + * + * sign: one of + * '+' '-' + */ + static bool is_decimal_literal(std::string_view s) { + auto is_digit = [](auto c) constexpr { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return true; + default: + return false; + } + }; + + // precondition: we have consumed or will consume at least one digit + auto consume_digits = [=](std::string_view sd) { + // NOLINTNEXTLINE(readability-qualified-auto) + auto it = std::find_if_not(std::begin(sd), std::end(sd), is_digit); + return sd.substr(static_cast(it - std::begin(sd))); + }; + + switch (lookahead(s)) { + case '0': { + s.remove_prefix(1); + if (s.empty()) { + return true; + } + goto integer_part; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + s = consume_digits(s); + if (s.empty()) { + return true; + } + goto integer_part_consumed; + } + case '.': { + s.remove_prefix(1); + goto post_decimal_point; + } + default: + return false; + } + + integer_part: + s = consume_digits(s); + integer_part_consumed: + switch (lookahead(s)) { + case '.': { + s.remove_prefix(1); + if (is_digit(lookahead(s))) { + goto post_decimal_point; + } else { + goto exponent_part_opt; + } + } + case 'e': + case 'E': { + s.remove_prefix(1); + goto post_e; + } + default: + return false; + } + + post_decimal_point: + if (is_digit(lookahead(s))) { + s = consume_digits(s); + goto exponent_part_opt; + } + return false; + + exponent_part_opt: + switch (lookahead(s)) { + case eof: + return true; + case 'e': + case 'E': { + s.remove_prefix(1); + goto post_e; + } + default: + return false; + } + + post_e: + switch (lookahead(s)) { + case '-': + case '+': + s.remove_prefix(1); + } + if (is_digit(lookahead(s))) { + s = consume_digits(s); + return s.empty(); + } + return false; + } + + static bool is_optional(std::string_view name, + std::string_view prefix_chars) { + return !is_positional(name, prefix_chars); + } + + /* + * Get argument value given a type + * @throws std::logic_error in case of incompatible types + */ + template T get() const { + if (!m_values.empty()) { + if constexpr (details::IsContainer) { + return any_cast_container(m_values); + } else { + return std::any_cast(m_values.front()); + } + } + if (m_default_value.has_value()) { + return std::any_cast(m_default_value); + } + if constexpr (details::IsContainer) { + if (!m_accepts_optional_like_value) { + return any_cast_container(m_values); + } + } + + throw std::logic_error("No value provided for '" + m_names.back() + "'."); + } + + /* + * Get argument value given a type. + * @pre The object has no default value. + * @returns The stored value if any, std::nullopt otherwise. + */ + template auto present() const -> std::optional { + if (m_default_value.has_value()) { + throw std::logic_error("Argument with default value always presents"); + } + if (m_values.empty()) { + return std::nullopt; + } + if constexpr (details::IsContainer) { + return any_cast_container(m_values); + } + return std::any_cast(m_values.front()); + } + + template + static auto any_cast_container(const std::vector &operand) -> T { + using ValueType = typename T::value_type; + + T result; + std::transform( + std::begin(operand), std::end(operand), std::back_inserter(result), + [](const auto &value) { return std::any_cast(value); }); + return result; + } + + void set_usage_newline_counter(int i) { m_usage_newline_counter = i; } + + void set_group_idx(std::size_t i) { m_group_idx = i; } + + std::vector m_names; + std::string_view m_used_name; + std::string m_help; + std::string m_metavar; + std::any m_default_value; + std::string m_default_value_repr; + std::optional + m_default_value_str; // used for checking default_value against choices + std::any m_implicit_value; + std::optional> m_choices{std::nullopt}; + using valued_action = std::function; + using void_action = std::function; + std::variant m_action{ + std::in_place_type, + [](const std::string &value) { return value; }}; + std::vector m_values; + NArgsRange m_num_args_range{1, 1}; + // Bit field of bool values. Set default value in ctor. + bool m_accepts_optional_like_value : 1; + bool m_is_optional : 1; + bool m_is_required : 1; + bool m_is_repeatable : 1; + bool m_is_used : 1; + bool m_is_hidden : 1; // if set, does not appear in usage or help + std::string_view m_prefix_chars; // ArgumentParser has the prefix_chars + int m_usage_newline_counter = 0; + std::size_t m_group_idx = 0; +}; + +class ArgumentParser { +public: + explicit ArgumentParser(std::string program_name = {}, + std::string version = "1.0", + default_arguments add_args = default_arguments::all, + bool exit_on_default_arguments = true, + std::ostream &os = std::cout) + : m_program_name(std::move(program_name)), m_version(std::move(version)), + m_exit_on_default_arguments(exit_on_default_arguments), + m_parser_path(m_program_name) { + if ((add_args & default_arguments::help) == default_arguments::help) { + add_argument("-h", "--help") + .action([&](const auto & /*unused*/) { + os << help().str(); + if (m_exit_on_default_arguments) { + std::exit(0); + } + }) + .default_value(false) + .help("shows help message and exits") + .implicit_value(true) + .nargs(0); + } + if ((add_args & default_arguments::version) == default_arguments::version) { + add_argument("-v", "--version") + .action([&](const auto & /*unused*/) { + os << m_version << std::endl; + if (m_exit_on_default_arguments) { + std::exit(0); + } + }) + .default_value(false) + .help("prints version information and exits") + .implicit_value(true) + .nargs(0); + } + } + + ~ArgumentParser() = default; + + // ArgumentParser is meant to be used in a single function. + // Setup everything and parse arguments in one place. + // + // ArgumentParser internally uses std::string_views, + // references, iterators, etc. + // Many of these elements become invalidated after a copy or move. + ArgumentParser(const ArgumentParser &other) = delete; + ArgumentParser &operator=(const ArgumentParser &other) = delete; + ArgumentParser(ArgumentParser &&) noexcept = delete; + ArgumentParser &operator=(ArgumentParser &&) = delete; + + explicit operator bool() const { + auto arg_used = std::any_of(m_argument_map.cbegin(), m_argument_map.cend(), + [](auto &it) { return it.second->m_is_used; }); + auto subparser_used = + std::any_of(m_subparser_used.cbegin(), m_subparser_used.cend(), + [](auto &it) { return it.second; }); + + return m_is_parsed && (arg_used || subparser_used); + } + + // Parameter packing + // Call add_argument with variadic number of string arguments + template Argument &add_argument(Targs... f_args) { + using array_of_sv = std::array; + auto argument = + m_optional_arguments.emplace(std::cend(m_optional_arguments), + m_prefix_chars, array_of_sv{f_args...}); + + if (!argument->m_is_optional) { + m_positional_arguments.splice(std::cend(m_positional_arguments), + m_optional_arguments, argument); + } + argument->set_usage_newline_counter(m_usage_newline_counter); + argument->set_group_idx(m_group_names.size()); + + index_argument(argument); + return *argument; + } + + class MutuallyExclusiveGroup { + friend class ArgumentParser; + + public: + MutuallyExclusiveGroup() = delete; + + explicit MutuallyExclusiveGroup(ArgumentParser &parent, + bool required = false) + : m_parent(parent), m_required(required), m_elements({}) {} + + MutuallyExclusiveGroup(const MutuallyExclusiveGroup &other) = delete; + MutuallyExclusiveGroup & + operator=(const MutuallyExclusiveGroup &other) = delete; + + MutuallyExclusiveGroup(MutuallyExclusiveGroup &&other) noexcept + : m_parent(other.m_parent), m_required(other.m_required), + m_elements(std::move(other.m_elements)) { + other.m_elements.clear(); + } + + template Argument &add_argument(Targs... f_args) { + auto &argument = m_parent.add_argument(std::forward(f_args)...); + m_elements.push_back(&argument); + argument.set_usage_newline_counter(m_parent.m_usage_newline_counter); + argument.set_group_idx(m_parent.m_group_names.size()); + return argument; + } + + private: + ArgumentParser &m_parent; + bool m_required{false}; + std::vector m_elements{}; + }; + + MutuallyExclusiveGroup &add_mutually_exclusive_group(bool required = false) { + m_mutually_exclusive_groups.emplace_back(*this, required); + return m_mutually_exclusive_groups.back(); + } + + // Parameter packed add_parents method + // Accepts a variadic number of ArgumentParser objects + template + ArgumentParser &add_parents(const Targs &... f_args) { + for (const ArgumentParser &parent_parser : {std::ref(f_args)...}) { + for (const auto &argument : parent_parser.m_positional_arguments) { + auto it = m_positional_arguments.insert( + std::cend(m_positional_arguments), argument); + index_argument(it); + } + for (const auto &argument : parent_parser.m_optional_arguments) { + auto it = m_optional_arguments.insert(std::cend(m_optional_arguments), + argument); + index_argument(it); + } + } + return *this; + } + + // Ask for the next optional arguments to be displayed on a separate + // line in usage() output. Only effective if set_usage_max_line_width() is + // also used. + ArgumentParser &add_usage_newline() { + ++m_usage_newline_counter; + return *this; + } + + // Ask for the next optional arguments to be displayed in a separate section + // in usage() and help (<< *this) output. + // For usage(), this is only effective if set_usage_max_line_width() is + // also used. + ArgumentParser &add_group(std::string group_name) { + m_group_names.emplace_back(std::move(group_name)); + return *this; + } + + ArgumentParser &add_description(std::string description) { + m_description = std::move(description); + return *this; + } + + ArgumentParser &add_epilog(std::string epilog) { + m_epilog = std::move(epilog); + return *this; + } + + // Add a un-documented/hidden alias for an argument. + // Ideally we'd want this to be a method of Argument, but Argument + // does not own its owing ArgumentParser. + ArgumentParser &add_hidden_alias_for(Argument &arg, std::string_view alias) { + for (auto it = m_optional_arguments.begin(); + it != m_optional_arguments.end(); ++it) { + if (&(*it) == &arg) { + m_argument_map.insert_or_assign(std::string(alias), it); + return *this; + } + } + throw std::logic_error( + "Argument is not an optional argument of this parser"); + } + + /* Getter for arguments and subparsers. + * @throws std::logic_error in case of an invalid argument or subparser name + */ + template T &at(std::string_view name) { + if constexpr (std::is_same_v) { + return (*this)[name]; + } else { + std::string str_name(name); + auto subparser_it = m_subparser_map.find(str_name); + if (subparser_it != m_subparser_map.end()) { + return subparser_it->second->get(); + } + throw std::logic_error("No such subparser: " + str_name); + } + } + + ArgumentParser &set_prefix_chars(std::string prefix_chars) { + m_prefix_chars = std::move(prefix_chars); + return *this; + } + + ArgumentParser &set_assign_chars(std::string assign_chars) { + m_assign_chars = std::move(assign_chars); + return *this; + } + + /* Call parse_args_internal - which does all the work + * Then, validate the parsed arguments + * This variant is used mainly for testing + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args(const std::vector &arguments) { + parse_args_internal(arguments); + // Check if all arguments are parsed + for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { + argument->validate(); + } + + // Check each mutually exclusive group and make sure + // there are no constraint violations + for (const auto &group : m_mutually_exclusive_groups) { + auto mutex_argument_used{false}; + Argument *mutex_argument_it{nullptr}; + for (Argument *arg : group.m_elements) { + if (!mutex_argument_used && arg->m_is_used) { + mutex_argument_used = true; + mutex_argument_it = arg; + } else if (mutex_argument_used && arg->m_is_used) { + // Violation + throw std::runtime_error("Argument '" + arg->get_usage_full() + + "' not allowed with '" + + mutex_argument_it->get_usage_full() + "'"); + } + } + + if (!mutex_argument_used && group.m_required) { + // at least one argument from the group is + // required + std::string argument_names{}; + std::size_t i = 0; + std::size_t size = group.m_elements.size(); + for (Argument *arg : group.m_elements) { + if (i + 1 == size) { + // last + argument_names += std::string("'") + arg->get_usage_full() + std::string("' "); + } else { + argument_names += std::string("'") + arg->get_usage_full() + std::string("' or "); + } + i += 1; + } + throw std::runtime_error("One of the arguments " + argument_names + + "is required"); + } + } + } + + /* Call parse_known_args_internal - which does all the work + * Then, validate the parsed arguments + * This variant is used mainly for testing + * @throws std::runtime_error in case of any invalid argument + */ + std::vector + parse_known_args(const std::vector &arguments) { + auto unknown_arguments = parse_known_args_internal(arguments); + // Check if all arguments are parsed + for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { + argument->validate(); + } + return unknown_arguments; + } + + /* Main entry point for parsing command-line arguments using this + * ArgumentParser + * @throws std::runtime_error in case of any invalid argument + */ + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) + void parse_args(int argc, const char *const argv[]) { + parse_args({argv, argv + argc}); + } + + /* Main entry point for parsing command-line arguments using this + * ArgumentParser + * @throws std::runtime_error in case of any invalid argument + */ + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) + auto parse_known_args(int argc, const char *const argv[]) { + return parse_known_args({argv, argv + argc}); + } + + /* Getter for options with default values. + * @throws std::logic_error if parse_args() has not been previously called + * @throws std::logic_error if there is no such option + * @throws std::logic_error if the option has no value + * @throws std::bad_any_cast if the option is not of type T + */ + template T get(std::string_view arg_name) const { + if (!m_is_parsed) { + throw std::logic_error("Nothing parsed, no arguments are available."); + } + return (*this)[arg_name].get(); + } + + /* Getter for options without default values. + * @pre The option has no default value. + * @throws std::logic_error if there is no such option + * @throws std::bad_any_cast if the option is not of type T + */ + template + auto present(std::string_view arg_name) const -> std::optional { + return (*this)[arg_name].present(); + } + + /* Getter that returns true for user-supplied options. Returns false if not + * user-supplied, even with a default value. + */ + auto is_used(std::string_view arg_name) const { + return (*this)[arg_name].m_is_used; + } + + /* Getter that returns true if a subcommand is used. + */ + auto is_subcommand_used(std::string_view subcommand_name) const { + return m_subparser_used.at(std::string(subcommand_name)); + } + + /* Getter that returns true if a subcommand is used. + */ + auto is_subcommand_used(const ArgumentParser &subparser) const { + return is_subcommand_used(subparser.m_program_name); + } + + /* Indexing operator. Return a reference to an Argument object + * Used in conjunction with Argument.operator== e.g., parser["foo"] == true + * @throws std::logic_error in case of an invalid argument name + */ + Argument &operator[](std::string_view arg_name) const { + std::string name(arg_name); + auto it = m_argument_map.find(name); + if (it != m_argument_map.end()) { + return *(it->second); + } + if (!is_valid_prefix_char(arg_name.front())) { + const auto legal_prefix_char = get_any_valid_prefix_char(); + const auto prefix = std::string(1, legal_prefix_char); + + // "-" + arg_name + name = prefix + name; + it = m_argument_map.find(name); + if (it != m_argument_map.end()) { + return *(it->second); + } + // "--" + arg_name + name = prefix + name; + it = m_argument_map.find(name); + if (it != m_argument_map.end()) { + return *(it->second); + } + } + throw std::logic_error("No such argument: " + std::string(arg_name)); + } + + // Print help message + friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) + -> std::ostream & { + stream.setf(std::ios_base::left); + + auto longest_arg_length = parser.get_length_of_longest_argument(); + + stream << parser.usage() << "\n\n"; + + if (!parser.m_description.empty()) { + stream << parser.m_description << "\n\n"; + } + + const bool has_visible_positional_args = std::find_if( + parser.m_positional_arguments.begin(), + parser.m_positional_arguments.end(), + [](const auto &argument) { + return !argument.m_is_hidden; }) != + parser.m_positional_arguments.end(); + if (has_visible_positional_args) { + stream << "Positional arguments:\n"; + } + + for (const auto &argument : parser.m_positional_arguments) { + if (!argument.m_is_hidden) { + stream.width(static_cast(longest_arg_length)); + stream << argument; + } + } + + if (!parser.m_optional_arguments.empty()) { + stream << (!has_visible_positional_args ? "" : "\n") + << "Optional arguments:\n"; + } + + for (const auto &argument : parser.m_optional_arguments) { + if (argument.m_group_idx == 0 && !argument.m_is_hidden) { + stream.width(static_cast(longest_arg_length)); + stream << argument; + } + } + + for (size_t i_group = 0; i_group < parser.m_group_names.size(); ++i_group) { + stream << "\n" << parser.m_group_names[i_group] << " (detailed usage):\n"; + for (const auto &argument : parser.m_optional_arguments) { + if (argument.m_group_idx == i_group + 1 && !argument.m_is_hidden) { + stream.width(static_cast(longest_arg_length)); + stream << argument; + } + } + } + + bool has_visible_subcommands = std::any_of( + parser.m_subparser_map.begin(), parser.m_subparser_map.end(), + [](auto &p) { return !p.second->get().m_suppress; }); + + if (has_visible_subcommands) { + stream << (parser.m_positional_arguments.empty() + ? (parser.m_optional_arguments.empty() ? "" : "\n") + : "\n") + << "Subcommands:\n"; + for (const auto &[command, subparser] : parser.m_subparser_map) { + if (subparser->get().m_suppress) { + continue; + } + + stream << std::setw(2) << " "; + stream << std::setw(static_cast(longest_arg_length - 2)) + << command; + stream << " " << subparser->get().m_description << "\n"; + } + } + + if (!parser.m_epilog.empty()) { + stream << '\n'; + stream << parser.m_epilog << "\n\n"; + } + + return stream; + } + + // Format help message + auto help() const -> std::stringstream { + std::stringstream out; + out << *this; + return out; + } + + // Sets the maximum width for a line of the Usage message + ArgumentParser &set_usage_max_line_width(size_t w) { + this->m_usage_max_line_width = w; + return *this; + } + + // Asks to display arguments of mutually exclusive group on separate lines in + // the Usage message + ArgumentParser &set_usage_break_on_mutex() { + this->m_usage_break_on_mutex = true; + return *this; + } + + // Format usage part of help only + auto usage() const -> std::string { + std::stringstream stream; + + std::string curline("Usage: "); + curline += this->m_program_name; + const bool multiline_usage = + this->m_usage_max_line_width < (std::numeric_limits::max)(); + const size_t indent_size = curline.size(); + + const auto deal_with_options_of_group = [&](std::size_t group_idx) { + bool found_options = false; + // Add any options inline here + const MutuallyExclusiveGroup *cur_mutex = nullptr; + int usage_newline_counter = -1; + for (const auto &argument : this->m_optional_arguments) { + if (argument.m_is_hidden) { + continue; + } + if (multiline_usage) { + if (argument.m_group_idx != group_idx) { + continue; + } + if (usage_newline_counter != argument.m_usage_newline_counter) { + if (usage_newline_counter >= 0) { + if (curline.size() > indent_size) { + stream << curline << std::endl; + curline = std::string(indent_size, ' '); + } + } + usage_newline_counter = argument.m_usage_newline_counter; + } + } + found_options = true; + const std::string arg_inline_usage = argument.get_inline_usage(); + const MutuallyExclusiveGroup *arg_mutex = + get_belonging_mutex(&argument); + if ((cur_mutex != nullptr) && (arg_mutex == nullptr)) { + curline += ']'; + if (this->m_usage_break_on_mutex) { + stream << curline << std::endl; + curline = std::string(indent_size, ' '); + } + } else if ((cur_mutex == nullptr) && (arg_mutex != nullptr)) { + if ((this->m_usage_break_on_mutex && curline.size() > indent_size) || + curline.size() + 3 + arg_inline_usage.size() > + this->m_usage_max_line_width) { + stream << curline << std::endl; + curline = std::string(indent_size, ' '); + } + curline += " ["; + } else if ((cur_mutex != nullptr) && (arg_mutex != nullptr)) { + if (cur_mutex != arg_mutex) { + curline += ']'; + if (this->m_usage_break_on_mutex || + curline.size() + 3 + arg_inline_usage.size() > + this->m_usage_max_line_width) { + stream << curline << std::endl; + curline = std::string(indent_size, ' '); + } + curline += " ["; + } else { + curline += '|'; + } + } + cur_mutex = arg_mutex; + if (curline.size() + 1 + arg_inline_usage.size() > + this->m_usage_max_line_width) { + stream << curline << std::endl; + curline = std::string(indent_size, ' '); + curline += " "; + } else if (cur_mutex == nullptr) { + curline += " "; + } + curline += arg_inline_usage; + } + if (cur_mutex != nullptr) { + curline += ']'; + } + return found_options; + }; + + const bool found_options = deal_with_options_of_group(0); + + if (found_options && multiline_usage && + !this->m_positional_arguments.empty()) { + stream << curline << std::endl; + curline = std::string(indent_size, ' '); + } + // Put positional arguments after the optionals + for (const auto &argument : this->m_positional_arguments) { + if (argument.m_is_hidden) { + continue; + } + const std::string pos_arg = !argument.m_metavar.empty() + ? argument.m_metavar + : argument.m_names.front(); + if (curline.size() + 1 + pos_arg.size() > this->m_usage_max_line_width) { + stream << curline << std::endl; + curline = std::string(indent_size, ' '); + } + curline += " "; + if (argument.m_num_args_range.get_min() == 0 && + !argument.m_num_args_range.is_right_bounded()) { + curline += "["; + curline += pos_arg; + curline += "]..."; + } else if (argument.m_num_args_range.get_min() == 1 && + !argument.m_num_args_range.is_right_bounded()) { + curline += pos_arg; + curline += "..."; + } else { + curline += pos_arg; + } + } + + if (multiline_usage) { + // Display options of other groups + for (std::size_t i = 0; i < m_group_names.size(); ++i) { + stream << curline << std::endl << std::endl; + stream << m_group_names[i] << ":" << std::endl; + curline = std::string(indent_size, ' '); + deal_with_options_of_group(i + 1); + } + } + + stream << curline; + + // Put subcommands after positional arguments + if (!m_subparser_map.empty()) { + stream << " {"; + std::size_t i{0}; + for (const auto &[command, subparser] : m_subparser_map) { + if (subparser->get().m_suppress) { + continue; + } + + if (i == 0) { + stream << command; + } else { + stream << "," << command; + } + ++i; + } + stream << "}"; + } + + return stream.str(); + } + + // Printing the one and only help message + // I've stuck with a simple message format, nothing fancy. + [[deprecated("Use cout << program; instead. See also help().")]] std::string + print_help() const { + auto out = help(); + std::cout << out.rdbuf(); + return out.str(); + } + + void add_subparser(ArgumentParser &parser) { + parser.m_parser_path = m_program_name + " " + parser.m_program_name; + auto it = m_subparsers.emplace(std::cend(m_subparsers), parser); + m_subparser_map.insert_or_assign(parser.m_program_name, it); + m_subparser_used.insert_or_assign(parser.m_program_name, false); + } + + void set_suppress(bool suppress) { m_suppress = suppress; } + +protected: + const MutuallyExclusiveGroup *get_belonging_mutex(const Argument *arg) const { + for (const auto &mutex : m_mutually_exclusive_groups) { + if (std::find(mutex.m_elements.begin(), mutex.m_elements.end(), arg) != + mutex.m_elements.end()) { + return &mutex; + } + } + return nullptr; + } + + bool is_valid_prefix_char(char c) const { + return m_prefix_chars.find(c) != std::string::npos; + } + + char get_any_valid_prefix_char() const { return m_prefix_chars[0]; } + + /* + * Pre-process this argument list. Anything starting with "--", that + * contains an =, where the prefix before the = has an entry in the + * options table, should be split. + */ + std::vector + preprocess_arguments(const std::vector &raw_arguments) const { + std::vector arguments{}; + for (const auto &arg : raw_arguments) { + + const auto argument_starts_with_prefix_chars = + [this](const std::string &a) -> bool { + if (!a.empty()) { + + const auto legal_prefix = [this](char c) -> bool { + return m_prefix_chars.find(c) != std::string::npos; + }; + + // Windows-style + // if '/' is a legal prefix char + // then allow single '/' followed by argument name, followed by an + // assign char, e.g., ':' e.g., 'test.exe /A:Foo' + const auto windows_style = legal_prefix('/'); + + if (windows_style) { + if (legal_prefix(a[0])) { + return true; + } + } else { + // Slash '/' is not a legal prefix char + // For all other characters, only support long arguments + // i.e., the argument must start with 2 prefix chars, e.g, + // '--foo' e,g, './test --foo=Bar -DARG=yes' + if (a.size() > 1) { + return (legal_prefix(a[0]) && legal_prefix(a[1])); + } + } + } + return false; + }; + + // Check that: + // - We don't have an argument named exactly this + // - The argument starts with a prefix char, e.g., "--" + // - The argument contains an assign char, e.g., "=" + auto assign_char_pos = arg.find_first_of(m_assign_chars); + + if (m_argument_map.find(arg) == m_argument_map.end() && + argument_starts_with_prefix_chars(arg) && + assign_char_pos != std::string::npos) { + // Get the name of the potential option, and check it exists + std::string opt_name = arg.substr(0, assign_char_pos); + if (m_argument_map.find(opt_name) != m_argument_map.end()) { + // This is the name of an option! Split it into two parts + arguments.push_back(std::move(opt_name)); + arguments.push_back(arg.substr(assign_char_pos + 1)); + continue; + } + } + // If we've fallen through to here, then it's a standard argument + arguments.push_back(arg); + } + return arguments; + } + + /* + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args_internal(const std::vector &raw_arguments) { + auto arguments = preprocess_arguments(raw_arguments); + if (m_program_name.empty() && !arguments.empty()) { + m_program_name = arguments.front(); + } + auto end = std::end(arguments); + auto positional_argument_it = std::begin(m_positional_arguments); + for (auto it = std::next(std::begin(arguments)); it != end;) { + const auto ¤t_argument = *it; + if (Argument::is_positional(current_argument, m_prefix_chars)) { + if (positional_argument_it == std::end(m_positional_arguments)) { + + // Check sub-parsers + auto subparser_it = m_subparser_map.find(current_argument); + if (subparser_it != m_subparser_map.end()) { + + // build list of remaining args + const auto unprocessed_arguments = + std::vector(it, end); + + // invoke subparser + m_is_parsed = true; + m_subparser_used[current_argument] = true; + return subparser_it->second->get().parse_args( + unprocessed_arguments); + } + + if (m_positional_arguments.empty()) { + + // Ask the user if they argument they provided was a typo + // for some sub-parser, + // e.g., user provided `git totes` instead of `git notes` + if (!m_subparser_map.empty()) { + throw std::runtime_error( + "Failed to parse '" + current_argument + "', did you mean '" + + std::string{details::get_most_similar_string( + m_subparser_map, current_argument)} + + "'"); + } + + // Ask the user if they meant to use a specific optional argument + if (!m_optional_arguments.empty()) { + for (const auto &opt : m_optional_arguments) { + if (!opt.m_implicit_value.has_value()) { + // not a flag, requires a value + if (!opt.m_is_used) { + throw std::runtime_error( + "Zero positional arguments expected, did you mean " + + opt.get_usage_full()); + } + } + } + + throw std::runtime_error("Zero positional arguments expected"); + } else { + throw std::runtime_error("Zero positional arguments expected"); + } + } else { + throw std::runtime_error("Maximum number of positional arguments " + "exceeded, failed to parse '" + + current_argument + "'"); + } + } + auto argument = positional_argument_it++; + + // Deal with the situation of ... + if (argument->m_num_args_range.get_min() == 1 && + argument->m_num_args_range.get_max() == (std::numeric_limits::max)() && + positional_argument_it != std::end(m_positional_arguments) && + std::next(positional_argument_it) == std::end(m_positional_arguments) && + positional_argument_it->m_num_args_range.get_min() == 1 && + positional_argument_it->m_num_args_range.get_max() == 1 ) { + if (std::next(it) != end) { + positional_argument_it->consume(std::prev(end), end); + end = std::prev(end); + } else { + throw std::runtime_error("Missing " + positional_argument_it->m_names.front()); + } + } + + it = argument->consume(it, end); + continue; + } + + auto arg_map_it = m_argument_map.find(current_argument); + if (arg_map_it != m_argument_map.end()) { + auto argument = arg_map_it->second; + it = argument->consume(std::next(it), end, arg_map_it->first); + } else if (const auto &compound_arg = current_argument; + compound_arg.size() > 1 && + is_valid_prefix_char(compound_arg[0]) && + !is_valid_prefix_char(compound_arg[1])) { + ++it; + for (std::size_t j = 1; j < compound_arg.size(); j++) { + auto hypothetical_arg = std::string{'-', compound_arg[j]}; + auto arg_map_it2 = m_argument_map.find(hypothetical_arg); + if (arg_map_it2 != m_argument_map.end()) { + auto argument = arg_map_it2->second; + it = argument->consume(it, end, arg_map_it2->first); + } else { + throw std::runtime_error("Unknown argument: " + current_argument); + } + } + } else { + throw std::runtime_error("Unknown argument: " + current_argument); + } + } + m_is_parsed = true; + } + + /* + * Like parse_args_internal but collects unused args into a vector + */ + std::vector + parse_known_args_internal(const std::vector &raw_arguments) { + auto arguments = preprocess_arguments(raw_arguments); + + std::vector unknown_arguments{}; + + if (m_program_name.empty() && !arguments.empty()) { + m_program_name = arguments.front(); + } + auto end = std::end(arguments); + auto positional_argument_it = std::begin(m_positional_arguments); + for (auto it = std::next(std::begin(arguments)); it != end;) { + const auto ¤t_argument = *it; + if (Argument::is_positional(current_argument, m_prefix_chars)) { + if (positional_argument_it == std::end(m_positional_arguments)) { + + // Check sub-parsers + auto subparser_it = m_subparser_map.find(current_argument); + if (subparser_it != m_subparser_map.end()) { + + // build list of remaining args + const auto unprocessed_arguments = + std::vector(it, end); + + // invoke subparser + m_is_parsed = true; + m_subparser_used[current_argument] = true; + return subparser_it->second->get().parse_known_args_internal( + unprocessed_arguments); + } + + // save current argument as unknown and go to next argument + unknown_arguments.push_back(current_argument); + ++it; + } else { + // current argument is the value of a positional argument + // consume it + auto argument = positional_argument_it++; + it = argument->consume(it, end); + } + continue; + } + + auto arg_map_it = m_argument_map.find(current_argument); + if (arg_map_it != m_argument_map.end()) { + auto argument = arg_map_it->second; + it = argument->consume(std::next(it), end, arg_map_it->first); + } else if (const auto &compound_arg = current_argument; + compound_arg.size() > 1 && + is_valid_prefix_char(compound_arg[0]) && + !is_valid_prefix_char(compound_arg[1])) { + ++it; + for (std::size_t j = 1; j < compound_arg.size(); j++) { + auto hypothetical_arg = std::string{'-', compound_arg[j]}; + auto arg_map_it2 = m_argument_map.find(hypothetical_arg); + if (arg_map_it2 != m_argument_map.end()) { + auto argument = arg_map_it2->second; + it = argument->consume(it, end, arg_map_it2->first); + } else { + unknown_arguments.push_back(current_argument); + break; + } + } + } else { + // current argument is an optional-like argument that is unknown + // save it and move to next argument + unknown_arguments.push_back(current_argument); + ++it; + } + } + m_is_parsed = true; + return unknown_arguments; + } + + // Used by print_help. + std::size_t get_length_of_longest_argument() const { + if (m_argument_map.empty()) { + return 0; + } + std::size_t max_size = 0; + for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { + max_size = + std::max(max_size, argument->get_arguments_length()); + } + for ([[maybe_unused]] const auto &[command, unused] : m_subparser_map) { + max_size = std::max(max_size, command.size()); + } + return max_size; + } + + using argument_it = std::list::iterator; + using mutex_group_it = std::vector::iterator; + using argument_parser_it = + std::list>::iterator; + + void index_argument(argument_it it) { + for (const auto &name : std::as_const(it->m_names)) { + m_argument_map.insert_or_assign(name, it); + } + } + + std::string m_program_name; + std::string m_version; + std::string m_description; + std::string m_epilog; + bool m_exit_on_default_arguments = true; + std::string m_prefix_chars{"-"}; + std::string m_assign_chars{"="}; + bool m_is_parsed = false; + std::list m_positional_arguments; + std::list m_optional_arguments; + std::map m_argument_map; + std::string m_parser_path; + std::list> m_subparsers; + std::map m_subparser_map; + std::map m_subparser_used; + std::vector m_mutually_exclusive_groups; + bool m_suppress = false; + std::size_t m_usage_max_line_width = (std::numeric_limits::max)(); + bool m_usage_break_on_mutex = false; + int m_usage_newline_counter = 0; + std::vector m_group_names; +}; + +} // namespace wpi diff --git a/wpiutil/src/main/native/thirdparty/concurrentqueue/include/wpi/concurrentqueue.h b/wpiutil/src/main/native/thirdparty/concurrentqueue/include/wpi/concurrentqueue.h new file mode 100644 index 00000000000..214e4f53dd9 --- /dev/null +++ b/wpiutil/src/main/native/thirdparty/concurrentqueue/include/wpi/concurrentqueue.h @@ -0,0 +1,3747 @@ +// Provides a C++11 implementation of a multi-producer, multi-consumer lock-free queue. +// An overview, including benchmark results, is provided here: +// http://moodycamel.com/blog/2014/a-fast-general-purpose-lock-free-queue-for-c++ +// The full design is also described in excruciating detail at: +// http://moodycamel.com/blog/2014/detailed-design-of-a-lock-free-queue + +// Simplified BSD license: +// Copyright (c) 2013-2020, Cameron Desrochers. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// - Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// - Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Also dual-licensed under the Boost Software License (see LICENSE.md) + +#pragma once + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +// Disable -Wconversion warnings (spuriously triggered when Traits::size_t and +// Traits::index_t are set to < 32 bits, causing integer promotion, causing warnings +// upon assigning any computed values) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" + +#ifdef MCDBGQ_USE_RELACY +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" +#endif +#endif + +#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) +// VS2019 with /W4 warns about constant conditional expressions but unless /std=c++17 or higher +// does not support `if constexpr`, so we have no choice but to simply disable the warning +#pragma warning(push) +#pragma warning(disable: 4127) // conditional expression is constant +#endif + +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif + +#ifdef MCDBGQ_USE_RELACY +#include "relacy/relacy_std.hpp" +#include "relacy_shims.h" +// We only use malloc/free anyway, and the delete macro messes up `= delete` method declarations. +// We'll override the default trait malloc ourselves without a macro. +#undef new +#undef delete +#undef malloc +#undef free +#else +#include // Requires C++11. Sorry VS2010. +#include +#endif +#include // for max_align_t +#include +#include +#include +#include +#include +#include +#include // for CHAR_BIT +#include +#include // partly for __WINPTHREADS_VERSION if on MinGW-w64 w/ POSIX threading +#include // used for thread exit synchronization + +// Platform-specific definitions of a numeric thread ID type and an invalid value +namespace wpi { namespace details { + template struct thread_id_converter { + typedef thread_id_t thread_id_numeric_size_t; + typedef thread_id_t thread_id_hash_t; + static thread_id_hash_t prehash(thread_id_t const& x) { return x; } + }; +} } +#if defined(MCDBGQ_USE_RELACY) +namespace wpi { namespace details { + typedef std::uint32_t thread_id_t; + static const thread_id_t invalid_thread_id = 0xFFFFFFFFU; + static const thread_id_t invalid_thread_id2 = 0xFFFFFFFEU; + static inline thread_id_t thread_id() { return rl::thread_index(); } +} } +#elif defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__) +// No sense pulling in windows.h in a header, we'll manually declare the function +// we use and rely on backwards-compatibility for this not to break +extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(void); +namespace wpi { namespace details { + static_assert(sizeof(unsigned long) == sizeof(std::uint32_t), "Expected size of unsigned long to be 32 bits on Windows"); + typedef std::uint32_t thread_id_t; + static const thread_id_t invalid_thread_id = 0; // See http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx + static const thread_id_t invalid_thread_id2 = 0xFFFFFFFFU; // Not technically guaranteed to be invalid, but is never used in practice. Note that all Win32 thread IDs are presently multiples of 4. + static inline thread_id_t thread_id() { return static_cast(::GetCurrentThreadId()); } +} } +#elif defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || (defined(__APPLE__) && TARGET_OS_IPHONE) || defined(__MVS__) || defined(WPI_CQ_NO_THREAD_LOCAL) +namespace wpi { namespace details { + static_assert(sizeof(std::thread::id) == 4 || sizeof(std::thread::id) == 8, "std::thread::id is expected to be either 4 or 8 bytes"); + + typedef std::thread::id thread_id_t; + static const thread_id_t invalid_thread_id; // Default ctor creates invalid ID + + // Note we don't define a invalid_thread_id2 since std::thread::id doesn't have one; it's + // only used if WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED is defined anyway, which it won't + // be. + static inline thread_id_t thread_id() { return std::this_thread::get_id(); } + + template struct thread_id_size { }; + template<> struct thread_id_size<4> { typedef std::uint32_t numeric_t; }; + template<> struct thread_id_size<8> { typedef std::uint64_t numeric_t; }; + + template<> struct thread_id_converter { + typedef thread_id_size::numeric_t thread_id_numeric_size_t; +#ifndef __APPLE__ + typedef std::size_t thread_id_hash_t; +#else + typedef thread_id_numeric_size_t thread_id_hash_t; +#endif + + static thread_id_hash_t prehash(thread_id_t const& x) + { +#ifndef __APPLE__ + return std::hash()(x); +#else + return *reinterpret_cast(&x); +#endif + } + }; +} } +#else +// Use a nice trick from this answer: http://stackoverflow.com/a/8438730/21475 +// In order to get a numeric thread ID in a platform-independent way, we use a thread-local +// static variable's address as a thread identifier :-) +#if defined(__GNUC__) || defined(__INTEL_COMPILER) +#define WPI_CQ_THREADLOCAL __thread +#elif defined(_MSC_VER) +#define WPI_CQ_THREADLOCAL __declspec(thread) +#else +// Assume C++11 compliant compiler +#define WPI_CQ_THREADLOCAL thread_local +#endif +namespace wpi { namespace details { + typedef std::uintptr_t thread_id_t; + static const thread_id_t invalid_thread_id = 0; // Address can't be nullptr + static const thread_id_t invalid_thread_id2 = 1; // Member accesses off a null pointer are also generally invalid. Plus it's not aligned. + inline thread_id_t thread_id() { static WPI_CQ_THREADLOCAL int x; return reinterpret_cast(&x); } +} } +#endif + +// Constexpr if +#ifndef WPI_CQ_CONSTEXPR_IF +#if (defined(_MSC_VER) && defined(_HAS_CXX17) && _HAS_CXX17) || __cplusplus > 201402L +#define WPI_CQ_CONSTEXPR_IF if constexpr +#define WPI_CQ_MAYBE_UNUSED [[maybe_unused]] +#else +#define WPI_CQ_CONSTEXPR_IF if +#define WPI_CQ_MAYBE_UNUSED +#endif +#endif + +// Exceptions +#ifndef WPI_CQ_EXCEPTIONS_ENABLED +#if (defined(_MSC_VER) && defined(_CPPUNWIND)) || (defined(__GNUC__) && defined(__EXCEPTIONS)) || (!defined(_MSC_VER) && !defined(__GNUC__)) +#define WPI_CQ_EXCEPTIONS_ENABLED +#endif +#endif +#ifdef WPI_CQ_EXCEPTIONS_ENABLED +#define WPI_CQ_TRY try +#define WPI_CQ_CATCH(...) catch(__VA_ARGS__) +#define WPI_CQ_RETHROW throw +#define WPI_CQ_THROW(expr) throw (expr) +#else +#define WPI_CQ_TRY WPI_CQ_CONSTEXPR_IF (true) +#define WPI_CQ_CATCH(...) else WPI_CQ_CONSTEXPR_IF (false) +#define WPI_CQ_RETHROW +#define WPI_CQ_THROW(expr) +#endif + +#ifndef WPI_CQ_NOEXCEPT +#if !defined(WPI_CQ_EXCEPTIONS_ENABLED) +#define WPI_CQ_NOEXCEPT +#define WPI_CQ_NOEXCEPT_CTOR(type, valueType, expr) true +#define WPI_CQ_NOEXCEPT_ASSIGN(type, valueType, expr) true +#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1800 +// VS2012's std::is_nothrow_[move_]constructible is broken and returns true when it shouldn't :-( +// We have to assume *all* non-trivial constructors may throw on VS2012! +#define WPI_CQ_NOEXCEPT _NOEXCEPT +#define WPI_CQ_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value : std::is_trivially_copy_constructible::value) +#define WPI_CQ_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && WPI_CQ_NOEXCEPT_CTOR(type, valueType, expr)) +#elif defined(_MSC_VER) && defined(_NOEXCEPT) && _MSC_VER < 1900 +#define WPI_CQ_NOEXCEPT _NOEXCEPT +#define WPI_CQ_NOEXCEPT_CTOR(type, valueType, expr) (std::is_rvalue_reference::value && std::is_move_constructible::value ? std::is_trivially_move_constructible::value || std::is_nothrow_move_constructible::value : std::is_trivially_copy_constructible::value || std::is_nothrow_copy_constructible::value) +#define WPI_CQ_NOEXCEPT_ASSIGN(type, valueType, expr) ((std::is_rvalue_reference::value && std::is_move_assignable::value ? std::is_trivially_move_assignable::value || std::is_nothrow_move_assignable::value : std::is_trivially_copy_assignable::value || std::is_nothrow_copy_assignable::value) && WPI_CQ_NOEXCEPT_CTOR(type, valueType, expr)) +#else +#define WPI_CQ_NOEXCEPT noexcept +#define WPI_CQ_NOEXCEPT_CTOR(type, valueType, expr) noexcept(expr) +#define WPI_CQ_NOEXCEPT_ASSIGN(type, valueType, expr) noexcept(expr) +#endif +#endif + +#ifndef WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED +#ifdef MCDBGQ_USE_RELACY +#define WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED +#else +// VS2013 doesn't support `thread_local`, and MinGW-w64 w/ POSIX threading has a crippling bug: http://sourceforge.net/p/mingw-w64/bugs/445 +// g++ <=4.7 doesn't support thread_local either. +// Finally, iOS/ARM doesn't have support for it either, and g++/ARM allows it to compile but it's unconfirmed to actually work +#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && (!defined(__MINGW32__) && !defined(__MINGW64__) || !defined(__WINPTHREADS_VERSION)) && (!defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) && (!defined(__APPLE__) || !TARGET_OS_IPHONE) && !defined(__arm__) && !defined(_M_ARM) && !defined(__aarch64__) && !defined(__MVS__) +// Assume `thread_local` is fully supported in all other C++11 compilers/platforms +#define WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED // tentatively enabled for now; years ago several users report having problems with it on +#endif +#endif +#endif + +// VS2012 doesn't support deleted functions. +// In this case, we declare the function normally but don't define it. A link error will be generated if the function is called. +#ifndef WPI_CQ_DELETE_FUNCTION +#if defined(_MSC_VER) && _MSC_VER < 1800 +#define WPI_CQ_DELETE_FUNCTION +#else +#define WPI_CQ_DELETE_FUNCTION = delete +#endif +#endif + +namespace wpi { namespace details { +#ifndef WPI_CQ_ALIGNAS +// VS2013 doesn't support alignas or alignof, and align() requires a constant literal +#if defined(_MSC_VER) && _MSC_VER <= 1800 +#define WPI_CQ_ALIGNAS(alignment) __declspec(align(alignment)) +#define WPI_CQ_ALIGNOF(obj) __alignof(obj) +#define WPI_CQ_ALIGNED_TYPE_LIKE(T, obj) typename details::Vs2013Aligned::value, T>::type + template struct Vs2013Aligned { }; // default, unsupported alignment + template struct Vs2013Aligned<1, T> { typedef __declspec(align(1)) T type; }; + template struct Vs2013Aligned<2, T> { typedef __declspec(align(2)) T type; }; + template struct Vs2013Aligned<4, T> { typedef __declspec(align(4)) T type; }; + template struct Vs2013Aligned<8, T> { typedef __declspec(align(8)) T type; }; + template struct Vs2013Aligned<16, T> { typedef __declspec(align(16)) T type; }; + template struct Vs2013Aligned<32, T> { typedef __declspec(align(32)) T type; }; + template struct Vs2013Aligned<64, T> { typedef __declspec(align(64)) T type; }; + template struct Vs2013Aligned<128, T> { typedef __declspec(align(128)) T type; }; + template struct Vs2013Aligned<256, T> { typedef __declspec(align(256)) T type; }; +#else + template struct identity { typedef T type; }; +#define WPI_CQ_ALIGNAS(alignment) alignas(alignment) +#define WPI_CQ_ALIGNOF(obj) alignof(obj) +#define WPI_CQ_ALIGNED_TYPE_LIKE(T, obj) alignas(alignof(obj)) typename details::identity::type +#endif +#endif +} } + + +// TSAN can false report races in lock-free code. To enable TSAN to be used from projects that use this one, +// we can apply per-function compile-time suppression. +// See https://clang.llvm.org/docs/ThreadSanitizer.html#has-feature-thread-sanitizer +#define WPI_CQ_NO_TSAN +#if defined(__has_feature) + #if __has_feature(thread_sanitizer) + #undef WPI_CQ_NO_TSAN + #define WPI_CQ_NO_TSAN __attribute__((no_sanitize("thread"))) + #endif // TSAN +#endif // TSAN + +// Compiler-specific likely/unlikely hints +namespace wpi { namespace details { +#if defined(__GNUC__) + static inline bool (likely)(bool x) { return __builtin_expect((x), true); } + static inline bool (unlikely)(bool x) { return __builtin_expect((x), false); } +#else + static inline bool (likely)(bool x) { return x; } + static inline bool (unlikely)(bool x) { return x; } +#endif +} } + +#ifdef WPI_CQ_QUEUE_INTERNAL_DEBUG +#include "internal/concurrentqueue_internal_debug.h" +#endif + +namespace wpi { +namespace details { + template + struct const_numeric_max { + static_assert(std::is_integral::value, "const_numeric_max can only be used with integers"); + static const T value = std::numeric_limits::is_signed + ? (static_cast(1) << (sizeof(T) * CHAR_BIT - 1)) - static_cast(1) + : static_cast(-1); + }; + +#if defined(__GLIBCXX__) + typedef ::max_align_t std_max_align_t; // libstdc++ forgot to add it to std:: for a while +#else + typedef std::max_align_t std_max_align_t; // Others (e.g. MSVC) insist it can *only* be accessed via std:: +#endif + + // Some platforms have incorrectly set max_align_t to a type with <8 bytes alignment even while supporting + // 8-byte aligned scalar values (*cough* 32-bit iOS). Work around this with our own union. See issue #64. + typedef union { + std_max_align_t x; + long long y; + void* z; + } max_align_t; +} + +// Default traits for the ConcurrentQueue. To change some of the +// traits without re-implementing all of them, inherit from this +// struct and shadow the declarations you wish to be different; +// since the traits are used as a template type parameter, the +// shadowed declarations will be used where defined, and the defaults +// otherwise. +struct ConcurrentQueueDefaultTraits +{ + // General-purpose size type. std::size_t is strongly recommended. + typedef std::size_t size_t; + + // The type used for the enqueue and dequeue indices. Must be at least as + // large as size_t. Should be significantly larger than the number of elements + // you expect to hold at once, especially if you have a high turnover rate; + // for example, on 32-bit x86, if you expect to have over a hundred million + // elements or pump several million elements through your queue in a very + // short space of time, using a 32-bit type *may* trigger a race condition. + // A 64-bit int type is recommended in that case, and in practice will + // prevent a race condition no matter the usage of the queue. Note that + // whether the queue is lock-free with a 64-int type depends on the whether + // std::atomic is lock-free, which is platform-specific. + typedef std::size_t index_t; + + // Internally, all elements are enqueued and dequeued from multi-element + // blocks; this is the smallest controllable unit. If you expect few elements + // but many producers, a smaller block size should be favoured. For few producers + // and/or many elements, a larger block size is preferred. A sane default + // is provided. Must be a power of 2. + static const size_t BLOCK_SIZE = 32; + + // For explicit producers (i.e. when using a producer token), the block is + // checked for being empty by iterating through a list of flags, one per element. + // For large block sizes, this is too inefficient, and switching to an atomic + // counter-based approach is faster. The switch is made for block sizes strictly + // larger than this threshold. + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = 32; + + // How many full blocks can be expected for a single explicit producer? This should + // reflect that number's maximum for optimal performance. Must be a power of 2. + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = 32; + + // How many full blocks can be expected for a single implicit producer? This should + // reflect that number's maximum for optimal performance. Must be a power of 2. + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = 32; + + // The initial size of the hash table mapping thread IDs to implicit producers. + // Note that the hash is resized every time it becomes half full. + // Must be a power of two, and either 0 or at least 1. If 0, implicit production + // (using the enqueue methods without an explicit producer token) is disabled. + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = 32; + + // Controls the number of items that an explicit consumer (i.e. one with a token) + // must consume before it causes all consumers to rotate and move on to the next + // internal queue. + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = 256; + + // The maximum number of elements (inclusive) that can be enqueued to a sub-queue. + // Enqueue operations that would cause this limit to be surpassed will fail. Note + // that this limit is enforced at the block level (for performance reasons), i.e. + // it's rounded up to the nearest block size. + static const size_t MAX_SUBQUEUE_SIZE = details::const_numeric_max::value; + + // The number of times to spin before sleeping when waiting on a semaphore. + // Recommended values are on the order of 1000-10000 unless the number of + // consumer threads exceeds the number of idle cores (in which case try 0-100). + // Only affects instances of the BlockingConcurrentQueue. + static const int MAX_SEMA_SPINS = 10000; + + // Whether to recycle dynamically-allocated blocks into an internal free list or + // not. If false, only pre-allocated blocks (controlled by the constructor + // arguments) will be recycled, and all others will be `free`d back to the heap. + // Note that blocks consumed by explicit producers are only freed on destruction + // of the queue (not following destruction of the token) regardless of this trait. + static const bool RECYCLE_ALLOCATED_BLOCKS = false; + + +#ifndef MCDBGQ_USE_RELACY + // Memory allocation can be customized if needed. + // malloc should return nullptr on failure, and handle alignment like std::malloc. +#if defined(malloc) || defined(free) + // Gah, this is 2015, stop defining macros that break standard code already! + // Work around malloc/free being special macros: + static inline void* WORKAROUND_malloc(size_t size) { return malloc(size); } + static inline void WORKAROUND_free(void* ptr) { return free(ptr); } + static inline void* (malloc)(size_t size) { return WORKAROUND_malloc(size); } + static inline void (free)(void* ptr) { return WORKAROUND_free(ptr); } +#else + static inline void* malloc(size_t size) { return std::malloc(size); } + static inline void free(void* ptr) { return std::free(ptr); } +#endif +#else + // Debug versions when running under the Relacy race detector (ignore + // these in user code) + static inline void* malloc(size_t size) { return rl::rl_malloc(size, $); } + static inline void free(void* ptr) { return rl::rl_free(ptr, $); } +#endif +}; + + +// When producing or consuming many elements, the most efficient way is to: +// 1) Use one of the bulk-operation methods of the queue with a token +// 2) Failing that, use the bulk-operation methods without a token +// 3) Failing that, create a token and use that with the single-item methods +// 4) Failing that, use the single-parameter methods of the queue +// Having said that, don't create tokens willy-nilly -- ideally there should be +// a maximum of one token per thread (of each kind). +struct ProducerToken; +struct ConsumerToken; + +template class ConcurrentQueue; +template class BlockingConcurrentQueue; +class ConcurrentQueueTests; + + +namespace details +{ + struct ConcurrentQueueProducerTypelessBase + { + ConcurrentQueueProducerTypelessBase* next; + std::atomic inactive; + ProducerToken* token; + + ConcurrentQueueProducerTypelessBase() + : next(nullptr), inactive(false), token(nullptr) + { + } + }; + + template struct _hash_32_or_64 { + static inline std::uint32_t hash(std::uint32_t h) + { + // MurmurHash3 finalizer -- see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp + // Since the thread ID is already unique, all we really want to do is propagate that + // uniqueness evenly across all the bits, so that we can use a subset of the bits while + // reducing collisions significantly + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + return h ^ (h >> 16); + } + }; + template<> struct _hash_32_or_64<1> { + static inline std::uint64_t hash(std::uint64_t h) + { + h ^= h >> 33; + h *= 0xff51afd7ed558ccd; + h ^= h >> 33; + h *= 0xc4ceb9fe1a85ec53; + return h ^ (h >> 33); + } + }; + template struct hash_32_or_64 : public _hash_32_or_64<(size > 4)> { }; + + static inline size_t hash_thread_id(thread_id_t id) + { + static_assert(sizeof(thread_id_t) <= 8, "Expected a platform where thread IDs are at most 64-bit values"); + return static_cast(hash_32_or_64::thread_id_hash_t)>::hash( + thread_id_converter::prehash(id))); + } + + template + static inline bool circular_less_than(T a, T b) + { + static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "circular_less_than is intended to be used only with unsigned integer types"); + return static_cast(a - b) > static_cast(static_cast(1) << (static_cast(sizeof(T) * CHAR_BIT - 1))); + // Note: extra parens around rhs of operator<< is MSVC bug: https://developercommunity2.visualstudio.com/t/C4554-triggers-when-both-lhs-and-rhs-is/10034931 + // silencing the bug requires #pragma warning(disable: 4554) around the calling code and has no effect when done here. + } + + template + static inline char* align_for(char* ptr) + { + const std::size_t alignment = std::alignment_of::value; + return ptr + (alignment - (reinterpret_cast(ptr) % alignment)) % alignment; + } + + template + static inline T ceil_to_pow_2(T x) + { + static_assert(std::is_integral::value && !std::numeric_limits::is_signed, "ceil_to_pow_2 is intended to be used only with unsigned integer types"); + + // Adapted from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + for (std::size_t i = 1; i < sizeof(T); i <<= 1) { + x |= x >> (i << 3); + } + ++x; + return x; + } + + template + static inline void swap_relaxed(std::atomic& left, std::atomic& right) + { + T temp = std::move(left.load(std::memory_order_relaxed)); + left.store(std::move(right.load(std::memory_order_relaxed)), std::memory_order_relaxed); + right.store(std::move(temp), std::memory_order_relaxed); + } + + template + static inline T const& nomove(T const& x) + { + return x; + } + + template + struct nomove_if + { + template + static inline T const& eval(T const& x) + { + return x; + } + }; + + template<> + struct nomove_if + { + template + static inline auto eval(U&& x) + -> decltype(std::forward(x)) + { + return std::forward(x); + } + }; + + template + static inline auto deref_noexcept(It& it) WPI_CQ_NOEXCEPT -> decltype(*it) + { + return *it; + } + +#if defined(__clang__) || !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + template struct is_trivially_destructible : std::is_trivially_destructible { }; +#else + template struct is_trivially_destructible : std::has_trivial_destructor { }; +#endif + +#ifdef WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED +#ifdef MCDBGQ_USE_RELACY + typedef RelacyThreadExitListener ThreadExitListener; + typedef RelacyThreadExitNotifier ThreadExitNotifier; +#else + class ThreadExitNotifier; + + struct ThreadExitListener + { + typedef void (*callback_t)(void*); + callback_t callback; + void* userData; + + ThreadExitListener* next; // reserved for use by the ThreadExitNotifier + ThreadExitNotifier* chain; // reserved for use by the ThreadExitNotifier + }; + + class ThreadExitNotifier + { + public: + static void subscribe(ThreadExitListener* listener) + { + auto& tlsInst = instance(); + std::lock_guard guard(mutex()); + listener->next = tlsInst.tail; + listener->chain = &tlsInst; + tlsInst.tail = listener; + } + + static void unsubscribe(ThreadExitListener* listener) + { + std::lock_guard guard(mutex()); + if (!listener->chain) { + return; // race with ~ThreadExitNotifier + } + auto& tlsInst = *listener->chain; + listener->chain = nullptr; + ThreadExitListener** prev = &tlsInst.tail; + for (auto ptr = tlsInst.tail; ptr != nullptr; ptr = ptr->next) { + if (ptr == listener) { + *prev = ptr->next; + break; + } + prev = &ptr->next; + } + } + + private: + ThreadExitNotifier() : tail(nullptr) { } + ThreadExitNotifier(ThreadExitNotifier const&) WPI_CQ_DELETE_FUNCTION; + ThreadExitNotifier& operator=(ThreadExitNotifier const&) WPI_CQ_DELETE_FUNCTION; + + ~ThreadExitNotifier() + { + // This thread is about to exit, let everyone know! + assert(this == &instance() && "If this assert fails, you likely have a buggy compiler! Change the preprocessor conditions such that WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED is no longer defined."); + std::lock_guard guard(mutex()); + for (auto ptr = tail; ptr != nullptr; ptr = ptr->next) { + ptr->chain = nullptr; + ptr->callback(ptr->userData); + } + } + + // Thread-local + static inline ThreadExitNotifier& instance() + { + static thread_local ThreadExitNotifier notifier; + return notifier; + } + + static inline std::mutex& mutex() + { + // Must be static because the ThreadExitNotifier could be destroyed while unsubscribe is called + static std::mutex mutex; + return mutex; + } + + private: + ThreadExitListener* tail; + }; +#endif +#endif + + template struct static_is_lock_free_num { enum { value = 0 }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_CHAR_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_SHORT_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_INT_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_LONG_LOCK_FREE }; }; + template<> struct static_is_lock_free_num { enum { value = ATOMIC_LLONG_LOCK_FREE }; }; + template struct static_is_lock_free : static_is_lock_free_num::type> { }; + template<> struct static_is_lock_free { enum { value = ATOMIC_BOOL_LOCK_FREE }; }; + template struct static_is_lock_free { enum { value = ATOMIC_POINTER_LOCK_FREE }; }; +} + + +struct ProducerToken +{ + template + explicit ProducerToken(ConcurrentQueue& queue); + + template + explicit ProducerToken(BlockingConcurrentQueue& queue); + + ProducerToken(ProducerToken&& other) WPI_CQ_NOEXCEPT + : producer(other.producer) + { + other.producer = nullptr; + if (producer != nullptr) { + producer->token = this; + } + } + + inline ProducerToken& operator=(ProducerToken&& other) WPI_CQ_NOEXCEPT + { + swap(other); + return *this; + } + + void swap(ProducerToken& other) WPI_CQ_NOEXCEPT + { + std::swap(producer, other.producer); + if (producer != nullptr) { + producer->token = this; + } + if (other.producer != nullptr) { + other.producer->token = &other; + } + } + + // A token is always valid unless: + // 1) Memory allocation failed during construction + // 2) It was moved via the move constructor + // (Note: assignment does a swap, leaving both potentially valid) + // 3) The associated queue was destroyed + // Note that if valid() returns true, that only indicates + // that the token is valid for use with a specific queue, + // but not which one; that's up to the user to track. + inline bool valid() const { return producer != nullptr; } + + ~ProducerToken() + { + if (producer != nullptr) { + producer->token = nullptr; + producer->inactive.store(true, std::memory_order_release); + } + } + + // Disable copying and assignment + ProducerToken(ProducerToken const&) WPI_CQ_DELETE_FUNCTION; + ProducerToken& operator=(ProducerToken const&) WPI_CQ_DELETE_FUNCTION; + +private: + template friend class ConcurrentQueue; + friend class ConcurrentQueueTests; + +protected: + details::ConcurrentQueueProducerTypelessBase* producer; +}; + + +struct ConsumerToken +{ + template + explicit ConsumerToken(ConcurrentQueue& q); + + template + explicit ConsumerToken(BlockingConcurrentQueue& q); + + ConsumerToken(ConsumerToken&& other) WPI_CQ_NOEXCEPT + : initialOffset(other.initialOffset), lastKnownGlobalOffset(other.lastKnownGlobalOffset), itemsConsumedFromCurrent(other.itemsConsumedFromCurrent), currentProducer(other.currentProducer), desiredProducer(other.desiredProducer) + { + } + + inline ConsumerToken& operator=(ConsumerToken&& other) WPI_CQ_NOEXCEPT + { + swap(other); + return *this; + } + + void swap(ConsumerToken& other) WPI_CQ_NOEXCEPT + { + std::swap(initialOffset, other.initialOffset); + std::swap(lastKnownGlobalOffset, other.lastKnownGlobalOffset); + std::swap(itemsConsumedFromCurrent, other.itemsConsumedFromCurrent); + std::swap(currentProducer, other.currentProducer); + std::swap(desiredProducer, other.desiredProducer); + } + + // Disable copying and assignment + ConsumerToken(ConsumerToken const&) WPI_CQ_DELETE_FUNCTION; + ConsumerToken& operator=(ConsumerToken const&) WPI_CQ_DELETE_FUNCTION; + +private: + template friend class ConcurrentQueue; + friend class ConcurrentQueueTests; + +private: // but shared with ConcurrentQueue + std::uint32_t initialOffset; + std::uint32_t lastKnownGlobalOffset; + std::uint32_t itemsConsumedFromCurrent; + details::ConcurrentQueueProducerTypelessBase* currentProducer; + details::ConcurrentQueueProducerTypelessBase* desiredProducer; +}; + +// Need to forward-declare this swap because it's in a namespace. +// See http://stackoverflow.com/questions/4492062/why-does-a-c-friend-class-need-a-forward-declaration-only-in-other-namespaces +template +inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) WPI_CQ_NOEXCEPT; + + +template +class ConcurrentQueue +{ +public: + typedef ::wpi::ProducerToken producer_token_t; + typedef ::wpi::ConsumerToken consumer_token_t; + + typedef typename Traits::index_t index_t; + typedef typename Traits::size_t size_t; + + static const size_t BLOCK_SIZE = static_cast(Traits::BLOCK_SIZE); + static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = static_cast(Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD); + static const size_t EXPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::EXPLICIT_INITIAL_INDEX_SIZE); + static const size_t IMPLICIT_INITIAL_INDEX_SIZE = static_cast(Traits::IMPLICIT_INITIAL_INDEX_SIZE); + static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = static_cast(Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE); + static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = static_cast(Traits::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE); +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4307) // + integral constant overflow (that's what the ternary expression is for!) +#pragma warning(disable: 4309) // static_cast: Truncation of constant value +#endif + static const size_t MAX_SUBQUEUE_SIZE = (details::const_numeric_max::value - static_cast(Traits::MAX_SUBQUEUE_SIZE) < BLOCK_SIZE) ? details::const_numeric_max::value : ((static_cast(Traits::MAX_SUBQUEUE_SIZE) + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::size_t must be an unsigned integral type"); + static_assert(!std::numeric_limits::is_signed && std::is_integral::value, "Traits::index_t must be an unsigned integral type"); + static_assert(sizeof(index_t) >= sizeof(size_t), "Traits::index_t must be at least as wide as Traits::size_t"); + static_assert((BLOCK_SIZE > 1) && !(BLOCK_SIZE & (BLOCK_SIZE - 1)), "Traits::BLOCK_SIZE must be a power of 2 (and at least 2)"); + static_assert((EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD > 1) && !(EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD & (EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD - 1)), "Traits::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD must be a power of 2 (and greater than 1)"); + static_assert((EXPLICIT_INITIAL_INDEX_SIZE > 1) && !(EXPLICIT_INITIAL_INDEX_SIZE & (EXPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::EXPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); + static_assert((IMPLICIT_INITIAL_INDEX_SIZE > 1) && !(IMPLICIT_INITIAL_INDEX_SIZE & (IMPLICIT_INITIAL_INDEX_SIZE - 1)), "Traits::IMPLICIT_INITIAL_INDEX_SIZE must be a power of 2 (and greater than 1)"); + static_assert((INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) || !(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE & (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE - 1)), "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be a power of 2"); + static_assert(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0 || INITIAL_IMPLICIT_PRODUCER_HASH_SIZE >= 1, "Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE must be at least 1 (or 0 to disable implicit enqueueing)"); + +public: + // Creates a queue with at least `capacity` element slots; note that the + // actual number of elements that can be inserted without additional memory + // allocation depends on the number of producers and the block size (e.g. if + // the block size is equal to `capacity`, only a single block will be allocated + // up-front, which means only a single producer will be able to enqueue elements + // without an extra allocation -- blocks aren't shared between producers). + // This method is not thread safe -- it is up to the user to ensure that the + // queue is fully constructed before it starts being used by other threads (this + // includes making the memory effects of construction visible, possibly with a + // memory barrier). + explicit ConcurrentQueue(size_t capacity = 32 * BLOCK_SIZE) + : producerListTail(nullptr), + producerCount(0), + initialBlockPoolIndex(0), + nextExplicitConsumerId(0), + globalExplicitConsumerOffset(0) + { + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + populate_initial_block_list(capacity / BLOCK_SIZE + ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1)); + +#ifdef WPI_CQ_QUEUE_INTERNAL_DEBUG + // Track all the producers using a fully-resolved typed list for + // each kind; this makes it possible to debug them starting from + // the root queue object (otherwise wacky casts are needed that + // don't compile in the debugger's expression evaluator). + explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + } + + // Computes the correct amount of pre-allocated blocks for you based + // on the minimum number of elements you want available at any given + // time, and the maximum concurrent number of each type of producer. + ConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers) + : producerListTail(nullptr), + producerCount(0), + initialBlockPoolIndex(0), + nextExplicitConsumerId(0), + globalExplicitConsumerOffset(0) + { + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + size_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * (maxExplicitProducers + 1) + 2 * (maxExplicitProducers + maxImplicitProducers); + populate_initial_block_list(blocks); + +#ifdef WPI_CQ_QUEUE_INTERNAL_DEBUG + explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + } + + // Note: The queue should not be accessed concurrently while it's + // being deleted. It's up to the user to synchronize this. + // This method is not thread safe. + ~ConcurrentQueue() + { + // Destroy producers + auto ptr = producerListTail.load(std::memory_order_relaxed); + while (ptr != nullptr) { + auto next = ptr->next_prod(); + if (ptr->token != nullptr) { + ptr->token->producer = nullptr; + } + destroy(ptr); + ptr = next; + } + + // Destroy implicit producer hash tables + WPI_CQ_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE != 0) { + auto hash = implicitProducerHash.load(std::memory_order_relaxed); + while (hash != nullptr) { + auto prev = hash->prev; + if (prev != nullptr) { // The last hash is part of this object and was not allocated dynamically + for (size_t i = 0; i != hash->capacity; ++i) { + hash->entries[i].~ImplicitProducerKVP(); + } + hash->~ImplicitProducerHash(); + (Traits::free)(hash); + } + hash = prev; + } + } + + // Destroy global free list + auto block = freeList.head_unsafe(); + while (block != nullptr) { + auto next = block->freeListNext.load(std::memory_order_relaxed); + if (block->dynamicallyAllocated) { + destroy(block); + } + block = next; + } + + // Destroy initial free list + destroy_array(initialBlockPool, initialBlockPoolSize); + } + + // Disable copying and copy assignment + ConcurrentQueue(ConcurrentQueue const&) WPI_CQ_DELETE_FUNCTION; + ConcurrentQueue& operator=(ConcurrentQueue const&) WPI_CQ_DELETE_FUNCTION; + + // Moving is supported, but note that it is *not* a thread-safe operation. + // Nobody can use the queue while it's being moved, and the memory effects + // of that move must be propagated to other threads before they can use it. + // Note: When a queue is moved, its tokens are still valid but can only be + // used with the destination queue (i.e. semantically they are moved along + // with the queue itself). + ConcurrentQueue(ConcurrentQueue&& other) WPI_CQ_NOEXCEPT + : producerListTail(other.producerListTail.load(std::memory_order_relaxed)), + producerCount(other.producerCount.load(std::memory_order_relaxed)), + initialBlockPoolIndex(other.initialBlockPoolIndex.load(std::memory_order_relaxed)), + initialBlockPool(other.initialBlockPool), + initialBlockPoolSize(other.initialBlockPoolSize), + freeList(std::move(other.freeList)), + nextExplicitConsumerId(other.nextExplicitConsumerId.load(std::memory_order_relaxed)), + globalExplicitConsumerOffset(other.globalExplicitConsumerOffset.load(std::memory_order_relaxed)) + { + // Move the other one into this, and leave the other one as an empty queue + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + populate_initial_implicit_producer_hash(); + swap_implicit_producer_hashes(other); + + other.producerListTail.store(nullptr, std::memory_order_relaxed); + other.producerCount.store(0, std::memory_order_relaxed); + other.nextExplicitConsumerId.store(0, std::memory_order_relaxed); + other.globalExplicitConsumerOffset.store(0, std::memory_order_relaxed); + +#ifdef WPI_CQ_QUEUE_INTERNAL_DEBUG + explicitProducers.store(other.explicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); + other.explicitProducers.store(nullptr, std::memory_order_relaxed); + implicitProducers.store(other.implicitProducers.load(std::memory_order_relaxed), std::memory_order_relaxed); + other.implicitProducers.store(nullptr, std::memory_order_relaxed); +#endif + + other.initialBlockPoolIndex.store(0, std::memory_order_relaxed); + other.initialBlockPoolSize = 0; + other.initialBlockPool = nullptr; + + reown_producers(); + } + + inline ConcurrentQueue& operator=(ConcurrentQueue&& other) WPI_CQ_NOEXCEPT + { + return swap_internal(other); + } + + // Swaps this queue's state with the other's. Not thread-safe. + // Swapping two queues does not invalidate their tokens, however + // the tokens that were created for one queue must be used with + // only the swapped queue (i.e. the tokens are tied to the + // queue's movable state, not the object itself). + inline void swap(ConcurrentQueue& other) WPI_CQ_NOEXCEPT + { + swap_internal(other); + } + +private: + ConcurrentQueue& swap_internal(ConcurrentQueue& other) + { + if (this == &other) { + return *this; + } + + details::swap_relaxed(producerListTail, other.producerListTail); + details::swap_relaxed(producerCount, other.producerCount); + details::swap_relaxed(initialBlockPoolIndex, other.initialBlockPoolIndex); + std::swap(initialBlockPool, other.initialBlockPool); + std::swap(initialBlockPoolSize, other.initialBlockPoolSize); + freeList.swap(other.freeList); + details::swap_relaxed(nextExplicitConsumerId, other.nextExplicitConsumerId); + details::swap_relaxed(globalExplicitConsumerOffset, other.globalExplicitConsumerOffset); + + swap_implicit_producer_hashes(other); + + reown_producers(); + other.reown_producers(); + +#ifdef WPI_CQ_QUEUE_INTERNAL_DEBUG + details::swap_relaxed(explicitProducers, other.explicitProducers); + details::swap_relaxed(implicitProducers, other.implicitProducers); +#endif + + return *this; + } + +public: + // Enqueues a single item (by copying it). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T const& item) + { + WPI_CQ_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(item); + } + + // Enqueues a single item (by moving it, if possible). + // Allocates memory if required. Only fails if memory allocation fails (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0, + // or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(T&& item) + { + WPI_CQ_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(std::move(item)); + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T const& item) + { + return inner_enqueue(token, item); + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails (or + // Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Thread-safe. + inline bool enqueue(producer_token_t const& token, T&& item) + { + return inner_enqueue(token, std::move(item)); + } + + // Enqueues several items. + // Allocates memory if required. Only fails if memory allocation fails (or + // implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved instead of copied. + // Thread-safe. + template + bool enqueue_bulk(It itemFirst, size_t count) + { + WPI_CQ_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue_bulk(itemFirst, count); + } + + // Enqueues several items using an explicit producer token. + // Allocates memory if required. Only fails if memory allocation fails + // (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return inner_enqueue_bulk(token, itemFirst, count); + } + + // Enqueues a single item (by copying it). + // Does not allocate memory. Fails if not enough room to enqueue (or implicit + // production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE + // is 0). + // Thread-safe. + inline bool try_enqueue(T const& item) + { + WPI_CQ_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(item); + } + + // Enqueues a single item (by moving it, if possible). + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Thread-safe. + inline bool try_enqueue(T&& item) + { + WPI_CQ_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue(std::move(item)); + } + + // Enqueues a single item (by copying it) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T const& item) + { + return inner_enqueue(token, item); + } + + // Enqueues a single item (by moving it, if possible) using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Thread-safe. + inline bool try_enqueue(producer_token_t const& token, T&& item) + { + return inner_enqueue(token, std::move(item)); + } + + // Enqueues several items. + // Does not allocate memory (except for one-time implicit producer). + // Fails if not enough room to enqueue (or implicit production is + // disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0). + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool try_enqueue_bulk(It itemFirst, size_t count) + { + WPI_CQ_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) return false; + else return inner_enqueue_bulk(itemFirst, count); + } + + // Enqueues several items using an explicit producer token. + // Does not allocate memory. Fails if not enough room to enqueue. + // Note: Use std::make_move_iterator if the elements should be moved + // instead of copied. + // Thread-safe. + template + bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return inner_enqueue_bulk(token, itemFirst, count); + } + + + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + bool try_dequeue(U& item) + { + // Instead of simply trying each producer in turn (which could cause needless contention on the first + // producer), we score them heuristically. + size_t nonEmptyCount = 0; + ProducerBase* best = nullptr; + size_t bestSize = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); nonEmptyCount < 3 && ptr != nullptr; ptr = ptr->next_prod()) { + auto size = ptr->size_approx(); + if (size > 0) { + if (size > bestSize) { + bestSize = size; + best = ptr; + } + ++nonEmptyCount; + } + } + + // If there was at least one non-empty queue but it appears empty at the time + // we try to dequeue from it, we need to make sure every queue's been tried + if (nonEmptyCount > 0) { + if ((details::likely)(best->dequeue(item))) { + return true; + } + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr != best && ptr->dequeue(item)) { + return true; + } + } + } + return false; + } + + // Attempts to dequeue from the queue. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // This differs from the try_dequeue(item) method in that this one does + // not attempt to reduce contention by interleaving the order that producer + // streams are dequeued from. So, using this method can reduce overall throughput + // under contention, but will give more predictable results in single-threaded + // consumer scenarios. This is mostly only useful for internal unit tests. + // Never allocates. Thread-safe. + template + bool try_dequeue_non_interleaved(U& item) + { + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr->dequeue(item)) { + return true; + } + } + return false; + } + + // Attempts to dequeue from the queue using an explicit consumer token. + // Returns false if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + bool try_dequeue(consumer_token_t& token, U& item) + { + // The idea is roughly as follows: + // Every 256 items from one producer, make everyone rotate (increase the global offset) -> this means the highest efficiency consumer dictates the rotation speed of everyone else, more or less + // If you see that the global offset has changed, you must reset your consumption counter and move to your designated place + // If there's no items where you're supposed to be, keep moving until you find a producer with some items + // If the global offset has not changed but you've run out of items to consume, move over from your current position until you find an producer with something in it + + if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { + if (!update_current_producer_after_rotation(token)) { + return false; + } + } + + // If there was at least one non-empty queue but it appears empty at the time + // we try to dequeue from it, we need to make sure every queue's been tried + if (static_cast(token.currentProducer)->dequeue(item)) { + if (++token.itemsConsumedFromCurrent == EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { + globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); + } + return true; + } + + auto tail = producerListTail.load(std::memory_order_acquire); + auto ptr = static_cast(token.currentProducer)->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + while (ptr != static_cast(token.currentProducer)) { + if (ptr->dequeue(item)) { + token.currentProducer = ptr; + token.itemsConsumedFromCurrent = 1; + return true; + } + ptr = ptr->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + } + return false; + } + + // Attempts to dequeue several elements from the queue. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + size_t try_dequeue_bulk(It itemFirst, size_t max) + { + size_t count = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + count += ptr->dequeue_bulk(itemFirst, max - count); + if (count == max) { + break; + } + } + return count; + } + + // Attempts to dequeue several elements from the queue using an explicit consumer token. + // Returns the number of items actually dequeued. + // Returns 0 if all producer streams appeared empty at the time they + // were checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max) + { + if (token.desiredProducer == nullptr || token.lastKnownGlobalOffset != globalExplicitConsumerOffset.load(std::memory_order_relaxed)) { + if (!update_current_producer_after_rotation(token)) { + return 0; + } + } + + size_t count = static_cast(token.currentProducer)->dequeue_bulk(itemFirst, max); + if (count == max) { + if ((token.itemsConsumedFromCurrent += static_cast(max)) >= EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE) { + globalExplicitConsumerOffset.fetch_add(1, std::memory_order_relaxed); + } + return max; + } + token.itemsConsumedFromCurrent += static_cast(count); + max -= count; + + auto tail = producerListTail.load(std::memory_order_acquire); + auto ptr = static_cast(token.currentProducer)->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + while (ptr != static_cast(token.currentProducer)) { + auto dequeued = ptr->dequeue_bulk(itemFirst, max); + count += dequeued; + if (dequeued != 0) { + token.currentProducer = ptr; + token.itemsConsumedFromCurrent = static_cast(dequeued); + } + if (dequeued == max) { + break; + } + max -= dequeued; + ptr = ptr->next_prod(); + if (ptr == nullptr) { + ptr = tail; + } + } + return count; + } + + + + // Attempts to dequeue from a specific producer's inner queue. + // If you happen to know which producer you want to dequeue from, this + // is significantly faster than using the general-case try_dequeue methods. + // Returns false if the producer's queue appeared empty at the time it + // was checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline bool try_dequeue_from_producer(producer_token_t const& producer, U& item) + { + return static_cast(producer.producer)->dequeue(item); + } + + // Attempts to dequeue several elements from a specific producer's inner queue. + // Returns the number of items actually dequeued. + // If you happen to know which producer you want to dequeue from, this + // is significantly faster than using the general-case try_dequeue methods. + // Returns 0 if the producer's queue appeared empty at the time it + // was checked (so, the queue is likely but not guaranteed to be empty). + // Never allocates. Thread-safe. + template + inline size_t try_dequeue_bulk_from_producer(producer_token_t const& producer, It itemFirst, size_t max) + { + return static_cast(producer.producer)->dequeue_bulk(itemFirst, max); + } + + + // Returns an estimate of the total number of elements currently in the queue. This + // estimate is only accurate if the queue has completely stabilized before it is called + // (i.e. all enqueue and dequeue operations have completed and their memory effects are + // visible on the calling thread, and no further operations start while this method is + // being called). + // Thread-safe. + size_t size_approx() const + { + size_t size = 0; + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + size += ptr->size_approx(); + } + return size; + } + + + // Returns true if the underlying atomic variables used by + // the queue are lock-free (they should be on most platforms). + // Thread-safe. + static constexpr bool is_lock_free() + { + return + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::value == 2 && + details::static_is_lock_free::thread_id_numeric_size_t>::value == 2; + } + + +private: + friend struct ProducerToken; + friend struct ConsumerToken; + struct ExplicitProducer; + friend struct ExplicitProducer; + struct ImplicitProducer; + friend struct ImplicitProducer; + friend class ConcurrentQueueTests; + + enum AllocationMode { CanAlloc, CannotAlloc }; + + + /////////////////////////////// + // Queue methods + /////////////////////////////// + + template + inline bool inner_enqueue(producer_token_t const& token, U&& element) + { + return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue(std::forward(element)); + } + + template + inline bool inner_enqueue(U&& element) + { + auto producer = get_or_add_implicit_producer(); + return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue(std::forward(element)); + } + + template + inline bool inner_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count) + { + return static_cast(token.producer)->ConcurrentQueue::ExplicitProducer::template enqueue_bulk(itemFirst, count); + } + + template + inline bool inner_enqueue_bulk(It itemFirst, size_t count) + { + auto producer = get_or_add_implicit_producer(); + return producer == nullptr ? false : producer->ConcurrentQueue::ImplicitProducer::template enqueue_bulk(itemFirst, count); + } + + inline bool update_current_producer_after_rotation(consumer_token_t& token) + { + // Ah, there's been a rotation, figure out where we should be! + auto tail = producerListTail.load(std::memory_order_acquire); + if (token.desiredProducer == nullptr && tail == nullptr) { + return false; + } + auto prodCount = producerCount.load(std::memory_order_relaxed); + auto globalOffset = globalExplicitConsumerOffset.load(std::memory_order_relaxed); + if ((details::unlikely)(token.desiredProducer == nullptr)) { + // Aha, first time we're dequeueing anything. + // Figure out our local position + // Note: offset is from start, not end, but we're traversing from end -- subtract from count first + std::uint32_t offset = prodCount - 1 - (token.initialOffset % prodCount); + token.desiredProducer = tail; + for (std::uint32_t i = 0; i != offset; ++i) { + token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); + if (token.desiredProducer == nullptr) { + token.desiredProducer = tail; + } + } + } + + std::uint32_t delta = globalOffset - token.lastKnownGlobalOffset; + if (delta >= prodCount) { + delta = delta % prodCount; + } + for (std::uint32_t i = 0; i != delta; ++i) { + token.desiredProducer = static_cast(token.desiredProducer)->next_prod(); + if (token.desiredProducer == nullptr) { + token.desiredProducer = tail; + } + } + + token.lastKnownGlobalOffset = globalOffset; + token.currentProducer = token.desiredProducer; + token.itemsConsumedFromCurrent = 0; + return true; + } + + + /////////////////////////// + // Free list + /////////////////////////// + + template + struct FreeListNode + { + FreeListNode() : freeListRefs(0), freeListNext(nullptr) { } + + std::atomic freeListRefs; + std::atomic freeListNext; + }; + + // A simple CAS-based lock-free free list. Not the fastest thing in the world under heavy contention, but + // simple and correct (assuming nodes are never freed until after the free list is destroyed), and fairly + // speedy under low contention. + template // N must inherit FreeListNode or have the same fields (and initialization of them) + struct FreeList + { + FreeList() : freeListHead(nullptr) { } + FreeList(FreeList&& other) : freeListHead(other.freeListHead.load(std::memory_order_relaxed)) { other.freeListHead.store(nullptr, std::memory_order_relaxed); } + void swap(FreeList& other) { details::swap_relaxed(freeListHead, other.freeListHead); } + + FreeList(FreeList const&) WPI_CQ_DELETE_FUNCTION; + FreeList& operator=(FreeList const&) WPI_CQ_DELETE_FUNCTION; + + inline void add(N* node) + { +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugLock lock(mutex); +#endif + // We know that the should-be-on-freelist bit is 0 at this point, so it's safe to + // set it using a fetch_add + if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST, std::memory_order_acq_rel) == 0) { + // Oh look! We were the last ones referencing this node, and we know + // we want to add it to the free list, so let's do it! + add_knowing_refcount_is_zero(node); + } + } + + inline N* try_get() + { +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugLock lock(mutex); +#endif + auto head = freeListHead.load(std::memory_order_acquire); + while (head != nullptr) { + auto prevHead = head; + auto refs = head->freeListRefs.load(std::memory_order_relaxed); + if ((refs & REFS_MASK) == 0 || !head->freeListRefs.compare_exchange_strong(refs, refs + 1, std::memory_order_acquire, std::memory_order_relaxed)) { + head = freeListHead.load(std::memory_order_acquire); + continue; + } + + // Good, reference count has been incremented (it wasn't at zero), which means we can read the + // next and not worry about it changing between now and the time we do the CAS + auto next = head->freeListNext.load(std::memory_order_relaxed); + if (freeListHead.compare_exchange_strong(head, next, std::memory_order_acquire, std::memory_order_relaxed)) { + // Yay, got the node. This means it was on the list, which means shouldBeOnFreeList must be false no + // matter the refcount (because nobody else knows it's been taken off yet, it can't have been put back on). + assert((head->freeListRefs.load(std::memory_order_relaxed) & SHOULD_BE_ON_FREELIST) == 0); + + // Decrease refcount twice, once for our ref, and once for the list's ref + head->freeListRefs.fetch_sub(2, std::memory_order_release); + return head; + } + + // OK, the head must have changed on us, but we still need to decrease the refcount we increased. + // Note that we don't need to release any memory effects, but we do need to ensure that the reference + // count decrement happens-after the CAS on the head. + refs = prevHead->freeListRefs.fetch_sub(1, std::memory_order_acq_rel); + if (refs == SHOULD_BE_ON_FREELIST + 1) { + add_knowing_refcount_is_zero(prevHead); + } + } + + return nullptr; + } + + // Useful for traversing the list when there's no contention (e.g. to destroy remaining nodes) + N* head_unsafe() const { return freeListHead.load(std::memory_order_relaxed); } + + private: + inline void add_knowing_refcount_is_zero(N* node) + { + // Since the refcount is zero, and nobody can increase it once it's zero (except us, and we run + // only one copy of this method per node at a time, i.e. the single thread case), then we know + // we can safely change the next pointer of the node; however, once the refcount is back above + // zero, then other threads could increase it (happens under heavy contention, when the refcount + // goes to zero in between a load and a refcount increment of a node in try_get, then back up to + // something non-zero, then the refcount increment is done by the other thread) -- so, if the CAS + // to add the node to the actual list fails, decrease the refcount and leave the add operation to + // the next thread who puts the refcount back at zero (which could be us, hence the loop). + auto head = freeListHead.load(std::memory_order_relaxed); + while (true) { + node->freeListNext.store(head, std::memory_order_relaxed); + node->freeListRefs.store(1, std::memory_order_release); + if (!freeListHead.compare_exchange_strong(head, node, std::memory_order_release, std::memory_order_relaxed)) { + // Hmm, the add failed, but we can only try again when the refcount goes back to zero + if (node->freeListRefs.fetch_add(SHOULD_BE_ON_FREELIST - 1, std::memory_order_release) == 1) { + continue; + } + } + return; + } + } + + private: + // Implemented like a stack, but where node order doesn't matter (nodes are inserted out of order under contention) + std::atomic freeListHead; + + static const std::uint32_t REFS_MASK = 0x7FFFFFFF; + static const std::uint32_t SHOULD_BE_ON_FREELIST = 0x80000000; + +#ifdef MCDBGQ_NOLOCKFREE_FREELIST + debug::DebugMutex mutex; +#endif + }; + + + /////////////////////////// + // Block + /////////////////////////// + + enum InnerQueueContext { implicit_context = 0, explicit_context = 1 }; + + struct Block + { + Block() + : next(nullptr), elementsCompletelyDequeued(0), freeListRefs(0), freeListNext(nullptr), dynamicallyAllocated(true) + { +#ifdef MCDBGQ_TRACKMEM + owner = nullptr; +#endif + } + + template + inline bool is_empty() const + { + WPI_CQ_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Check flags + for (size_t i = 0; i < BLOCK_SIZE; ++i) { + if (!emptyFlags[i].load(std::memory_order_relaxed)) { + return false; + } + } + + // Aha, empty; make sure we have all other memory effects that happened before the empty flags were set + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + else { + // Check counter + if (elementsCompletelyDequeued.load(std::memory_order_relaxed) == BLOCK_SIZE) { + std::atomic_thread_fence(std::memory_order_acquire); + return true; + } + assert(elementsCompletelyDequeued.load(std::memory_order_relaxed) <= BLOCK_SIZE); + return false; + } + } + + // Returns true if the block is now empty (does not apply in explicit context) + template + inline bool set_empty(WPI_CQ_MAYBE_UNUSED index_t i) + { + WPI_CQ_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set flag + assert(!emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].load(std::memory_order_relaxed)); + emptyFlags[BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1))].store(true, std::memory_order_release); + return false; + } + else { + // Increment counter + auto prevVal = elementsCompletelyDequeued.fetch_add(1, std::memory_order_release); + assert(prevVal < BLOCK_SIZE); + return prevVal == BLOCK_SIZE - 1; + } + } + + // Sets multiple contiguous item statuses to 'empty' (assumes no wrapping and count > 0). + // Returns true if the block is now empty (does not apply in explicit context). + template + inline bool set_many_empty(WPI_CQ_MAYBE_UNUSED index_t i, size_t count) + { + WPI_CQ_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set flags + std::atomic_thread_fence(std::memory_order_release); + i = BLOCK_SIZE - 1 - static_cast(i & static_cast(BLOCK_SIZE - 1)) - count + 1; + for (size_t j = 0; j != count; ++j) { + assert(!emptyFlags[i + j].load(std::memory_order_relaxed)); + emptyFlags[i + j].store(true, std::memory_order_relaxed); + } + return false; + } + else { + // Increment counter + auto prevVal = elementsCompletelyDequeued.fetch_add(count, std::memory_order_release); + assert(prevVal + count <= BLOCK_SIZE); + return prevVal + count == BLOCK_SIZE; + } + } + + template + inline void set_all_empty() + { + WPI_CQ_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Set all flags + for (size_t i = 0; i != BLOCK_SIZE; ++i) { + emptyFlags[i].store(true, std::memory_order_relaxed); + } + } + else { + // Reset counter + elementsCompletelyDequeued.store(BLOCK_SIZE, std::memory_order_relaxed); + } + } + + template + inline void reset_empty() + { + WPI_CQ_CONSTEXPR_IF (context == explicit_context && BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD) { + // Reset flags + for (size_t i = 0; i != BLOCK_SIZE; ++i) { + emptyFlags[i].store(false, std::memory_order_relaxed); + } + } + else { + // Reset counter + elementsCompletelyDequeued.store(0, std::memory_order_relaxed); + } + } + + inline T* operator[](index_t idx) WPI_CQ_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } + inline T const* operator[](index_t idx) const WPI_CQ_NOEXCEPT { return static_cast(static_cast(elements)) + static_cast(idx & static_cast(BLOCK_SIZE - 1)); } + + private: + static_assert(std::alignment_of::value <= sizeof(T), "The queue does not support types with an alignment greater than their size at this time"); + WPI_CQ_ALIGNED_TYPE_LIKE(char[sizeof(T) * BLOCK_SIZE], T) elements; + public: + Block* next; + std::atomic elementsCompletelyDequeued; + std::atomic emptyFlags[BLOCK_SIZE <= EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD ? BLOCK_SIZE : 1]; + public: + std::atomic freeListRefs; + std::atomic freeListNext; + bool dynamicallyAllocated; // Perhaps a better name for this would be 'isNotPartOfInitialBlockPool' + +#ifdef MCDBGQ_TRACKMEM + void* owner; +#endif + }; + static_assert(std::alignment_of::value >= std::alignment_of::value, "Internal error: Blocks must be at least as aligned as the type they are wrapping"); + + +#ifdef MCDBGQ_TRACKMEM +public: + struct MemStats; +private: +#endif + + /////////////////////////// + // Producer base + /////////////////////////// + + struct ProducerBase : public details::ConcurrentQueueProducerTypelessBase + { + ProducerBase(ConcurrentQueue* parent_, bool isExplicit_) : + tailIndex(0), + headIndex(0), + dequeueOptimisticCount(0), + dequeueOvercommit(0), + tailBlock(nullptr), + isExplicit(isExplicit_), + parent(parent_) + { + } + + virtual ~ProducerBase() { } + + template + inline bool dequeue(U& element) + { + if (isExplicit) { + return static_cast(this)->dequeue(element); + } + else { + return static_cast(this)->dequeue(element); + } + } + + template + inline size_t dequeue_bulk(It& itemFirst, size_t max) + { + if (isExplicit) { + return static_cast(this)->dequeue_bulk(itemFirst, max); + } + else { + return static_cast(this)->dequeue_bulk(itemFirst, max); + } + } + + inline ProducerBase* next_prod() const { return static_cast(next); } + + inline size_t size_approx() const + { + auto tail = tailIndex.load(std::memory_order_relaxed); + auto head = headIndex.load(std::memory_order_relaxed); + return details::circular_less_than(head, tail) ? static_cast(tail - head) : 0; + } + + inline index_t getTail() const { return tailIndex.load(std::memory_order_relaxed); } + protected: + std::atomic tailIndex; // Where to enqueue to next + std::atomic headIndex; // Where to dequeue from next + + std::atomic dequeueOptimisticCount; + std::atomic dequeueOvercommit; + + Block* tailBlock; + + public: + bool isExplicit; + ConcurrentQueue* parent; + + protected: +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + /////////////////////////// + // Explicit queue + /////////////////////////// + + struct ExplicitProducer : public ProducerBase + { + explicit ExplicitProducer(ConcurrentQueue* parent_) : + ProducerBase(parent_, true), + blockIndex(nullptr), + pr_blockIndexSlotsUsed(0), + pr_blockIndexSize(EXPLICIT_INITIAL_INDEX_SIZE >> 1), + pr_blockIndexFront(0), + pr_blockIndexEntries(nullptr), + pr_blockIndexRaw(nullptr) + { + size_t poolBasedIndexSize = details::ceil_to_pow_2(parent_->initialBlockPoolSize) >> 1; + if (poolBasedIndexSize > pr_blockIndexSize) { + pr_blockIndexSize = poolBasedIndexSize; + } + + new_block_index(0); // This creates an index with double the number of current entries, i.e. EXPLICIT_INITIAL_INDEX_SIZE + } + + ~ExplicitProducer() + { + // Destruct any elements not yet dequeued. + // Since we're in the destructor, we can assume all elements + // are either completely dequeued or completely not (no halfways). + if (this->tailBlock != nullptr) { // Note this means there must be a block index too + // First find the block that's partially dequeued, if any + Block* halfDequeuedBlock = nullptr; + if ((this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) != 0) { + // The head's not on a block boundary, meaning a block somewhere is partially dequeued + // (or the head block is the tail block and was fully dequeued, but the head/tail are still not on a boundary) + size_t i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & (pr_blockIndexSize - 1); + while (details::circular_less_than(pr_blockIndexEntries[i].base + BLOCK_SIZE, this->headIndex.load(std::memory_order_relaxed))) { + i = (i + 1) & (pr_blockIndexSize - 1); + } + assert(details::circular_less_than(pr_blockIndexEntries[i].base, this->headIndex.load(std::memory_order_relaxed))); + halfDequeuedBlock = pr_blockIndexEntries[i].block; + } + + // Start at the head block (note the first line in the loop gives us the head from the tail on the first iteration) + auto block = this->tailBlock; + do { + block = block->next; + if (block->ConcurrentQueue::Block::template is_empty()) { + continue; + } + + size_t i = 0; // Offset into block + if (block == halfDequeuedBlock) { + i = static_cast(this->headIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); + } + + // Walk through all the items in the block; if this is the tail block, we need to stop when we reach the tail index + auto lastValidIndex = (this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)) == 0 ? BLOCK_SIZE : static_cast(this->tailIndex.load(std::memory_order_relaxed) & static_cast(BLOCK_SIZE - 1)); + while (i != BLOCK_SIZE && (block != this->tailBlock || i != lastValidIndex)) { + (*block)[i++]->~T(); + } + } while (block != this->tailBlock); + } + + // Destroy all blocks that we own + if (this->tailBlock != nullptr) { + auto block = this->tailBlock; + do { + auto nextBlock = block->next; + this->parent->add_block_to_free_list(block); + block = nextBlock; + } while (block != this->tailBlock); + } + + // Destroy the block indices + auto header = static_cast(pr_blockIndexRaw); + while (header != nullptr) { + auto prev = static_cast(header->prev); + header->~BlockIndexHeader(); + (Traits::free)(header); + header = prev; + } + } + + template + inline bool enqueue(U&& element) + { + index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); + index_t newTailIndex = 1 + currentTailIndex; + if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + // We reached the end of a block, start a new one + auto startBlock = this->tailBlock; + auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; + if (this->tailBlock != nullptr && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { + // We can re-use the block ahead of us, it's empty! + this->tailBlock = this->tailBlock->next; + this->tailBlock->ConcurrentQueue::Block::template reset_empty(); + + // We'll put the block on the block index (guaranteed to be room since we're conceptually removing the + // last block from it first -- except instead of removing then adding, we can just overwrite). + // Note that there must be a valid block index here, since even if allocation failed in the ctor, + // it would have been re-attempted when adding the first block to the queue; since there is such + // a block, a block index must have been successfully allocated. + } + else { + // Whatever head value we see here is >= the last value we saw here (relatively), + // and <= its current value. Since we have the most recent tail, the head must be + // <= to it. + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) + || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { + // We can't enqueue in another block because there's not enough leeway -- the + // tail could surpass the head by the time the block fills up! (Or we'll exceed + // the size limit, if the second part of the condition was true.) + return false; + } + // We're going to need a new block; check that the block index has room + if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize) { + // Hmm, the circular block index is already full -- we'll need + // to allocate a new index. Note pr_blockIndexRaw can only be nullptr if + // the initial allocation failed in the constructor. + + WPI_CQ_CONSTEXPR_IF (allocMode == CannotAlloc) { + return false; + } + else if (!new_block_index(pr_blockIndexSlotsUsed)) { + return false; + } + } + + // Insert a new block in the circular linked list + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + return false; + } +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + if (this->tailBlock == nullptr) { + newBlock->next = newBlock; + } + else { + newBlock->next = this->tailBlock->next; + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + ++pr_blockIndexSlotsUsed; + } + + WPI_CQ_CONSTEXPR_IF (!WPI_CQ_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + // The constructor may throw. We want the element not to appear in the queue in + // that case (without corrupting the queue): + WPI_CQ_TRY { + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + } + WPI_CQ_CATCH (...) { + // Revert change to the current block, but leave the new block available + // for next time + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? this->tailBlock : startBlock; + WPI_CQ_RETHROW; + } + } + else { + (void)startBlock; + (void)originalBlockIndexSlotsUsed; + } + + // Add block to block index + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + blockIndex.load(std::memory_order_relaxed)->front.store(pr_blockIndexFront, std::memory_order_release); + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + + WPI_CQ_CONSTEXPR_IF (!WPI_CQ_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + } + + // Enqueue + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + bool dequeue(U& element) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { + // Might be something to dequeue, let's give it a try + + // Note that this if is purely for performance purposes in the common case when the queue is + // empty and the values are eventually consistent -- we may enter here spuriously. + + // Note that whatever the values of overcommit and tail are, they are not going to change (unless we + // change them) and must be the same value at this point (inside the if) as when the if condition was + // evaluated. + + // We insert an acquire fence here to synchronize-with the release upon incrementing dequeueOvercommit below. + // This ensures that whatever the value we got loaded into overcommit, the load of dequeueOptisticCount in + // the fetch_add below will result in a value at least as recent as that (and therefore at least as large). + // Note that I believe a compiler (signal) fence here would be sufficient due to the nature of fetch_add (all + // read-modify-write operations are guaranteed to work on the latest value in the modification order), but + // unfortunately that can't be shown to be correct using only the C++11 standard. + // See http://stackoverflow.com/questions/18223161/what-are-the-c11-memory-ordering-guarantees-in-this-corner-case + std::atomic_thread_fence(std::memory_order_acquire); + + // Increment optimistic counter, then check if it went over the boundary + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); + + // Note that since dequeueOvercommit must be <= dequeueOptimisticCount (because dequeueOvercommit is only ever + // incremented after dequeueOptimisticCount -- this is enforced in the `else` block below), and since we now + // have a version of dequeueOptimisticCount that is at least as recent as overcommit (due to the release upon + // incrementing dequeueOvercommit and the acquire above that synchronizes with it), overcommit <= myDequeueCount. + // However, we can't assert this since both dequeueOptimisticCount and dequeueOvercommit may (independently) + // overflow; in such a case, though, the logic still holds since the difference between the two is maintained. + + // Note that we reload tail here in case it changed; it will be the same value as before or greater, since + // this load is sequenced after (happens after) the earlier load above. This is supported by read-read + // coherency (as defined in the standard), explained here: http://en.cppreference.com/w/cpp/atomic/memory_order + tail = this->tailIndex.load(std::memory_order_acquire); + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { + // Guaranteed to be at least one element to dequeue! + + // Get the index. Note that since there's guaranteed to be at least one element, this + // will never exceed tail. We need to do an acquire-release fence here since it's possible + // that whatever condition got us to this point was for an earlier enqueued element (that + // we already see the memory effects for), but that by the time we increment somebody else + // has incremented it, and we need to see the memory effects for *that* element, which is + // in such a case is necessarily visible on the thread that incremented it in the first + // place with the more current condition (they must have acquired a tail that is at least + // as recent). + auto index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); + + + // Determine which block the element is in + + auto localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); + + // We need to be careful here about subtracting and dividing because of index wrap-around. + // When an index wraps, we need to preserve the sign of the offset when dividing it by the + // block size (in order to get a correct signed block count offset in all cases): + auto headBase = localBlockIndex->entries[localBlockIndexHead].base; + auto blockBaseIndex = index & ~static_cast(BLOCK_SIZE - 1); + auto offset = static_cast(static_cast::type>(blockBaseIndex - headBase) / static_cast::type>(BLOCK_SIZE)); + auto block = localBlockIndex->entries[(localBlockIndexHead + offset) & (localBlockIndex->size - 1)].block; + + // Dequeue + auto& el = *((*block)[index]); + if (!WPI_CQ_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { + // Make sure the element is still fully dequeued and destroyed even if the assignment + // throws + struct Guard { + Block* block; + index_t index; + + ~Guard() + { + (*block)[index]->~T(); + block->ConcurrentQueue::Block::template set_empty(index); + } + } guard = { block, index }; + + element = std::move(el); // NOLINT + } + else { + element = std::move(el); // NOLINT + el.~T(); // NOLINT + block->ConcurrentQueue::Block::template set_empty(index); + } + + return true; + } + else { + // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent + this->dequeueOvercommit.fetch_add(1, std::memory_order_release); // Release so that the fetch_add on dequeueOptimisticCount is guaranteed to happen before this write + } + } + + return false; + } + + template + bool WPI_CQ_NO_TSAN enqueue_bulk(It itemFirst, size_t count) + { + // First, we need to make sure we have enough room to enqueue all of the elements; + // this means pre-allocating blocks and putting them in the block index (but only if + // all the allocations succeeded). + index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); + auto startBlock = this->tailBlock; + auto originalBlockIndexFront = pr_blockIndexFront; + auto originalBlockIndexSlotsUsed = pr_blockIndexSlotsUsed; + + Block* firstAllocatedBlock = nullptr; + + // Figure out how many blocks we'll need to allocate, and do so + size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); + index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + if (blockBaseDiff > 0) { + // Allocate as many blocks as possible from ahead + while (blockBaseDiff > 0 && this->tailBlock != nullptr && this->tailBlock->next != firstAllocatedBlock && this->tailBlock->next->ConcurrentQueue::Block::template is_empty()) { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + this->tailBlock = this->tailBlock->next; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; + + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + } + + // Now allocate as many blocks as necessary from the block pool + while (blockBaseDiff > 0) { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); + if (pr_blockIndexRaw == nullptr || pr_blockIndexSlotsUsed == pr_blockIndexSize || full) { + WPI_CQ_CONSTEXPR_IF (allocMode == CannotAlloc) { + // Failed to allocate, undo changes (but keep injected blocks) + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + else if (full || !new_block_index(originalBlockIndexSlotsUsed)) { + // Failed to allocate, undo changes (but keep injected blocks) + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + + // pr_blockIndexFront is updated inside new_block_index, so we need to + // update our fallback value too (since we keep the new index even if we + // later fail) + originalBlockIndexFront = originalBlockIndexSlotsUsed; + } + + // Insert a new block in the circular linked list + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + return false; + } + +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template set_all_empty(); + if (this->tailBlock == nullptr) { + newBlock->next = newBlock; + } + else { + newBlock->next = this->tailBlock->next; + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? this->tailBlock : firstAllocatedBlock; + + ++pr_blockIndexSlotsUsed; + + auto& entry = blockIndex.load(std::memory_order_relaxed)->entries[pr_blockIndexFront]; + entry.base = currentTailIndex; + entry.block = this->tailBlock; + pr_blockIndexFront = (pr_blockIndexFront + 1) & (pr_blockIndexSize - 1); + } + + // Excellent, all allocations succeeded. Reset each block's emptiness before we fill them up, and + // publish the new block index front + auto block = firstAllocatedBlock; + while (true) { + block->ConcurrentQueue::Block::template reset_empty(); + if (block == this->tailBlock) { + break; + } + block = block->next; + } + + WPI_CQ_CONSTEXPR_IF (WPI_CQ_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); + } + } + + // Enqueue, one block at a time + index_t newTailIndex = startTailIndex + static_cast(count); + currentTailIndex = startTailIndex; + auto endBlock = this->tailBlock; + this->tailBlock = startBlock; + assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { + this->tailBlock = firstAllocatedBlock; + } + while (true) { + index_t stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(newTailIndex, stopIndex)) { + stopIndex = newTailIndex; + } + WPI_CQ_CONSTEXPR_IF (WPI_CQ_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); + } + } + else { + WPI_CQ_TRY { + while (currentTailIndex != stopIndex) { + // Must use copy constructor even if move constructor is available + // because we may have to revert if there's an exception. + // Sorry about the horrible templated next line, but it was the only way + // to disable moving *at compile time*, which is important because a type + // may only define a (noexcept) move constructor, and so calls to the + // cctor will not compile, even if they are in an if branch that will never + // be executed + new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + ++currentTailIndex; + ++itemFirst; + } + } + WPI_CQ_CATCH (...) { + // Oh dear, an exception's been thrown -- destroy the elements that + // were enqueued so far and revert the entire bulk operation (we'll keep + // any allocated blocks in our linked list for later, though). + auto constructedStopIndex = currentTailIndex; + auto lastBlockEnqueued = this->tailBlock; + + pr_blockIndexFront = originalBlockIndexFront; + pr_blockIndexSlotsUsed = originalBlockIndexSlotsUsed; + this->tailBlock = startBlock == nullptr ? firstAllocatedBlock : startBlock; + + if (!details::is_trivially_destructible::value) { + auto block = startBlock; + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + block = firstAllocatedBlock; + } + currentTailIndex = startTailIndex; + while (true) { + stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(constructedStopIndex, stopIndex)) { + stopIndex = constructedStopIndex; + } + while (currentTailIndex != stopIndex) { + (*block)[currentTailIndex++]->~T(); + } + if (block == lastBlockEnqueued) { + break; + } + block = block->next; + } + } + WPI_CQ_RETHROW; + } + } + + if (this->tailBlock == endBlock) { + assert(currentTailIndex == newTailIndex); + break; + } + this->tailBlock = this->tailBlock->next; + } + + WPI_CQ_CONSTEXPR_IF (!WPI_CQ_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + if (firstAllocatedBlock != nullptr) + blockIndex.load(std::memory_order_relaxed)->front.store((pr_blockIndexFront - 1) & (pr_blockIndexSize - 1), std::memory_order_release); + } + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + size_t dequeue_bulk(It& itemFirst, size_t max) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); + if (details::circular_less_than(0, desiredCount)) { + desiredCount = desiredCount < max ? desiredCount : max; + std::atomic_thread_fence(std::memory_order_acquire); + + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); + + tail = this->tailIndex.load(std::memory_order_acquire); + auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); + if (details::circular_less_than(0, actualCount)) { + actualCount = desiredCount < actualCount ? desiredCount : actualCount; + if (actualCount < desiredCount) { + this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); + } + + // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this + // will never exceed tail. + auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); + + // Determine which block the first element is in + auto localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto localBlockIndexHead = localBlockIndex->front.load(std::memory_order_acquire); + + auto headBase = localBlockIndex->entries[localBlockIndexHead].base; + auto firstBlockBaseIndex = firstIndex & ~static_cast(BLOCK_SIZE - 1); + auto offset = static_cast(static_cast::type>(firstBlockBaseIndex - headBase) / static_cast::type>(BLOCK_SIZE)); + auto indexIndex = (localBlockIndexHead + offset) & (localBlockIndex->size - 1); + + // Iterate the blocks and dequeue + auto index = firstIndex; + do { + auto firstIndexInBlock = index; + index_t endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + auto block = localBlockIndex->entries[indexIndex].block; + if (WPI_CQ_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst++ = std::move(el); + el.~T(); + ++index; + } + } + else { + WPI_CQ_TRY { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst = std::move(el); + ++itemFirst; + el.~T(); + ++index; + } + } + WPI_CQ_CATCH (...) { + // It's too late to revert the dequeue, but we can make sure that all + // the dequeued objects are properly destroyed and the block index + // (and empty count) are properly updated before we propagate the exception + do { + block = localBlockIndex->entries[indexIndex].block; + while (index != endIndex) { + (*block)[index++]->~T(); + } + block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); + indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); + + firstIndexInBlock = index; + endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + } while (index != firstIndex + actualCount); + + WPI_CQ_RETHROW; + } + } + block->ConcurrentQueue::Block::template set_many_empty(firstIndexInBlock, static_cast(endIndex - firstIndexInBlock)); + indexIndex = (indexIndex + 1) & (localBlockIndex->size - 1); + } while (index != firstIndex + actualCount); + + return actualCount; + } + else { + // Wasn't anything to dequeue after all; make the effective dequeue count eventually consistent + this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); + } + } + + return 0; + } + + private: + struct BlockIndexEntry + { + index_t base; + Block* block; + }; + + struct BlockIndexHeader + { + size_t size; + std::atomic front; // Current slot (not next, like pr_blockIndexFront) + BlockIndexEntry* entries; + void* prev; + }; + + + bool new_block_index(size_t numberOfFilledSlotsToExpose) + { + auto prevBlockSizeMask = pr_blockIndexSize - 1; + + // Create the new block + pr_blockIndexSize <<= 1; + auto newRawPtr = static_cast((Traits::malloc)(sizeof(BlockIndexHeader) + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * pr_blockIndexSize)); + if (newRawPtr == nullptr) { + pr_blockIndexSize >>= 1; // Reset to allow graceful retry + return false; + } + + auto newBlockIndexEntries = reinterpret_cast(details::align_for(newRawPtr + sizeof(BlockIndexHeader))); + + // Copy in all the old indices, if any + size_t j = 0; + if (pr_blockIndexSlotsUsed != 0) { + auto i = (pr_blockIndexFront - pr_blockIndexSlotsUsed) & prevBlockSizeMask; + do { + newBlockIndexEntries[j++] = pr_blockIndexEntries[i]; + i = (i + 1) & prevBlockSizeMask; + } while (i != pr_blockIndexFront); + } + + // Update everything + auto header = new (newRawPtr) BlockIndexHeader; + header->size = pr_blockIndexSize; + header->front.store(numberOfFilledSlotsToExpose - 1, std::memory_order_relaxed); + header->entries = newBlockIndexEntries; + header->prev = pr_blockIndexRaw; // we link the new block to the old one so we can free it later + + pr_blockIndexFront = j; + pr_blockIndexEntries = newBlockIndexEntries; + pr_blockIndexRaw = newRawPtr; + blockIndex.store(header, std::memory_order_release); + + return true; + } + + private: + std::atomic blockIndex; + + // To be used by producer only -- consumer must use the ones in referenced by blockIndex + size_t pr_blockIndexSlotsUsed; + size_t pr_blockIndexSize; + size_t pr_blockIndexFront; // Next slot (not current) + BlockIndexEntry* pr_blockIndexEntries; + void* pr_blockIndexRaw; + +#ifdef WPI_CQ_QUEUE_INTERNAL_DEBUG + public: + ExplicitProducer* nextExplicitProducer; + private: +#endif + +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + ////////////////////////////////// + // Implicit queue + ////////////////////////////////// + + struct ImplicitProducer : public ProducerBase + { + ImplicitProducer(ConcurrentQueue* parent_) : + ProducerBase(parent_, false), + nextBlockIndexCapacity(IMPLICIT_INITIAL_INDEX_SIZE), + blockIndex(nullptr) + { + new_block_index(); + } + + ~ImplicitProducer() + { + // Note that since we're in the destructor we can assume that all enqueue/dequeue operations + // completed already; this means that all undequeued elements are placed contiguously across + // contiguous blocks, and that only the first and last remaining blocks can be only partially + // empty (all other remaining blocks must be completely full). + +#ifdef WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED + // Unregister ourselves for thread termination notification + if (!this->inactive.load(std::memory_order_relaxed)) { + details::ThreadExitNotifier::unsubscribe(&threadExitListener); + } +#endif + + // Destroy all remaining elements! + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto index = this->headIndex.load(std::memory_order_relaxed); + Block* block = nullptr; + assert(index == tail || details::circular_less_than(index, tail)); + bool forceFreeLastBlock = index != tail; // If we enter the loop, then the last (tail) block will not be freed + while (index != tail) { + if ((index & static_cast(BLOCK_SIZE - 1)) == 0 || block == nullptr) { + if (block != nullptr) { + // Free the old block + this->parent->add_block_to_free_list(block); + } + + block = get_block_index_entry_for_index(index)->value.load(std::memory_order_relaxed); + } + + ((*block)[index])->~T(); + ++index; + } + // Even if the queue is empty, there's still one block that's not on the free list + // (unless the head index reached the end of it, in which case the tail will be poised + // to create a new block). + if (this->tailBlock != nullptr && (forceFreeLastBlock || (tail & static_cast(BLOCK_SIZE - 1)) != 0)) { + this->parent->add_block_to_free_list(this->tailBlock); + } + + // Destroy block index + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); + if (localBlockIndex != nullptr) { + for (size_t i = 0; i != localBlockIndex->capacity; ++i) { + localBlockIndex->index[i]->~BlockIndexEntry(); + } + do { + auto prev = localBlockIndex->prev; + localBlockIndex->~BlockIndexHeader(); + (Traits::free)(localBlockIndex); + localBlockIndex = prev; + } while (localBlockIndex != nullptr); + } + } + + template + inline bool enqueue(U&& element) + { + index_t currentTailIndex = this->tailIndex.load(std::memory_order_relaxed); + index_t newTailIndex = 1 + currentTailIndex; + if ((currentTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + // We reached the end of a block, start a new one + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + if (!details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head))) { + return false; + } +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Find out where we'll be inserting this block in the block index + BlockIndexEntry* idxEntry; + if (!insert_block_index_entry(idxEntry, currentTailIndex)) { + return false; + } + + // Get ahold of a new block + auto newBlock = this->parent->ConcurrentQueue::template requisition_block(); + if (newBlock == nullptr) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + return false; + } +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + + WPI_CQ_CONSTEXPR_IF (!WPI_CQ_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + // May throw, try to insert now before we publish the fact that we have this new block + WPI_CQ_TRY { + new ((*newBlock)[currentTailIndex]) T(std::forward(element)); + } + WPI_CQ_CATCH (...) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + this->parent->add_block_to_free_list(newBlock); + WPI_CQ_RETHROW; + } + } + + // Insert the new block into the index + idxEntry->value.store(newBlock, std::memory_order_relaxed); + + this->tailBlock = newBlock; + + WPI_CQ_CONSTEXPR_IF (!WPI_CQ_NOEXCEPT_CTOR(T, U, new (static_cast(nullptr)) T(std::forward(element)))) { + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + } + + // Enqueue + new ((*this->tailBlock)[currentTailIndex]) T(std::forward(element)); + + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } + + template + bool dequeue(U& element) + { + // See ExplicitProducer::dequeue for rationale and explanation + index_t tail = this->tailIndex.load(std::memory_order_relaxed); + index_t overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + if (details::circular_less_than(this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit, tail)) { + std::atomic_thread_fence(std::memory_order_acquire); + + index_t myDequeueCount = this->dequeueOptimisticCount.fetch_add(1, std::memory_order_relaxed); + tail = this->tailIndex.load(std::memory_order_acquire); + if ((details::likely)(details::circular_less_than(myDequeueCount - overcommit, tail))) { + index_t index = this->headIndex.fetch_add(1, std::memory_order_acq_rel); + + // Determine which block the element is in + auto entry = get_block_index_entry_for_index(index); + + // Dequeue + auto block = entry->value.load(std::memory_order_relaxed); + auto& el = *((*block)[index]); + + if (!WPI_CQ_NOEXCEPT_ASSIGN(T, T&&, element = std::move(el))) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + // Note: Acquiring the mutex with every dequeue instead of only when a block + // is released is very sub-optimal, but it is, after all, purely debug code. + debug::DebugLock lock(producer->mutex); +#endif + struct Guard { + Block* block; + index_t index; + BlockIndexEntry* entry; + ConcurrentQueue* parent; + + ~Guard() + { + (*block)[index]->~T(); + if (block->ConcurrentQueue::Block::template set_empty(index)) { + entry->value.store(nullptr, std::memory_order_relaxed); + parent->add_block_to_free_list(block); + } + } + } guard = { block, index, entry, this->parent }; + + element = std::move(el); // NOLINT + } + else { + element = std::move(el); // NOLINT + el.~T(); // NOLINT + + if (block->ConcurrentQueue::Block::template set_empty(index)) { + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Add the block back into the global free pool (and remove from block index) + entry->value.store(nullptr, std::memory_order_relaxed); + } + this->parent->add_block_to_free_list(block); // releases the above store + } + } + + return true; + } + else { + this->dequeueOvercommit.fetch_add(1, std::memory_order_release); + } + } + + return false; + } + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4706) // assignment within conditional expression +#endif + template + bool enqueue_bulk(It itemFirst, size_t count) + { + // First, we need to make sure we have enough room to enqueue all of the elements; + // this means pre-allocating blocks and putting them in the block index (but only if + // all the allocations succeeded). + + // Note that the tailBlock we start off with may not be owned by us any more; + // this happens if it was filled up exactly to the top (setting tailIndex to + // the first index of the next block which is not yet allocated), then dequeued + // completely (putting it on the free list) before we enqueue again. + + index_t startTailIndex = this->tailIndex.load(std::memory_order_relaxed); + auto startBlock = this->tailBlock; + Block* firstAllocatedBlock = nullptr; + auto endBlock = this->tailBlock; + + // Figure out how many blocks we'll need to allocate, and do so + size_t blockBaseDiff = ((startTailIndex + count - 1) & ~static_cast(BLOCK_SIZE - 1)) - ((startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1)); + index_t currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + if (blockBaseDiff > 0) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + do { + blockBaseDiff -= static_cast(BLOCK_SIZE); + currentTailIndex += static_cast(BLOCK_SIZE); + + // Find out where we'll be inserting this block in the block index + BlockIndexEntry* idxEntry = nullptr; // initialization here unnecessary but compiler can't always tell + Block* newBlock; + bool indexInserted = false; + auto head = this->headIndex.load(std::memory_order_relaxed); + assert(!details::circular_less_than(currentTailIndex, head)); + bool full = !details::circular_less_than(head, currentTailIndex + BLOCK_SIZE) || (MAX_SUBQUEUE_SIZE != details::const_numeric_max::value && (MAX_SUBQUEUE_SIZE == 0 || MAX_SUBQUEUE_SIZE - BLOCK_SIZE < currentTailIndex - head)); + + if (full || !(indexInserted = insert_block_index_entry(idxEntry, currentTailIndex)) || (newBlock = this->parent->ConcurrentQueue::template requisition_block()) == nullptr) { + // Index allocation or block allocation failed; revert any other allocations + // and index insertions done so far for this operation + if (indexInserted) { + rewind_block_index_tail(); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + } + currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { + currentTailIndex += static_cast(BLOCK_SIZE); + idxEntry = get_block_index_entry_for_index(currentTailIndex); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + rewind_block_index_tail(); + } + this->parent->add_blocks_to_free_list(firstAllocatedBlock); + this->tailBlock = startBlock; + + return false; + } + +#ifdef MCDBGQ_TRACKMEM + newBlock->owner = this; +#endif + newBlock->ConcurrentQueue::Block::template reset_empty(); + newBlock->next = nullptr; + + // Insert the new block into the index + idxEntry->value.store(newBlock, std::memory_order_relaxed); + + // Store the chain of blocks so that we can undo if later allocations fail, + // and so that we can find the blocks when we do the actual enqueueing + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr) { + assert(this->tailBlock != nullptr); + this->tailBlock->next = newBlock; + } + this->tailBlock = newBlock; + endBlock = newBlock; + firstAllocatedBlock = firstAllocatedBlock == nullptr ? newBlock : firstAllocatedBlock; + } while (blockBaseDiff > 0); + } + + // Enqueue, one block at a time + index_t newTailIndex = startTailIndex + static_cast(count); + currentTailIndex = startTailIndex; + this->tailBlock = startBlock; + assert((startTailIndex & static_cast(BLOCK_SIZE - 1)) != 0 || firstAllocatedBlock != nullptr || count == 0); + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0 && firstAllocatedBlock != nullptr) { + this->tailBlock = firstAllocatedBlock; + } + while (true) { + index_t stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(newTailIndex, stopIndex)) { + stopIndex = newTailIndex; + } + WPI_CQ_CONSTEXPR_IF (WPI_CQ_NOEXCEPT_CTOR(T, decltype(*itemFirst), new (static_cast(nullptr)) T(details::deref_noexcept(itemFirst)))) { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex++]) T(*itemFirst++); + } + } + else { + WPI_CQ_TRY { + while (currentTailIndex != stopIndex) { + new ((*this->tailBlock)[currentTailIndex]) T(details::nomove_if(nullptr)) T(details::deref_noexcept(itemFirst)))>::eval(*itemFirst)); + ++currentTailIndex; + ++itemFirst; + } + } + WPI_CQ_CATCH (...) { + auto constructedStopIndex = currentTailIndex; + auto lastBlockEnqueued = this->tailBlock; + + if (!details::is_trivially_destructible::value) { + auto block = startBlock; + if ((startTailIndex & static_cast(BLOCK_SIZE - 1)) == 0) { + block = firstAllocatedBlock; + } + currentTailIndex = startTailIndex; + while (true) { + stopIndex = (currentTailIndex & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + if (details::circular_less_than(constructedStopIndex, stopIndex)) { + stopIndex = constructedStopIndex; + } + while (currentTailIndex != stopIndex) { + (*block)[currentTailIndex++]->~T(); + } + if (block == lastBlockEnqueued) { + break; + } + block = block->next; + } + } + + currentTailIndex = (startTailIndex - 1) & ~static_cast(BLOCK_SIZE - 1); + for (auto block = firstAllocatedBlock; block != nullptr; block = block->next) { + currentTailIndex += static_cast(BLOCK_SIZE); + auto idxEntry = get_block_index_entry_for_index(currentTailIndex); + idxEntry->value.store(nullptr, std::memory_order_relaxed); + rewind_block_index_tail(); + } + this->parent->add_blocks_to_free_list(firstAllocatedBlock); + this->tailBlock = startBlock; + WPI_CQ_RETHROW; + } + } + + if (this->tailBlock == endBlock) { + assert(currentTailIndex == newTailIndex); + break; + } + this->tailBlock = this->tailBlock->next; + } + this->tailIndex.store(newTailIndex, std::memory_order_release); + return true; + } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + template + size_t dequeue_bulk(It& itemFirst, size_t max) + { + auto tail = this->tailIndex.load(std::memory_order_relaxed); + auto overcommit = this->dequeueOvercommit.load(std::memory_order_relaxed); + auto desiredCount = static_cast(tail - (this->dequeueOptimisticCount.load(std::memory_order_relaxed) - overcommit)); + if (details::circular_less_than(0, desiredCount)) { + desiredCount = desiredCount < max ? desiredCount : max; + std::atomic_thread_fence(std::memory_order_acquire); + + auto myDequeueCount = this->dequeueOptimisticCount.fetch_add(desiredCount, std::memory_order_relaxed); + + tail = this->tailIndex.load(std::memory_order_acquire); + auto actualCount = static_cast(tail - (myDequeueCount - overcommit)); + if (details::circular_less_than(0, actualCount)) { + actualCount = desiredCount < actualCount ? desiredCount : actualCount; + if (actualCount < desiredCount) { + this->dequeueOvercommit.fetch_add(desiredCount - actualCount, std::memory_order_release); + } + + // Get the first index. Note that since there's guaranteed to be at least actualCount elements, this + // will never exceed tail. + auto firstIndex = this->headIndex.fetch_add(actualCount, std::memory_order_acq_rel); + + // Iterate the blocks and dequeue + auto index = firstIndex; + BlockIndexHeader* localBlockIndex; + auto indexIndex = get_block_index_index_for_index(index, localBlockIndex); + do { + auto blockStartIndex = index; + index_t endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + + auto entry = localBlockIndex->index[indexIndex]; + auto block = entry->value.load(std::memory_order_relaxed); + if (WPI_CQ_NOEXCEPT_ASSIGN(T, T&&, details::deref_noexcept(itemFirst) = std::move((*(*block)[index])))) { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst++ = std::move(el); + el.~T(); + ++index; + } + } + else { + WPI_CQ_TRY { + while (index != endIndex) { + auto& el = *((*block)[index]); + *itemFirst = std::move(el); + ++itemFirst; + el.~T(); + ++index; + } + } + WPI_CQ_CATCH (...) { + do { + entry = localBlockIndex->index[indexIndex]; + block = entry->value.load(std::memory_order_relaxed); + while (index != endIndex) { + (*block)[index++]->~T(); + } + + if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + entry->value.store(nullptr, std::memory_order_relaxed); + this->parent->add_block_to_free_list(block); + } + indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); + + blockStartIndex = index; + endIndex = (index & ~static_cast(BLOCK_SIZE - 1)) + static_cast(BLOCK_SIZE); + endIndex = details::circular_less_than(firstIndex + static_cast(actualCount), endIndex) ? firstIndex + static_cast(actualCount) : endIndex; + } while (index != firstIndex + actualCount); + + WPI_CQ_RETHROW; + } + } + if (block->ConcurrentQueue::Block::template set_many_empty(blockStartIndex, static_cast(endIndex - blockStartIndex))) { + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + // Note that the set_many_empty above did a release, meaning that anybody who acquires the block + // we're about to free can use it safely since our writes (and reads!) will have happened-before then. + entry->value.store(nullptr, std::memory_order_relaxed); + } + this->parent->add_block_to_free_list(block); // releases the above store + } + indexIndex = (indexIndex + 1) & (localBlockIndex->capacity - 1); + } while (index != firstIndex + actualCount); + + return actualCount; + } + else { + this->dequeueOvercommit.fetch_add(desiredCount, std::memory_order_release); + } + } + + return 0; + } + + private: + // The block size must be > 1, so any number with the low bit set is an invalid block base index + static const index_t INVALID_BLOCK_BASE = 1; + + struct BlockIndexEntry + { + std::atomic key; + std::atomic value; + }; + + struct BlockIndexHeader + { + size_t capacity; + std::atomic tail; + BlockIndexEntry* entries; + BlockIndexEntry** index; + BlockIndexHeader* prev; + }; + + template + inline bool insert_block_index_entry(BlockIndexEntry*& idxEntry, index_t blockStartIndex) + { + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); // We're the only writer thread, relaxed is OK + if (localBlockIndex == nullptr) { + return false; // this can happen if new_block_index failed in the constructor + } + size_t newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); + idxEntry = localBlockIndex->index[newTail]; + if (idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE || + idxEntry->value.load(std::memory_order_relaxed) == nullptr) { + + idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); + localBlockIndex->tail.store(newTail, std::memory_order_release); + return true; + } + + // No room in the old block index, try to allocate another one! + WPI_CQ_CONSTEXPR_IF (allocMode == CannotAlloc) { + return false; + } + else if (!new_block_index()) { + return false; + } + else { + localBlockIndex = blockIndex.load(std::memory_order_relaxed); + newTail = (localBlockIndex->tail.load(std::memory_order_relaxed) + 1) & (localBlockIndex->capacity - 1); + idxEntry = localBlockIndex->index[newTail]; + assert(idxEntry->key.load(std::memory_order_relaxed) == INVALID_BLOCK_BASE); + idxEntry->key.store(blockStartIndex, std::memory_order_relaxed); + localBlockIndex->tail.store(newTail, std::memory_order_release); + return true; + } + } + + inline void rewind_block_index_tail() + { + auto localBlockIndex = blockIndex.load(std::memory_order_relaxed); + localBlockIndex->tail.store((localBlockIndex->tail.load(std::memory_order_relaxed) - 1) & (localBlockIndex->capacity - 1), std::memory_order_relaxed); + } + + inline BlockIndexEntry* get_block_index_entry_for_index(index_t index) const + { + BlockIndexHeader* localBlockIndex; + auto idx = get_block_index_index_for_index(index, localBlockIndex); + return localBlockIndex->index[idx]; + } + + inline size_t get_block_index_index_for_index(index_t index, BlockIndexHeader*& localBlockIndex) const + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + debug::DebugLock lock(mutex); +#endif + index &= ~static_cast(BLOCK_SIZE - 1); + localBlockIndex = blockIndex.load(std::memory_order_acquire); + auto tail = localBlockIndex->tail.load(std::memory_order_acquire); + auto tailBase = localBlockIndex->index[tail]->key.load(std::memory_order_relaxed); + assert(tailBase != INVALID_BLOCK_BASE); + // Note: Must use division instead of shift because the index may wrap around, causing a negative + // offset, whose negativity we want to preserve + auto offset = static_cast(static_cast::type>(index - tailBase) / static_cast::type>(BLOCK_SIZE)); + size_t idx = (tail + offset) & (localBlockIndex->capacity - 1); + assert(localBlockIndex->index[idx]->key.load(std::memory_order_relaxed) == index && localBlockIndex->index[idx]->value.load(std::memory_order_relaxed) != nullptr); + return idx; + } + + bool new_block_index() + { + auto prev = blockIndex.load(std::memory_order_relaxed); + size_t prevCapacity = prev == nullptr ? 0 : prev->capacity; + auto entryCount = prev == nullptr ? nextBlockIndexCapacity : prevCapacity; + auto raw = static_cast((Traits::malloc)( + sizeof(BlockIndexHeader) + + std::alignment_of::value - 1 + sizeof(BlockIndexEntry) * entryCount + + std::alignment_of::value - 1 + sizeof(BlockIndexEntry*) * nextBlockIndexCapacity)); + if (raw == nullptr) { + return false; + } + + auto header = new (raw) BlockIndexHeader; + auto entries = reinterpret_cast(details::align_for(raw + sizeof(BlockIndexHeader))); + auto index = reinterpret_cast(details::align_for(reinterpret_cast(entries) + sizeof(BlockIndexEntry) * entryCount)); + if (prev != nullptr) { + auto prevTail = prev->tail.load(std::memory_order_relaxed); + auto prevPos = prevTail; + size_t i = 0; + do { + prevPos = (prevPos + 1) & (prev->capacity - 1); + index[i++] = prev->index[prevPos]; + } while (prevPos != prevTail); + assert(i == prevCapacity); + } + for (size_t i = 0; i != entryCount; ++i) { + new (entries + i) BlockIndexEntry; + entries[i].key.store(INVALID_BLOCK_BASE, std::memory_order_relaxed); + index[prevCapacity + i] = entries + i; + } + header->prev = prev; + header->entries = entries; + header->index = index; + header->capacity = nextBlockIndexCapacity; + header->tail.store((prevCapacity - 1) & (nextBlockIndexCapacity - 1), std::memory_order_relaxed); + + blockIndex.store(header, std::memory_order_release); + + nextBlockIndexCapacity <<= 1; + + return true; + } + + private: + size_t nextBlockIndexCapacity; + std::atomic blockIndex; + +#ifdef WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED + public: + details::ThreadExitListener threadExitListener; + private: +#endif + +#ifdef WPI_CQ_QUEUE_INTERNAL_DEBUG + public: + ImplicitProducer* nextImplicitProducer; + private: +#endif + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODBLOCKINDEX + mutable debug::DebugMutex mutex; +#endif +#ifdef MCDBGQ_TRACKMEM + friend struct MemStats; +#endif + }; + + + ////////////////////////////////// + // Block pool manipulation + ////////////////////////////////// + + void populate_initial_block_list(size_t blockCount) + { + initialBlockPoolSize = blockCount; + if (initialBlockPoolSize == 0) { + initialBlockPool = nullptr; + return; + } + + initialBlockPool = create_array(blockCount); + if (initialBlockPool == nullptr) { + initialBlockPoolSize = 0; + } + for (size_t i = 0; i < initialBlockPoolSize; ++i) { + initialBlockPool[i].dynamicallyAllocated = false; + } + } + + inline Block* try_get_block_from_initial_pool() + { + if (initialBlockPoolIndex.load(std::memory_order_relaxed) >= initialBlockPoolSize) { + return nullptr; + } + + auto index = initialBlockPoolIndex.fetch_add(1, std::memory_order_relaxed); + + return index < initialBlockPoolSize ? (initialBlockPool + index) : nullptr; + } + + inline void add_block_to_free_list(Block* block) + { +#ifdef MCDBGQ_TRACKMEM + block->owner = nullptr; +#endif + if (!Traits::RECYCLE_ALLOCATED_BLOCKS && block->dynamicallyAllocated) { + destroy(block); + } + else { + freeList.add(block); + } + } + + inline void add_blocks_to_free_list(Block* block) + { + while (block != nullptr) { + auto next = block->next; + add_block_to_free_list(block); + block = next; + } + } + + inline Block* try_get_block_from_free_list() + { + return freeList.try_get(); + } + + // Gets a free block from one of the memory pools, or allocates a new one (if applicable) + template + Block* requisition_block() + { + auto block = try_get_block_from_initial_pool(); + if (block != nullptr) { + return block; + } + + block = try_get_block_from_free_list(); + if (block != nullptr) { + return block; + } + + WPI_CQ_CONSTEXPR_IF (canAlloc == CanAlloc) { + return create(); + } + else { + return nullptr; + } + } + + +#ifdef MCDBGQ_TRACKMEM + public: + struct MemStats { + size_t allocatedBlocks; + size_t usedBlocks; + size_t freeBlocks; + size_t ownedBlocksExplicit; + size_t ownedBlocksImplicit; + size_t implicitProducers; + size_t explicitProducers; + size_t elementsEnqueued; + size_t blockClassBytes; + size_t queueClassBytes; + size_t implicitBlockIndexBytes; + size_t explicitBlockIndexBytes; + + friend class ConcurrentQueue; + + private: + static MemStats getFor(ConcurrentQueue* q) + { + MemStats stats = { 0 }; + + stats.elementsEnqueued = q->size_approx(); + + auto block = q->freeList.head_unsafe(); + while (block != nullptr) { + ++stats.allocatedBlocks; + ++stats.freeBlocks; + block = block->freeListNext.load(std::memory_order_relaxed); + } + + for (auto ptr = q->producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + bool implicit = dynamic_cast(ptr) != nullptr; + stats.implicitProducers += implicit ? 1 : 0; + stats.explicitProducers += implicit ? 0 : 1; + + if (implicit) { + auto prod = static_cast(ptr); + stats.queueClassBytes += sizeof(ImplicitProducer); + auto head = prod->headIndex.load(std::memory_order_relaxed); + auto tail = prod->tailIndex.load(std::memory_order_relaxed); + auto hash = prod->blockIndex.load(std::memory_order_relaxed); + if (hash != nullptr) { + for (size_t i = 0; i != hash->capacity; ++i) { + if (hash->index[i]->key.load(std::memory_order_relaxed) != ImplicitProducer::INVALID_BLOCK_BASE && hash->index[i]->value.load(std::memory_order_relaxed) != nullptr) { + ++stats.allocatedBlocks; + ++stats.ownedBlocksImplicit; + } + } + stats.implicitBlockIndexBytes += hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry); + for (; hash != nullptr; hash = hash->prev) { + stats.implicitBlockIndexBytes += sizeof(typename ImplicitProducer::BlockIndexHeader) + hash->capacity * sizeof(typename ImplicitProducer::BlockIndexEntry*); + } + } + for (; details::circular_less_than(head, tail); head += BLOCK_SIZE) { + //auto block = prod->get_block_index_entry_for_index(head); + ++stats.usedBlocks; + } + } + else { + auto prod = static_cast(ptr); + stats.queueClassBytes += sizeof(ExplicitProducer); + auto tailBlock = prod->tailBlock; + bool wasNonEmpty = false; + if (tailBlock != nullptr) { + auto block = tailBlock; + do { + ++stats.allocatedBlocks; + if (!block->ConcurrentQueue::Block::template is_empty() || wasNonEmpty) { + ++stats.usedBlocks; + wasNonEmpty = wasNonEmpty || block != tailBlock; + } + ++stats.ownedBlocksExplicit; + block = block->next; + } while (block != tailBlock); + } + auto index = prod->blockIndex.load(std::memory_order_relaxed); + while (index != nullptr) { + stats.explicitBlockIndexBytes += sizeof(typename ExplicitProducer::BlockIndexHeader) + index->size * sizeof(typename ExplicitProducer::BlockIndexEntry); + index = static_cast(index->prev); + } + } + } + + auto freeOnInitialPool = q->initialBlockPoolIndex.load(std::memory_order_relaxed) >= q->initialBlockPoolSize ? 0 : q->initialBlockPoolSize - q->initialBlockPoolIndex.load(std::memory_order_relaxed); + stats.allocatedBlocks += freeOnInitialPool; + stats.freeBlocks += freeOnInitialPool; + + stats.blockClassBytes = sizeof(Block) * stats.allocatedBlocks; + stats.queueClassBytes += sizeof(ConcurrentQueue); + + return stats; + } + }; + + // For debugging only. Not thread-safe. + MemStats getMemStats() + { + return MemStats::getFor(this); + } + private: + friend struct MemStats; +#endif + + + ////////////////////////////////// + // Producer list manipulation + ////////////////////////////////// + + ProducerBase* recycle_or_create_producer(bool isExplicit) + { +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + // Try to re-use one first + for (auto ptr = producerListTail.load(std::memory_order_acquire); ptr != nullptr; ptr = ptr->next_prod()) { + if (ptr->inactive.load(std::memory_order_relaxed) && ptr->isExplicit == isExplicit) { + bool expected = true; + if (ptr->inactive.compare_exchange_strong(expected, /* desired */ false, std::memory_order_acquire, std::memory_order_relaxed)) { + // We caught one! It's been marked as activated, the caller can have it + return ptr; + } + } + } + + return add_producer(isExplicit ? static_cast(create(this)) : create(this)); + } + + ProducerBase* add_producer(ProducerBase* producer) + { + // Handle failed memory allocation + if (producer == nullptr) { + return nullptr; + } + + producerCount.fetch_add(1, std::memory_order_relaxed); + + // Add it to the lock-free list + auto prevTail = producerListTail.load(std::memory_order_relaxed); + do { + producer->next = prevTail; + } while (!producerListTail.compare_exchange_weak(prevTail, producer, std::memory_order_release, std::memory_order_relaxed)); + +#ifdef WPI_CQ_QUEUE_INTERNAL_DEBUG + if (producer->isExplicit) { + auto prevTailExplicit = explicitProducers.load(std::memory_order_relaxed); + do { + static_cast(producer)->nextExplicitProducer = prevTailExplicit; + } while (!explicitProducers.compare_exchange_weak(prevTailExplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); + } + else { + auto prevTailImplicit = implicitProducers.load(std::memory_order_relaxed); + do { + static_cast(producer)->nextImplicitProducer = prevTailImplicit; + } while (!implicitProducers.compare_exchange_weak(prevTailImplicit, static_cast(producer), std::memory_order_release, std::memory_order_relaxed)); + } +#endif + + return producer; + } + + void reown_producers() + { + // After another instance is moved-into/swapped-with this one, all the + // producers we stole still think their parents are the other queue. + // So fix them up! + for (auto ptr = producerListTail.load(std::memory_order_relaxed); ptr != nullptr; ptr = ptr->next_prod()) { + ptr->parent = this; + } + } + + + ////////////////////////////////// + // Implicit producer hash + ////////////////////////////////// + + struct ImplicitProducerKVP + { + std::atomic key; + ImplicitProducer* value; // No need for atomicity since it's only read by the thread that sets it in the first place + + ImplicitProducerKVP() : value(nullptr) { } + + ImplicitProducerKVP(ImplicitProducerKVP&& other) WPI_CQ_NOEXCEPT + { + key.store(other.key.load(std::memory_order_relaxed), std::memory_order_relaxed); + value = other.value; + } + + inline ImplicitProducerKVP& operator=(ImplicitProducerKVP&& other) WPI_CQ_NOEXCEPT + { + swap(other); + return *this; + } + + inline void swap(ImplicitProducerKVP& other) WPI_CQ_NOEXCEPT + { + if (this != &other) { + details::swap_relaxed(key, other.key); + std::swap(value, other.value); + } + } + }; + + template + friend void wpi::swap(typename ConcurrentQueue::ImplicitProducerKVP&, typename ConcurrentQueue::ImplicitProducerKVP&) WPI_CQ_NOEXCEPT; + + struct ImplicitProducerHash + { + size_t capacity; + ImplicitProducerKVP* entries; + ImplicitProducerHash* prev; + }; + + inline void populate_initial_implicit_producer_hash() + { + WPI_CQ_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { + return; + } + else { + implicitProducerHashCount.store(0, std::memory_order_relaxed); + auto hash = &initialImplicitProducerHash; + hash->capacity = INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; + hash->entries = &initialImplicitProducerHashEntries[0]; + for (size_t i = 0; i != INITIAL_IMPLICIT_PRODUCER_HASH_SIZE; ++i) { + initialImplicitProducerHashEntries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); + } + hash->prev = nullptr; + implicitProducerHash.store(hash, std::memory_order_relaxed); + } + } + + void swap_implicit_producer_hashes(ConcurrentQueue& other) + { + WPI_CQ_CONSTEXPR_IF (INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0) { + return; + } + else { + // Swap (assumes our implicit producer hash is initialized) + initialImplicitProducerHashEntries.swap(other.initialImplicitProducerHashEntries); + initialImplicitProducerHash.entries = &initialImplicitProducerHashEntries[0]; + other.initialImplicitProducerHash.entries = &other.initialImplicitProducerHashEntries[0]; + + details::swap_relaxed(implicitProducerHashCount, other.implicitProducerHashCount); + + details::swap_relaxed(implicitProducerHash, other.implicitProducerHash); + if (implicitProducerHash.load(std::memory_order_relaxed) == &other.initialImplicitProducerHash) { + implicitProducerHash.store(&initialImplicitProducerHash, std::memory_order_relaxed); + } + else { + ImplicitProducerHash* hash; + for (hash = implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &other.initialImplicitProducerHash; hash = hash->prev) { + continue; + } + hash->prev = &initialImplicitProducerHash; + } + if (other.implicitProducerHash.load(std::memory_order_relaxed) == &initialImplicitProducerHash) { + other.implicitProducerHash.store(&other.initialImplicitProducerHash, std::memory_order_relaxed); + } + else { + ImplicitProducerHash* hash; + for (hash = other.implicitProducerHash.load(std::memory_order_relaxed); hash->prev != &initialImplicitProducerHash; hash = hash->prev) { + continue; + } + hash->prev = &other.initialImplicitProducerHash; + } + } + } + + // Only fails (returns nullptr) if memory allocation fails + ImplicitProducer* get_or_add_implicit_producer() + { + // Note that since the data is essentially thread-local (key is thread ID), + // there's a reduced need for fences (memory ordering is already consistent + // for any individual thread), except for the current table itself. + + // Start by looking for the thread ID in the current and all previous hash tables. + // If it's not found, it must not be in there yet, since this same thread would + // have added it previously to one of the tables that we traversed. + + // Code and algorithm adapted from http://preshing.com/20130605/the-worlds-simplest-lock-free-hash-table + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + + auto id = details::thread_id(); + auto hashedId = details::hash_thread_id(id); + + auto mainHash = implicitProducerHash.load(std::memory_order_acquire); + assert(mainHash != nullptr); // silence clang-tidy and MSVC warnings (hash cannot be null) + for (auto hash = mainHash; hash != nullptr; hash = hash->prev) { + // Look for the id in this hash + auto index = hashedId; + while (true) { // Not an infinite loop because at least one slot is free in the hash table + index &= hash->capacity - 1u; + + auto probedKey = hash->entries[index].key.load(std::memory_order_relaxed); + if (probedKey == id) { + // Found it! If we had to search several hashes deep, though, we should lazily add it + // to the current main hash table to avoid the extended search next time. + // Note there's guaranteed to be room in the current hash table since every subsequent + // table implicitly reserves space for all previous tables (there's only one + // implicitProducerHashCount). + auto value = hash->entries[index].value; + if (hash != mainHash) { + index = hashedId; + while (true) { + index &= mainHash->capacity - 1u; + auto empty = details::invalid_thread_id; +#ifdef WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED + auto reusable = details::invalid_thread_id2; + if (mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_seq_cst, std::memory_order_relaxed) || + mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_seq_cst, std::memory_order_relaxed)) { +#else + if (mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_seq_cst, std::memory_order_relaxed)) { +#endif + mainHash->entries[index].value = value; + break; + } + ++index; + } + } + + return value; + } + if (probedKey == details::invalid_thread_id) { + break; // Not in this hash table + } + ++index; + } + } + + // Insert! + auto newCount = 1 + implicitProducerHashCount.fetch_add(1, std::memory_order_relaxed); + while (true) { + // NOLINTNEXTLINE(clang-analyzer-core.NullDereference) + if (newCount >= (mainHash->capacity >> 1) && !implicitProducerHashResizeInProgress.test_and_set(std::memory_order_acquire)) { + // We've acquired the resize lock, try to allocate a bigger hash table. + // Note the acquire fence synchronizes with the release fence at the end of this block, and hence when + // we reload implicitProducerHash it must be the most recent version (it only gets changed within this + // locked block). + mainHash = implicitProducerHash.load(std::memory_order_acquire); + if (newCount >= (mainHash->capacity >> 1)) { + size_t newCapacity = mainHash->capacity << 1; + while (newCount >= (newCapacity >> 1)) { + newCapacity <<= 1; + } + auto raw = static_cast((Traits::malloc)(sizeof(ImplicitProducerHash) + std::alignment_of::value - 1 + sizeof(ImplicitProducerKVP) * newCapacity)); + if (raw == nullptr) { + // Allocation failed + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed); + return nullptr; + } + + auto newHash = new (raw) ImplicitProducerHash; + newHash->capacity = static_cast(newCapacity); + newHash->entries = reinterpret_cast(details::align_for(raw + sizeof(ImplicitProducerHash))); + for (size_t i = 0; i != newCapacity; ++i) { + new (newHash->entries + i) ImplicitProducerKVP; + newHash->entries[i].key.store(details::invalid_thread_id, std::memory_order_relaxed); + } + newHash->prev = mainHash; + implicitProducerHash.store(newHash, std::memory_order_release); + implicitProducerHashResizeInProgress.clear(std::memory_order_release); + mainHash = newHash; + } + else { + implicitProducerHashResizeInProgress.clear(std::memory_order_release); + } + } + + // If it's < three-quarters full, add to the old one anyway so that we don't have to wait for the next table + // to finish being allocated by another thread (and if we just finished allocating above, the condition will + // always be true) + if (newCount < (mainHash->capacity >> 1) + (mainHash->capacity >> 2)) { + auto producer = static_cast(recycle_or_create_producer(false)); + if (producer == nullptr) { + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); + return nullptr; + } + +#ifdef WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED + producer->threadExitListener.callback = &ConcurrentQueue::implicit_producer_thread_exited_callback; + producer->threadExitListener.userData = producer; + details::ThreadExitNotifier::subscribe(&producer->threadExitListener); +#endif + + auto index = hashedId; + while (true) { + index &= mainHash->capacity - 1u; + auto empty = details::invalid_thread_id; +#ifdef WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED + auto reusable = details::invalid_thread_id2; + if (mainHash->entries[index].key.compare_exchange_strong(reusable, id, std::memory_order_seq_cst, std::memory_order_relaxed)) { + implicitProducerHashCount.fetch_sub(1, std::memory_order_relaxed); // already counted as a used slot + mainHash->entries[index].value = producer; + break; + } +#endif + if (mainHash->entries[index].key.compare_exchange_strong(empty, id, std::memory_order_seq_cst, std::memory_order_relaxed)) { + mainHash->entries[index].value = producer; + break; + } + ++index; + } + return producer; + } + + // Hmm, the old hash is quite full and somebody else is busy allocating a new one. + // We need to wait for the allocating thread to finish (if it succeeds, we add, if not, + // we try to allocate ourselves). + mainHash = implicitProducerHash.load(std::memory_order_acquire); + } + } + +#ifdef WPI_CQ_CPP11_THREAD_LOCAL_SUPPORTED + void implicit_producer_thread_exited(ImplicitProducer* producer) + { + // Remove from hash +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugLock lock(implicitProdMutex); +#endif + auto hash = implicitProducerHash.load(std::memory_order_acquire); + assert(hash != nullptr); // The thread exit listener is only registered if we were added to a hash in the first place + auto id = details::thread_id(); + auto hashedId = details::hash_thread_id(id); + details::thread_id_t probedKey; + + // We need to traverse all the hashes just in case other threads aren't on the current one yet and are + // trying to add an entry thinking there's a free slot (because they reused a producer) + for (; hash != nullptr; hash = hash->prev) { + auto index = hashedId; + do { + index &= hash->capacity - 1u; + probedKey = id; + if (hash->entries[index].key.compare_exchange_strong(probedKey, details::invalid_thread_id2, std::memory_order_seq_cst, std::memory_order_relaxed)) { + break; + } + ++index; + } while (probedKey != details::invalid_thread_id); // Can happen if the hash has changed but we weren't put back in it yet, or if we weren't added to this hash in the first place + } + + // Mark the queue as being recyclable + producer->inactive.store(true, std::memory_order_release); + } + + static void implicit_producer_thread_exited_callback(void* userData) + { + auto producer = static_cast(userData); + auto queue = producer->parent; + queue->implicit_producer_thread_exited(producer); + } +#endif + + ////////////////////////////////// + // Utility functions + ////////////////////////////////// + + template + static inline void* aligned_malloc(size_t size) + { + WPI_CQ_CONSTEXPR_IF (std::alignment_of::value <= std::alignment_of::value) + return (Traits::malloc)(size); + else { + size_t alignment = std::alignment_of::value; + void* raw = (Traits::malloc)(size + alignment - 1 + sizeof(void*)); + if (!raw) + return nullptr; + char* ptr = details::align_for(reinterpret_cast(raw) + sizeof(void*)); + *(reinterpret_cast(ptr) - 1) = raw; + return ptr; + } + } + + template + static inline void aligned_free(void* ptr) + { + WPI_CQ_CONSTEXPR_IF (std::alignment_of::value <= std::alignment_of::value) + return (Traits::free)(ptr); + else + (Traits::free)(ptr ? *(reinterpret_cast(ptr) - 1) : nullptr); + } + + template + static inline U* create_array(size_t count) + { + assert(count > 0); + U* p = static_cast(aligned_malloc(sizeof(U) * count)); + if (p == nullptr) + return nullptr; + + for (size_t i = 0; i != count; ++i) + new (p + i) U(); + return p; + } + + template + static inline void destroy_array(U* p, size_t count) + { + if (p != nullptr) { + assert(count > 0); + for (size_t i = count; i != 0; ) + (p + --i)->~U(); + } + aligned_free(p); + } + + template + static inline U* create() + { + void* p = aligned_malloc(sizeof(U)); + return p != nullptr ? new (p) U : nullptr; + } + + template + static inline U* create(A1&& a1) + { + void* p = aligned_malloc(sizeof(U)); + return p != nullptr ? new (p) U(std::forward(a1)) : nullptr; + } + + template + static inline void destroy(U* p) + { + if (p != nullptr) + p->~U(); + aligned_free(p); + } + +private: + std::atomic producerListTail; + std::atomic producerCount; + + std::atomic initialBlockPoolIndex; + Block* initialBlockPool; + size_t initialBlockPoolSize; + +#ifndef MCDBGQ_USEDEBUGFREELIST + FreeList freeList; +#else + debug::DebugFreeList freeList; +#endif + + std::atomic implicitProducerHash; + std::atomic implicitProducerHashCount; // Number of slots logically used + ImplicitProducerHash initialImplicitProducerHash; + std::array initialImplicitProducerHashEntries; + std::atomic_flag implicitProducerHashResizeInProgress; + + std::atomic nextExplicitConsumerId; + std::atomic globalExplicitConsumerOffset; + +#ifdef MCDBGQ_NOLOCKFREE_IMPLICITPRODHASH + debug::DebugMutex implicitProdMutex; +#endif + +#ifdef WPI_CQ_QUEUE_INTERNAL_DEBUG + std::atomic explicitProducers; + std::atomic implicitProducers; +#endif +}; + + +template +ProducerToken::ProducerToken(ConcurrentQueue& queue) + : producer(queue.recycle_or_create_producer(true)) +{ + if (producer != nullptr) { + producer->token = this; + } +} + +template +ProducerToken::ProducerToken(BlockingConcurrentQueue& queue) + : producer(reinterpret_cast*>(&queue)->recycle_or_create_producer(true)) +{ + if (producer != nullptr) { + producer->token = this; + } +} + +template +ConsumerToken::ConsumerToken(ConcurrentQueue& queue) + : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) +{ + initialOffset = queue.nextExplicitConsumerId.fetch_add(1, std::memory_order_release); + lastKnownGlobalOffset = static_cast(-1); +} + +template +ConsumerToken::ConsumerToken(BlockingConcurrentQueue& queue) + : itemsConsumedFromCurrent(0), currentProducer(nullptr), desiredProducer(nullptr) +{ + initialOffset = reinterpret_cast*>(&queue)->nextExplicitConsumerId.fetch_add(1, std::memory_order_release); + lastKnownGlobalOffset = static_cast(-1); +} + +template +inline void swap(ConcurrentQueue& a, ConcurrentQueue& b) WPI_CQ_NOEXCEPT +{ + a.swap(b); +} + +inline void swap(ProducerToken& a, ProducerToken& b) WPI_CQ_NOEXCEPT +{ + a.swap(b); +} + +inline void swap(ConsumerToken& a, ConsumerToken& b) WPI_CQ_NOEXCEPT +{ + a.swap(b); +} + +template +inline void swap(typename ConcurrentQueue::ImplicitProducerKVP& a, typename ConcurrentQueue::ImplicitProducerKVP& b) WPI_CQ_NOEXCEPT +{ + a.swap(b); +} + +} + +#if defined(_MSC_VER) && (!defined(_HAS_CXX17) || !_HAS_CXX17) +#pragma warning(pop) +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#pragma GCC diagnostic pop +#endif diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp index 3ee53a2d832..158a256855e 100644 --- a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp +++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp @@ -259,10 +259,14 @@ static std::unique_ptr GetMemoryBufferForStream( return GetMemBufferCopyImpl(buffer, bufferName, ec); } -std::unique_ptr MemoryBuffer::GetFile(std::string_view filename, - std::error_code& ec, - int64_t fileSize) { - return GetFileAux(filename, ec, fileSize, fileSize, 0); +wpi::expected, std::error_code> +MemoryBuffer::GetFile(std::string_view filename, int64_t fileSize) { + std::error_code ec; + auto ret = GetFileAux(filename, ec, fileSize, fileSize, 0); + if (ec) { + return wpi::unexpected{ec}; + } + return ret; } template diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h index b5eaea406f2..b3b62809603 100644 --- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h +++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h @@ -24,6 +24,7 @@ #include #include #include +#include // Duplicated from fs.h to avoid a dependency namespace fs { @@ -77,9 +78,8 @@ class MemoryBuffer { /// if successful, otherwise returning null. If FileSize is specified, this /// means that the client knows that the file exists and that it has the /// specified size. - static std::unique_ptr GetFile(std::string_view filename, - std::error_code& ec, - int64_t fileSize = -1); + static wpi::expected, std::error_code> + GetFile(std::string_view filename, int64_t fileSize = -1); /// Read all of the specified file into a MemoryBuffer as a stream /// (i.e. until EOF reached). This is useful for special files that diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h index 0edee8532b1..23df3271387 100644 --- a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h +++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h @@ -680,7 +680,7 @@ inline std::optional parse_integer(std::string_view str, static_cast(static_cast(val)) != val) { return std::nullopt; } - return val; + return static_cast(val); } /** diff --git a/wpiutil/src/main/native/unix/Demangle.cpp b/wpiutil/src/main/native/unix/Demangle.cpp index 69404ed792b..d376879b4c3 100644 --- a/wpiutil/src/main/native/unix/Demangle.cpp +++ b/wpiutil/src/main/native/unix/Demangle.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "wpi/SmallString.h" diff --git a/wpiutil/src/main/native/unix/StackTrace.cpp b/wpiutil/src/main/native/unix/StackTrace.cpp index 3b6606533b7..c0d9e546581 100644 --- a/wpiutil/src/main/native/unix/StackTrace.cpp +++ b/wpiutil/src/main/native/unix/StackTrace.cpp @@ -6,6 +6,8 @@ #include +#include + #include "wpi/Demangle.h" #include "wpi/SmallString.h" #include "wpi/StringExtras.h" diff --git a/wpiutil/src/main/native/windows/Demangle.cpp b/wpiutil/src/main/native/windows/Demangle.cpp index 18be3711f5b..f5a51bb3bd2 100644 --- a/wpiutil/src/main/native/windows/Demangle.cpp +++ b/wpiutil/src/main/native/windows/Demangle.cpp @@ -8,6 +8,8 @@ #include +#include + #include "wpi/SmallString.h" #include "wpi/mutex.h" diff --git a/wpiutil/src/main/native/windows/StackTrace.cpp b/wpiutil/src/main/native/windows/StackTrace.cpp index 5df8a6af7ac..db17bf8e83c 100644 --- a/wpiutil/src/main/native/windows/StackTrace.cpp +++ b/wpiutil/src/main/native/windows/StackTrace.cpp @@ -4,6 +4,8 @@ #include "wpi/StackTrace.h" +#include + #include "StackWalker.h" #include "wpi/ConvertUTF.h" #include "wpi/SmallString.h" diff --git a/wpiutil/src/test/native/cpp/Base64Test.cpp b/wpiutil/src/test/native/cpp/Base64Test.cpp index 9db43495033..b7ce945c58e 100644 --- a/wpiutil/src/test/native/cpp/Base64Test.cpp +++ b/wpiutil/src/test/native/cpp/Base64Test.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "wpi/Base64.h" diff --git a/wpiutil/src/test/native/cpp/DataLogTest.cpp b/wpiutil/src/test/native/cpp/DataLogTest.cpp index cc94adf88fa..149d3a36b78 100644 --- a/wpiutil/src/test/native/cpp/DataLogTest.cpp +++ b/wpiutil/src/test/native/cpp/DataLogTest.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include diff --git a/wpiutil/src/test/native/cpp/FileLoggerTest.cpp b/wpiutil/src/test/native/cpp/FileLoggerTest.cpp new file mode 100644 index 00000000000..0fbb54f160e --- /dev/null +++ b/wpiutil/src/test/native/cpp/FileLoggerTest.cpp @@ -0,0 +1,53 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#include +#include +#include + +#include + +#include "wpi/FileLogger.h" + +TEST(FileLoggerTest, LineBufferSingleLine) { + std::vector buf; + auto func = wpi::FileLogger::LineBuffer( + [&buf](std::string_view line) { buf.emplace_back(line); }); + func("qwertyuiop\n"); + EXPECT_EQ(buf.front(), "qwertyuiop"); + buf.clear(); +} + +TEST(FileLoggerTest, LineBufferMultiLine) { + std::vector buf; + auto func = wpi::FileLogger::LineBuffer( + [&buf](std::string_view line) { buf.emplace_back(line); }); + func("line 1\nline 2\nline 3\n"); + EXPECT_EQ("line 1", buf[0]); + EXPECT_EQ("line 2", buf[1]); + EXPECT_EQ("line 3", buf[2]); +} + +TEST(FileLoggerTest, LineBufferPartials) { + std::vector buf; + auto func = wpi::FileLogger::LineBuffer( + [&buf](std::string_view line) { buf.emplace_back(line); }); + func("part 1"); + func("part 2\npart 3"); + EXPECT_EQ("part 1part 2", buf.front()); + buf.clear(); + func("\n"); + EXPECT_EQ("part 3", buf.front()); +} + +TEST(FileLoggerTest, LineBufferMultiplePartials) { + std::vector buf; + auto func = wpi::FileLogger::LineBuffer( + [&buf](std::string_view line) { buf.emplace_back(line); }); + func("part 1"); + func("part 2"); + func("part 3"); + func("part 4\n"); + EXPECT_EQ("part 1part 2part 3part 4", buf.front()); +} diff --git a/wpiutil/src/test/native/cpp/ScopeExitTest.cpp b/wpiutil/src/test/native/cpp/ScopeExitTest.cpp index d6f99cabbab..14cad45b8ca 100644 --- a/wpiutil/src/test/native/cpp/ScopeExitTest.cpp +++ b/wpiutil/src/test/native/cpp/ScopeExitTest.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include + #include #include "wpi/scope" diff --git a/wpiutil/src/test/native/cpp/UidVectorTest.cpp b/wpiutil/src/test/native/cpp/UidVectorTest.cpp index dda7d79c3f7..724afced522 100644 --- a/wpiutil/src/test/native/cpp/UidVectorTest.cpp +++ b/wpiutil/src/test/native/cpp/UidVectorTest.cpp @@ -4,6 +4,8 @@ #include "wpi/UidVector.h" // NOLINT(build/include_order) +#include + #include namespace wpi { diff --git a/wpiutil/src/test/native/cpp/argparse/ArgumentParserTest.cpp b/wpiutil/src/test/native/cpp/argparse/ArgumentParserTest.cpp new file mode 100644 index 00000000000..a0388a84397 --- /dev/null +++ b/wpiutil/src/test/native/cpp/argparse/ArgumentParserTest.cpp @@ -0,0 +1,18 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#include + +#include "wpi/argparse.h" + +TEST(ArgparseTest, Basic) { + wpi::ArgumentParser program("ArgparseTest"); + + program.add_argument("test").help("Test argument").scan<'i', int>(); + + constexpr const char* args[] = {"foo", "42"}; + EXPECT_NO_THROW(program.parse_args(2, args)); + auto result = program.get("test"); + EXPECT_EQ(42, result); +} diff --git a/wpiutil/src/test/native/cpp/concurrentqueue/ConcurrentQueueTest.cpp b/wpiutil/src/test/native/cpp/concurrentqueue/ConcurrentQueueTest.cpp new file mode 100644 index 00000000000..b6f294a2fcb --- /dev/null +++ b/wpiutil/src/test/native/cpp/concurrentqueue/ConcurrentQueueTest.cpp @@ -0,0 +1,17 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#include + +#include "wpi/concurrentqueue.h" + +TEST(ConcurrentQueueTest, Basic) { + wpi::ConcurrentQueue q; + q.enqueue(25); + + int item; + bool found = q.try_dequeue(item); + EXPECT_TRUE(found); + EXPECT_EQ(item, 25); +} diff --git a/wpiutil/src/test/native/cpp/expected/ExpectedTest.cpp b/wpiutil/src/test/native/cpp/expected/ExpectedTest.cpp index f3c9150586d..8d7bc583b5d 100644 --- a/wpiutil/src/test/native/cpp/expected/ExpectedTest.cpp +++ b/wpiutil/src/test/native/cpp/expected/ExpectedTest.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include diff --git a/wpiutil/src/test/native/cpp/future_test.cpp b/wpiutil/src/test/native/cpp/future_test.cpp index 97e5e608cd9..aad45ea4901 100644 --- a/wpiutil/src/test/native/cpp/future_test.cpp +++ b/wpiutil/src/test/native/cpp/future_test.cpp @@ -4,7 +4,7 @@ #include "wpi/future.h" // NOLINT(build/include_order) -#include +#include #include diff --git a/wpiutil/src/test/native/cpp/sigslot/signal-tracking.cpp b/wpiutil/src/test/native/cpp/sigslot/signal-tracking.cpp index b77f5a47492..956f4660e5f 100644 --- a/wpiutil/src/test/native/cpp/sigslot/signal-tracking.cpp +++ b/wpiutil/src/test/native/cpp/sigslot/signal-tracking.cpp @@ -34,6 +34,7 @@ SOFTWARE. #include "wpi/Signal.h" // NOLINT(build/include_order) #include +#include #include #include diff --git a/wpiutil/src/test/native/cpp/sigslot/signal.cpp b/wpiutil/src/test/native/cpp/sigslot/signal.cpp index 34d149e7621..5886ae931a7 100644 --- a/wpiutil/src/test/native/cpp/sigslot/signal.cpp +++ b/wpiutil/src/test/native/cpp/sigslot/signal.cpp @@ -36,6 +36,7 @@ SOFTWARE. #include #include #include +#include #include diff --git a/wpiutil/src/test/native/cpp/struct/DynamicStructTest.cpp b/wpiutil/src/test/native/cpp/struct/DynamicStructTest.cpp index b0d43ffd069..9741667be06 100644 --- a/wpiutil/src/test/native/cpp/struct/DynamicStructTest.cpp +++ b/wpiutil/src/test/native/cpp/struct/DynamicStructTest.cpp @@ -6,6 +6,8 @@ #include +#include + #include using namespace wpi; diff --git a/xrpVendordep/XRPVendordep.json b/xrpVendordep/XRPVendordep.json index 3c7f1a1b7b7..28401fb933c 100644 --- a/xrpVendordep/XRPVendordep.json +++ b/xrpVendordep/XRPVendordep.json @@ -3,7 +3,7 @@ "name": "XRP-Vendordep", "version": "1.0.0", "uuid": "1571a1a5-ed3f-4f07-b7eb-b2beb17394e0", - "frcYear": "2024", + "frcYear": "2025", "mavenUrls": [], "jsonUrl": "", "javaDependencies": [ diff --git a/xrpVendordep/src/main/java/edu/wpi/first/wpilibj/xrp/XRPGyro.java b/xrpVendordep/src/main/java/edu/wpi/first/wpilibj/xrp/XRPGyro.java index b1b8199e62e..1c6403edfed 100644 --- a/xrpVendordep/src/main/java/edu/wpi/first/wpilibj/xrp/XRPGyro.java +++ b/xrpVendordep/src/main/java/edu/wpi/first/wpilibj/xrp/XRPGyro.java @@ -7,6 +7,7 @@ import edu.wpi.first.hal.SimDevice; import edu.wpi.first.hal.SimDevice.Direction; import edu.wpi.first.hal.SimDouble; +import edu.wpi.first.math.geometry.Rotation2d; /** * Use a rate gyro to return the robots heading relative to a starting position. @@ -154,6 +155,15 @@ public double getAngle() { return getAngleZ(); } + /** + * Gets the angle the robot is facing. + * + * @return A Rotation2d with the current heading. + */ + public Rotation2d getRotation2d() { + return Rotation2d.fromDegrees(getAngle()); + } + /** * Return the rate of rotation of the gyro * diff --git a/xrpVendordep/src/main/native/cpp/xrp/XRPGyro.cpp b/xrpVendordep/src/main/native/cpp/xrp/XRPGyro.cpp index 46bf6180f53..50127e55514 100644 --- a/xrpVendordep/src/main/native/cpp/xrp/XRPGyro.cpp +++ b/xrpVendordep/src/main/native/cpp/xrp/XRPGyro.cpp @@ -4,6 +4,8 @@ #include "frc/xrp/XRPGyro.h" +#include + using namespace frc; XRPGyro::XRPGyro() : m_simDevice("Gyro:XRPGyro") { @@ -28,6 +30,10 @@ double XRPGyro::GetAngle() const { return GetAngleZ(); } +frc::Rotation2d XRPGyro::GetRotation2d() const { + return frc::Rotation2d{units::degree_t{GetAngle()}}; +} + double XRPGyro::GetRate() const { return GetRateZ(); } diff --git a/xrpVendordep/src/main/native/cpp/xrp/XRPMotor.cpp b/xrpVendordep/src/main/native/cpp/xrp/XRPMotor.cpp index 91740798ae1..4e63f496102 100644 --- a/xrpVendordep/src/main/native/cpp/xrp/XRPMotor.cpp +++ b/xrpVendordep/src/main/native/cpp/xrp/XRPMotor.cpp @@ -6,6 +6,10 @@ #include +#include +#include +#include + using namespace frc; std::map XRPMotor::s_simDeviceMap = { diff --git a/xrpVendordep/src/main/native/cpp/xrp/XRPServo.cpp b/xrpVendordep/src/main/native/cpp/xrp/XRPServo.cpp index 01635cdcc65..f7233de22a7 100644 --- a/xrpVendordep/src/main/native/cpp/xrp/XRPServo.cpp +++ b/xrpVendordep/src/main/native/cpp/xrp/XRPServo.cpp @@ -6,6 +6,10 @@ #include +#include +#include +#include + using namespace frc; std::map XRPServo::s_simDeviceMap = {{4, "servo1"}, diff --git a/xrpVendordep/src/main/native/include/frc/xrp/XRPGyro.h b/xrpVendordep/src/main/native/include/frc/xrp/XRPGyro.h index 1cf49a77105..e32bd753fda 100644 --- a/xrpVendordep/src/main/native/include/frc/xrp/XRPGyro.h +++ b/xrpVendordep/src/main/native/include/frc/xrp/XRPGyro.h @@ -4,6 +4,8 @@ #pragma once +#include + #include namespace frc { @@ -40,6 +42,13 @@ class XRPGyro { */ double GetAngle() const; + /** + * Gets the angle the robot is facing. + * + * @return A Rotation2d with the current heading. + */ + frc::Rotation2d GetRotation2d() const; + /** * Return the rate of rotation of the gyro *