From 33a08e105c17625daa75c56086dcd5605058946c Mon Sep 17 00:00:00 2001 From: Ryan <16667079+mccaffers@users.noreply.github.com> Date: Wed, 5 Feb 2025 06:44:24 +0000 Subject: [PATCH 01/19] Added a trade manager to record open trades, with actions to reset and close trades, plus some XCTests --- .github/workflows/brew.sh | 12 ++-- .github/workflows/sonarcloud.yml | 12 +++- .vscode/settings.json | 67 +++++++++++++++++++ CMakeLists.txt | 2 + README.md | 2 +- .../project.pbxproj | 44 ++++++++++++ .../xcshareddata/WorkspaceSettings.xcsettings | 5 ++ scripts/run.sh | 32 ++++++++- source/include/models/trade.hpp | 38 +++++++++++ source/include/trading/tradeManager.hpp | 66 ++++++++++++++++++ source/main.cpp | 21 +++++- source/models/trade.cpp | 10 +++ source/trading/tradeManager.cpp | 9 +++ tests/tradeManager.mm | 58 ++++++++++++++++ 14 files changed, 367 insertions(+), 11 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 backtesting-engine-cpp.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 source/include/models/trade.hpp create mode 100644 source/include/trading/tradeManager.hpp create mode 100644 source/models/trade.cpp create mode 100644 source/trading/tradeManager.cpp create mode 100644 tests/tradeManager.mm diff --git a/.github/workflows/brew.sh b/.github/workflows/brew.sh index 5e03be3..c0f9188 100644 --- a/.github/workflows/brew.sh +++ b/.github/workflows/brew.sh @@ -1,15 +1,15 @@ #!/bin/bash -# Check if a package is already installed via Homebrew, then skip +# Function to check if a package is already installed via Homebrew, then skip installation if it is check_and_install() { if ! brew list $1 &>/dev/null; then - echo "Installing $1..." - brew install $1 + echo "Installing $1..." # Inform the user that the package is being installed + brew install $1 # Install the package using Homebrew else - echo "$1 is already installed" + echo "$1 is already installed" # Inform the user that the package is already installed fi } # Install packages if they don't exist -check_and_install postgresql -check_and_install pkg-config \ No newline at end of file +check_and_install postgresql # Check and install PostgreSQL +check_and_install pkg-config # Check and install pkg-config \ No newline at end of file diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index b84ab97..44b573f 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -74,7 +74,8 @@ jobs: with: path: sonarqube-generic-coverage.xml retention-days: 1 - + + # This block takes the artifact generated from the build step and uses it for SonarCloud analysis sonar-scan: name: SonarCloud Scan runs-on: ubuntu-latest @@ -109,13 +110,22 @@ jobs: # https://github.com/SonarSource/sonarqube-scan-action - name: Install Build Wrapper uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v4.2.1 + # This step installs the SonarQube build wrapper, which is necessary for analyzing C/C++ projects. + + # Downloads all artifacts generated by previous steps in the workflow - name: Download all workflow run artifacts uses: actions/download-artifact@v4 + + # Configures the CMake build system, specifying the source directory and build directory, and setting the build type - name: Configure CMake run: cmake -S ${{github.workspace}} -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + + # Runs the build wrapper to capture build commands and outputs them to the specified directory. Then builds the project using CMake - name: Run build-wrapper run: | build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + # Performs the SonarQube scan using the scan action. Uses captured build commands for analysis and requires GitHub and SonarQube tokens for authentication - name: SonarQube Scan uses: SonarSource/sonarqube-scan-action@v4.2.1 env: diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..487a355 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,67 @@ +{ + "files.associations": { + "unordered_map": "cpp", + "__bit_reference": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__node_handle": "cpp", + "__split_buffer": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__verbose_abort": "cpp", + "any": "cpp", + "array": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "complex": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "execution": "cpp", + "memory": "cpp", + "forward_list": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "mutex": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "print": "cpp", + "queue": "cpp", + "ratio": "cpp", + "regex": "cpp", + "set": "cpp", + "source_location": "cpp", + "span": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "tuple": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "variant": "cpp", + "vector": "cpp", + "algorithm": "cpp" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ddb6c7..29cd38c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,8 @@ add_subdirectory(external/libpqxx EXCLUDE_FROM_ALL) include_directories( ${CMAKE_SOURCE_DIR}/source/include ${CMAKE_SOURCE_DIR}/source/include/utilities + ${CMAKE_SOURCE_DIR}/source/include/models + ${CMAKE_SOURCE_DIR}/source/include/trading ${CMAKE_SOURCE_DIR}/source/include/trading_definitions ${CMAKE_SOURCE_DIR}/external ) diff --git a/README.md b/README.md index 216339d..e51d963 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Xcode - Library Path "/opt/homebrew/Cellar/postgresql@14/14.15/lib/postgresql@14" ``` -### Test build with cmake +### Test the build `sh ./scripts/build.sh` diff --git a/backtesting-engine-cpp.xcodeproj/project.pbxproj b/backtesting-engine-cpp.xcodeproj/project.pbxproj index 466e57a..eccccb0 100644 --- a/backtesting-engine-cpp.xcodeproj/project.pbxproj +++ b/backtesting-engine-cpp.xcodeproj/project.pbxproj @@ -17,6 +17,11 @@ 94280BA42D2FC00200F1CF56 /* base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94280BA22D2FC00200F1CF56 /* base64.cpp */; }; 94364CB62D416D8D00F35B55 /* db.mm in Sources */ = {isa = PBXBuildFile; fileRef = 94364CB52D416D8000F35B55 /* db.mm */; }; 944698852D3A545B0070E30F /* libpq.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 94CD8A972D2D34A100041BBA /* libpq.a */; }; + 94674B872D533B4000973137 /* tradeManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94674B852D533B4000973137 /* tradeManager.cpp */; }; + 94674B882D533B4000973137 /* tradeManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94674B852D533B4000973137 /* tradeManager.cpp */; }; + 94674B8A2D533BDA00973137 /* tradeManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 94674B892D533BDA00973137 /* tradeManager.mm */; }; + 94674B8D2D533E7800973137 /* trade.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94674B8B2D533E7800973137 /* trade.cpp */; }; + 94674B8E2D533E7800973137 /* trade.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94674B8B2D533E7800973137 /* trade.cpp */; }; 9470B5A42C8C5AD0007D9CC6 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9470B5A32C8C5AD0007D9CC6 /* main.cpp */; }; 9470B5B62C8C5BFD007D9CC6 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9470B5A32C8C5AD0007D9CC6 /* main.cpp */; }; 94CD8B992D2DCDD800041BBA /* libpqxx-7.10.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 94CD8B982D2DCDD800041BBA /* libpqxx-7.10.a */; }; @@ -65,6 +70,11 @@ 944D0DD02C8C3704004DD0FC /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 944D0DD12C8C3704004DD0FC /* random-indices-sp500-variable.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "random-indices-sp500-variable.svg"; sourceTree = ""; }; 944D0DD32C8C3704004DD0FC /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 94674B822D533B1D00973137 /* trade.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = trade.hpp; sourceTree = ""; }; + 94674B832D533B2F00973137 /* tradeManager.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = tradeManager.hpp; sourceTree = ""; }; + 94674B852D533B4000973137 /* tradeManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = tradeManager.cpp; sourceTree = ""; }; + 94674B892D533BDA00973137 /* tradeManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = tradeManager.mm; sourceTree = ""; }; + 94674B8B2D533E7800973137 /* trade.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = trade.cpp; sourceTree = ""; }; 94685CCE2D384A8B00863D04 /* json.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json.hpp; sourceTree = ""; }; 9470B5A12C8C5AD0007D9CC6 /* source */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = source; sourceTree = BUILT_PRODUCTS_DIR; }; 9470B5A32C8C5AD0007D9CC6 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; @@ -1289,6 +1299,7 @@ 942966D72D48E84100532862 /* models */ = { isa = PBXGroup; children = ( + 94674B822D533B1D00973137 /* trade.hpp */, 942966D82D48E84A00532862 /* priceData.hpp */, ); path = models; @@ -1343,6 +1354,30 @@ path = images; sourceTree = ""; }; + 94674B842D533B2F00973137 /* trading */ = { + isa = PBXGroup; + children = ( + 94674B832D533B2F00973137 /* tradeManager.hpp */, + ); + path = trading; + sourceTree = ""; + }; + 94674B862D533B4000973137 /* trading */ = { + isa = PBXGroup; + children = ( + 94674B852D533B4000973137 /* tradeManager.cpp */, + ); + path = trading; + sourceTree = ""; + }; + 94674B8C2D533E7800973137 /* models */ = { + isa = PBXGroup; + children = ( + 94674B8B2D533E7800973137 /* trade.cpp */, + ); + path = models; + sourceTree = ""; + }; 94685CCF2D384A8B00863D04 /* nlohmann */ = { isa = PBXGroup; children = ( @@ -1354,6 +1389,8 @@ 9470B5A22C8C5AD0007D9CC6 /* source */ = { isa = PBXGroup; children = ( + 94674B8C2D533E7800973137 /* models */, + 94674B862D533B4000973137 /* trading */, 94DE4F772C8C3E7C00FE48FF /* include */, 941B54982D3BBAD800E3BF64 /* trading_definitions */, 94280BA72D2FC29F00F1CF56 /* utilities */, @@ -1368,6 +1405,7 @@ 9470B5AD2C8C5B99007D9CC6 /* tests */ = { isa = PBXGroup; children = ( + 94674B892D533BDA00973137 /* tradeManager.mm */, 94364CB52D416D8000F35B55 /* db.mm */, ); path = tests; @@ -3464,6 +3502,7 @@ 94DE4F772C8C3E7C00FE48FF /* include */ = { isa = PBXGroup; children = ( + 94674B842D533B2F00973137 /* trading */, 942966D72D48E84100532862 /* models */, 94B8C7932D3D770800E17EB6 /* utilities */, 941B548F2D3BBA3B00E3BF64 /* trading_definitions */, @@ -3570,7 +3609,9 @@ files = ( 9470B5A42C8C5AD0007D9CC6 /* main.cpp in Sources */, 94280BA32D2FC00200F1CF56 /* base64.cpp in Sources */, + 94674B8E2D533E7800973137 /* trade.cpp in Sources */, 941B549B2D3BBADE00E3BF64 /* trading_definitions_json.cpp in Sources */, + 94674B872D533B4000973137 /* tradeManager.cpp in Sources */, 94CD8BA02D2E8CE500041BBA /* databaseConnection.cpp in Sources */, 940A61132C92CE210083FEB8 /* configManager.cpp in Sources */, 940A61172C92CE960083FEB8 /* serviceA.cpp in Sources */, @@ -3583,8 +3624,11 @@ files = ( 94CD8BA12D2E8CE500041BBA /* databaseConnection.cpp in Sources */, 94280BA42D2FC00200F1CF56 /* base64.cpp in Sources */, + 94674B8D2D533E7800973137 /* trade.cpp in Sources */, 941B549A2D3BBADE00E3BF64 /* trading_definitions_json.cpp in Sources */, + 94674B8A2D533BDA00973137 /* tradeManager.mm in Sources */, 940A61182C92CE960083FEB8 /* serviceA.cpp in Sources */, + 94674B882D533B4000973137 /* tradeManager.cpp in Sources */, 9470B5B62C8C5BFD007D9CC6 /* main.cpp in Sources */, 94364CB62D416D8D00F35B55 /* db.mm in Sources */, 940A61142C92CE210083FEB8 /* configManager.cpp in Sources */, diff --git a/backtesting-engine-cpp.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/backtesting-engine-cpp.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/backtesting-engine-cpp.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/scripts/run.sh b/scripts/run.sh index 5a82e40..79e8dd8 100644 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -17,7 +17,37 @@ else exit 1 fi +json='{ + "RUN_ID": "UNIQUE_IDENTIFER", + "SYMBOLS": "EURUSD", + "LAST_MONTHS": 6, + "STRATEGY": { + "UUID": "", + "TRADING_VARIABLES": { + "STRATEGY": "OHLC_RSI", + "STOP_DISTANCE_IN_PIPS": 1, + "LIMIT_DISTANCE_IN_PIPS": 1, + "TRADING_SIZE": 1 + }, + "OHLC_VARIABLES": [ + { + "OHLC_COUNT": 60, + "OHLC_MINUTES": 100 + } + ], + "STRATEGY_VARIABLES" : { + "OHLC_RSI_VARIABLES": { + "RSI_LONG": 60, + "RSI_SHORT": 40 + } + } + } +}' + +output=$(echo "$json" | base64) + + # Step 6: Run the tests for now (/executable) from the root directory # Passing two arguements, the destination of the QuestDB and the Strategy JSON (in base64) -./"$BUILD_DIR/$EXECUTABLE_NAME" localhost ewogICJSVU5fSUQiOiAiaWQiLAogICJTWU1CT0xTIjogIkVVUlVTRCIsCiAgIkxBU1RfTU9OVEhTIjogNiwKICAiU1RSQVRFR1kiOiB7CiAgICAgICJVVUlEIjogIiIsCiAgICAgICJUUkFESU5HX1ZBUklBQkxFUyI6IHsKICAgICAgICAgICJTVFJBVEVHWSI6ICJPSExDX1JTSSIsCiAgICAgICAgICAiU1RPUF9ESVNUQU5DRV9JTl9QSVBTIjogMSwKICAgICAgICAgICJMSU1JVF9ESVNUQU5DRV9JTl9QSVBTIjogMSwKICAgICAgICAgICJUUkFESU5HX1NJWkUiOiAxCiAgICAgIH0sCiAgICAgICJPSExDX1ZBUklBQkxFUyI6IFsKICAgICAgICAgIHsKICAgICAgICAgICAgICAiT0hMQ19DT1VOVCI6IDYwLAogICAgICAgICAgICAgICJPSExDX01JTlVURVMiOiAxMDAKICAgICAgICAgIH0KICAgICAgXSwKICAgICAgIk9ITENfUlNJX1ZBUklBQkxFUyI6IHsKICAgICAgICAgICJSU0lfTE9ORyI6IDYwLAogICAgICAgICAgIlJTSV9TSE9SVCI6IDQwCiAgICAgIH0KICB9Cn0K +./"$BUILD_DIR/$EXECUTABLE_NAME" localhost "$output" diff --git a/source/include/models/trade.hpp b/source/include/models/trade.hpp new file mode 100644 index 0000000..29eb4f5 --- /dev/null +++ b/source/include/models/trade.hpp @@ -0,0 +1,38 @@ +// Backtesting Engine in C++ +// +// (c) 2025 Ryan McCaffery | https://mccaffers.com +// This code is licensed under MIT license (see LICENSE.txt for details) +// --------------------------------------- + +#pragma once +#include +#include + +struct Trade { + static int idCounter; + std::string id; + double entryPrice; + double size; + std::chrono::system_clock::time_point openTime; + bool isLong; + + // Default constructor + Trade() : entryPrice(0), size(0), isLong(false), + openTime(std::chrono::system_clock::now()) {} + + // Copy constructor + Trade(const Trade& other) = default; + + Trade(double price, double quantity, bool long_position) + : entryPrice(price), + size(quantity), + isLong(long_position), + openTime(std::chrono::system_clock::now()) { + // Generate unique ID using counter + id = std::to_string(++idCounter); + } + + static void resetCounter() { + idCounter = 0; + } +}; diff --git a/source/include/trading/tradeManager.hpp b/source/include/trading/tradeManager.hpp new file mode 100644 index 0000000..f99b70a --- /dev/null +++ b/source/include/trading/tradeManager.hpp @@ -0,0 +1,66 @@ +// Backtesting Engine in C++ +// +// (c) 2025 Ryan McCaffery | https://mccaffers.com +// This code is licensed under MIT license (see LICENSE.txt for details) +// --------------------------------------- + +#pragma once +#include +#include +#include "trade.hpp" + +class TradeManager { +private: + static TradeManager* instance; + std::unordered_map activeTrades; + + // Private constructor for singleton + TradeManager() = default; + +public: + static TradeManager* getInstance() { + if (instance == nullptr) { + instance = new TradeManager(); + } + return instance; + } + + // Add reset method for testing + static void reset() { + delete instance; + instance = nullptr; + Trade::resetCounter(); // Reset the trade ID counter + } + + // Clear all trades + void clearAllTrades() { + activeTrades.clear(); + } + + // Open a new trade + std::string openTrade(double price, double size, bool isLong) { + Trade trade(price, size, isLong); + activeTrades[trade.id] = trade; + return trade.id; + } + + // Review account - returns number of open trades + size_t reviewAccount() const { + return activeTrades.size(); + } + + // Close a trade + bool closeTrade(const std::string& tradeId) { + auto it = activeTrades.find(tradeId); + if (it != activeTrades.end()) { + activeTrades.erase(it); + return true; + } + return false; + } + + // Get active trades + const std::unordered_map& getActiveTrades() const { + return activeTrades; + } +}; diff --git a/source/main.cpp b/source/main.cpp index fc498b9..d244306 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -19,6 +19,7 @@ #include "databaseConnection.hpp" #include "base64.hpp" #include "trading_definitions.hpp" // For everything +#include "tradeManager.hpp" using json = nlohmann::json; @@ -57,8 +58,24 @@ int main(int argc, const char * argv[]) { // Example query - replace with your actual query std::string query = "SELECT * FROM EURUSD LIMIT 5;"; - db.executeQuery(query); + std::vector priceData = db.executeQuery(query); + + std::cout << priceData[0].timestamp; + + auto tradeManager = TradeManager::getInstance(); + + // Open a trade + std::string tradeId = tradeManager->openTrade(1.2345, 100000, true); + std::cout << "Opened trade: " << tradeId << std::endl; -return 0; + // Review account + size_t openTrades = tradeManager->reviewAccount(); + std::cout << "Number of open trades: " << openTrades << std::endl; + + // Close trade + bool closed = tradeManager->closeTrade(tradeId); + std::cout << "Trade closed: " << (closed ? "yes" : "no") << std::endl; + + return 0; } diff --git a/source/models/trade.cpp b/source/models/trade.cpp new file mode 100644 index 0000000..1ff900e --- /dev/null +++ b/source/models/trade.cpp @@ -0,0 +1,10 @@ +// Backtesting Engine in C++ +// +// (c) 2025 Ryan McCaffery | https://mccaffers.com +// This code is licensed under MIT license (see LICENSE.txt for details) +// --------------------------------------- + +#include "trade.hpp" + +// Definition of static member +int Trade::idCounter = 0; diff --git a/source/trading/tradeManager.cpp b/source/trading/tradeManager.cpp new file mode 100644 index 0000000..3bfdd5c --- /dev/null +++ b/source/trading/tradeManager.cpp @@ -0,0 +1,9 @@ +// Backtesting Engine in C++ +// +// (c) 2025 Ryan McCaffery | https://mccaffers.com +// This code is licensed under MIT license (see LICENSE.txt for details) +// --------------------------------------- + +#include "tradeManager.hpp" + +TradeManager* TradeManager::instance = nullptr; diff --git a/tests/tradeManager.mm b/tests/tradeManager.mm new file mode 100644 index 0000000..1907d50 --- /dev/null +++ b/tests/tradeManager.mm @@ -0,0 +1,58 @@ +// Backtesting Engine in C++ +// +// (c) 2025 Ryan McCaffery | https://mccaffers.com +// This code is licensed under MIT license (see LICENSE.txt for details) +// --------------------------------------- + +#import +#import "tradeManager.hpp" + +@interface TradeManagerTests : XCTestCase +@property (nonatomic) TradeManager* manager; +@end + +@implementation TradeManagerTests + +- (void)setUp { + TradeManager::reset(); // Reset the singleton instance + self.manager = TradeManager::getInstance(); +} + +- (void)tearDown { + self.manager->clearAllTrades(); + TradeManager::reset(); +} + +- (void)testOpenTrade { + std::string tradeId = self.manager->openTrade(100.0, 1.0, true); + XCTAssertFalse(tradeId.empty(), "Trade ID should not be empty"); + XCTAssertEqual(self.manager->reviewAccount(), 1, "Should have 1 active trade"); +} + +- (void)testCloseTrade { + std::string tradeId = self.manager->openTrade(100.0, 1.0, true); + bool closed = self.manager->closeTrade(tradeId); + XCTAssertTrue(closed, "Trade should be closed successfully"); + XCTAssertEqual(self.manager->reviewAccount(), 0, "Should have 0 active trades"); +} + +- (void)testMultipleTrades { + self.manager->openTrade(100.0, 1.0, true); + self.manager->openTrade(200.0, 2.0, false); + self.manager->openTrade(300.0, 3.0, true); + + XCTAssertEqual(self.manager->reviewAccount(), 3, "Should have 3 active trades"); +} + +- (void)testTradeDetails { + std::string tradeId = self.manager->openTrade(100.0, 1.0, true); + auto trades = self.manager->getActiveTrades(); + auto trade = trades.find(tradeId); + + XCTAssertNotEqual(trade, trades.end(), "Trade should exist"); + XCTAssertEqual(trade->second.entryPrice, 100.0, "Entry price should match"); + XCTAssertEqual(trade->second.size, 1.0, "Size should match"); + XCTAssertTrue(trade->second.isLong, "Trade should be long"); +} + +@end From a72935d62d733a1abdfeb9621404e49ecacefb67 Mon Sep 17 00:00:00 2001 From: Ryan <16667079+mccaffers@users.noreply.github.com> Date: Wed, 5 Feb 2025 06:50:38 +0000 Subject: [PATCH 02/19] Fixing the timestamp printing issue in the main.cpp file. . The error occurs because we're trying to directly print a chrono::time_point object, which doesn't have a stream operator overload. --- source/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/main.cpp b/source/main.cpp index d244306..888b976 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include // external headers #include @@ -60,7 +61,9 @@ int main(int argc, const char * argv[]) { std::vector priceData = db.executeQuery(query); - std::cout << priceData[0].timestamp; + // Convert timestamp to readable format for debugging + auto timeT = std::chrono::system_clock::to_time_t(priceData[0].timestamp); + std::cout << "Timestamp: " << std::put_time(std::localtime(&timeT), "%Y-%m-%d %H:%M:%S") << std::endl; auto tradeManager = TradeManager::getInstance(); From 51732b0e8189b9b59bb55ed3bb8e45dcbef326f9 Mon Sep 17 00:00:00 2001 From: Ryan <16667079+mccaffers@users.noreply.github.com> Date: Wed, 5 Feb 2025 07:13:30 +0000 Subject: [PATCH 03/19] Missing the sonarqube test coverage file in the github workjflow --- .github/workflows/sonarcloud.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 44b573f..16de4f6 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -133,4 +133,5 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} with: args: > - --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" \ \ No newline at end of file + --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" \ + -Dsonar.coverageReportPaths=artifact/sonarqube-generic-coverage.xml \ No newline at end of file From f739df1ffccf02627cfcf111b5c4cd0dccb6aeac Mon Sep 17 00:00:00 2001 From: Ryan <16667079+mccaffers@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:32:34 +0000 Subject: [PATCH 04/19] Updating the sonarcloud syntax --- .github/workflows/sonarcloud.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 16de4f6..f49deb6 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -133,5 +133,7 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} with: args: > - --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" \ + -Dsonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json + -Dsonar.cfamily.build-wrapper-output=${{ env.BUILD_WRAPPER_OUT_DIR }} + -Dsonar.coverage.exclusions=tests/**/*,external/**/* -Dsonar.coverageReportPaths=artifact/sonarqube-generic-coverage.xml \ No newline at end of file From 6f51c48879c5ab78a1ca9a76d359aeae44065e6e Mon Sep 17 00:00:00 2001 From: Ryan <16667079+mccaffers@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:39:21 +0000 Subject: [PATCH 05/19] Updating the sonarcloud syntax --- .github/workflows/sonarcloud.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index f49deb6..bce48b7 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -134,6 +134,5 @@ jobs: with: args: > -Dsonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json - -Dsonar.cfamily.build-wrapper-output=${{ env.BUILD_WRAPPER_OUT_DIR }} -Dsonar.coverage.exclusions=tests/**/*,external/**/* -Dsonar.coverageReportPaths=artifact/sonarqube-generic-coverage.xml \ No newline at end of file From c1be6172203e07a2ab0e63af06c4820582a29181 Mon Sep 17 00:00:00 2001 From: Ryan <16667079+mccaffers@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:40:08 +0000 Subject: [PATCH 06/19] Updating the sonarcloud syntax --- .github/workflows/sonarcloud.yml | 1 - sonar-project.properties | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index bce48b7..e835739 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -134,5 +134,4 @@ jobs: with: args: > -Dsonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json - -Dsonar.coverage.exclusions=tests/**/*,external/**/* -Dsonar.coverageReportPaths=artifact/sonarqube-generic-coverage.xml \ No newline at end of file diff --git a/sonar-project.properties b/sonar-project.properties index 7ed5b0f..7f54568 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -4,5 +4,5 @@ sonar.python.version=3.8 sonar.language=c sonar.c.file.suffixes=.c,.h sonar.cpp.file.suffixes=.cc,.cpp,.cxx,.c++,.hh,.hpp,.hxx,.h++,.ipp -sonar.coverage.exclusions=tests/**, source/utilities/base64.cpp +sonar.coverage.exclusions=tests/**, external/**/*, source/utilities/base64.cpp sonar.sources=source/ From bd7516be63c0722f59ebb8a282f1b8433729d41b Mon Sep 17 00:00:00 2001 From: Ryan <16667079+mccaffers@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:52:42 +0000 Subject: [PATCH 07/19] Updating the sonarcloud syntax --- sonar-project.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 7f54568..a958544 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,8 +1,8 @@ sonar.projectKey=mccaffers_backtesting-engine-cpp sonar.organization=mccaffers sonar.python.version=3.8 -sonar.language=c -sonar.c.file.suffixes=.c,.h -sonar.cpp.file.suffixes=.cc,.cpp,.cxx,.c++,.hh,.hpp,.hxx,.h++,.ipp +sonar.language=cpp +sonar.cpp.file.suffixes=.cpp,.hpp,.mm sonar.coverage.exclusions=tests/**, external/**/*, source/utilities/base64.cpp sonar.sources=source/ +sonar.tests=tests/ From ab19cfb4af93d39e011c6ad72695e82caea055e3 Mon Sep 17 00:00:00 2001 From: Ryan <16667079+mccaffers@users.noreply.github.com> Date: Wed, 5 Feb 2025 20:06:41 +0000 Subject: [PATCH 08/19] Updating the sonarcloud syntax --- .github/workflows/sonarcloud.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index e835739..95336e1 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -115,6 +115,11 @@ jobs: # Downloads all artifacts generated by previous steps in the workflow - name: Download all workflow run artifacts uses: actions/download-artifact@v4 + + - name: Check artifacts + run: | + ls -l ./ + ls -l ./artifact/ # Configures the CMake build system, specifying the source directory and build directory, and setting the build type - name: Configure CMake From 19c47ab57a30b5034f09fd7ac6bbf84f6fdf3d0d Mon Sep 17 00:00:00 2001 From: Ryan <16667079+mccaffers@users.noreply.github.com> Date: Wed, 5 Feb 2025 20:34:01 +0000 Subject: [PATCH 09/19] refactoring the github workflow to pick up test coverage --- .github/workflows/cpp_coverage.sh | 6 + .github/workflows/sonarcloud.yml | 16 +- ...Z6X39bWUJhoHaba_eau-EKsOEKfXox3_nhh1Xnbg== | Bin 0 -> 204 bytes ...MYg7qsPastp25n71ro-KS4y9vhm5pIl4iacemMgg== | Bin 0 -> 255 bytes ...DAWolDj4RqbY3qixDR1tBUHlGt9Doftu10FLeF7Q== | Bin 0 -> 2201 bytes ...ueWFhsLFOfvtxGUfP9DWhtwvIunXzwQ2e5x56qEA== | Bin 0 -> 13914 bytes ...imFA5DNH4nM3UQS_LeI8lCBwbwTdpdTBURCvvWWQ== | Bin 0 -> 651 bytes ...paOC6P6QCZPb_rJhQT5PB5BA9nuirtvS0CO692mQ== | Bin 0 -> 6003 bytes ...1D1A5WxNoAthAtSDkObS9kDAWivdIBhLTESkKW6A== | Bin 0 -> 3735 bytes ...C3frGCpIBEDOsGmXthDz_qhddkovi-M-5-jyCUaA== | Bin 0 -> 1351 bytes ...ZaMCfg2RBRU3-kjsyRjm8kCvahTOGvuqeVcG67XA== | Bin 0 -> 272 bytes ...WDzTxeZBLKWd8iDii3okf2wV9yjskMuNQXr9oQTA== | Bin 0 -> 1484 bytes ...otLNPKS4_ZiZk8DoYBkF7bspDO8unXM7a74NdYsg== | Bin 0 -> 270 bytes ...dn4AgU0K4ibnnhcHbzc4ELP6ar0skoF-dxCVhXtw== | Bin 0 -> 269 bytes ...DrbjTZs8hapcvkyEy52mm5ViKS5s1s9Yea8JwScA== | Bin 0 -> 160 bytes ...WU15rLPgOe7OO2uocyEIdZ53LcJucQj1UVJnqhXA== | Bin 0 -> 268 bytes ...-F5ga75TQjJzXUxyw3fTd_NASbes-yWi5na-l0IA== | Bin 0 -> 1274 bytes ...UtzFLQpGnRrPfNTA6b8jurui2E_bG4emeF9tKL8w== | Bin 0 -> 110 bytes ...hEz2yZDekBrGgEKmBAxudGkWKMtRsW-WrmQyoAmQ== | Bin 0 -> 144 bytes ...iifCQyyYnQ0MuVBj2C06nvOeflFLlKkkaWf7F1XQ== | Bin 0 -> 713 bytes ...sIRT0yT0_u9BHHWQ_0FarM3ttnGW0lPF6h-qXMQA== | Bin 0 -> 110 bytes ...PLTL-mL18kp6xAp5Y--h0aSxq6lB5G43BfoQYZEA== | Bin 0 -> 295 bytes ...YENoIq7y9oUSDWL5B_P2gkdtWG8JEsJLxPbdWOZA== | Bin 0 -> 199 bytes ..._WLk4w68WdDOyxvsaPpnsnm9WH3baoQMw68qVsDw== | Bin 0 -> 261 bytes ...EUK6F-uAEmMNsIvG_7-_yO8-JbHHdrItXpqUJcFA== | Bin 0 -> 71 bytes ...PbPA9HfKqMspJyJ-cGSwtX9nnA2Ov742R_MmKJTA== | Bin 0 -> 271 bytes ...DZQG4Qn4AIivyW5FWaBrh9sTHIY549_5lbVgxynA== | Bin 0 -> 16846 bytes ...f0FiAZWSQFlgyuu9dnXl47hfHxR2NZKEzigTkbnQ== | Bin 0 -> 284 bytes ...LqRL2lCPhqmlFH6nTv0eWCej7DNeTqzqCgteBBIg== | Bin 0 -> 268 bytes ...0fvV0MeYbSaqVk0jByjazeYks80chErkx9EvuJqg== | 1 + ...nMxqL2D5subdwYpOkEEwzjcfyxBzXh1c-PFi7R3w== | Bin 0 -> 109 bytes ...kXO9l1E_1afR4RrU_UY81-NNe12NuxNnr-LeN2_g== | Bin 0 -> 4608 bytes ...pnBIDCpaTLgIP0IgkWg5dBaAU4xe8GCqPIN___aw== | Bin 0 -> 273 bytes ...Z6X39bWUJhoHaba_eau-EKsOEKfXox3_nhh1Xnbg== | Bin 0 -> 1 bytes ...MYg7qsPastp25n71ro-KS4y9vhm5pIl4iacemMgg== | Bin 0 -> 1 bytes ...DAWolDj4RqbY3qixDR1tBUHlGt9Doftu10FLeF7Q== | Bin 0 -> 1 bytes ...ueWFhsLFOfvtxGUfP9DWhtwvIunXzwQ2e5x56qEA== | Bin 0 -> 1 bytes ...imFA5DNH4nM3UQS_LeI8lCBwbwTdpdTBURCvvWWQ== | Bin 0 -> 1 bytes ...paOC6P6QCZPb_rJhQT5PB5BA9nuirtvS0CO692mQ== | Bin 0 -> 1 bytes ...1D1A5WxNoAthAtSDkObS9kDAWivdIBhLTESkKW6A== | Bin 0 -> 1 bytes ...C3frGCpIBEDOsGmXthDz_qhddkovi-M-5-jyCUaA== | Bin 0 -> 1 bytes ...ZaMCfg2RBRU3-kjsyRjm8kCvahTOGvuqeVcG67XA== | Bin 0 -> 1 bytes ...WDzTxeZBLKWd8iDii3okf2wV9yjskMuNQXr9oQTA== | Bin 0 -> 1 bytes ...otLNPKS4_ZiZk8DoYBkF7bspDO8unXM7a74NdYsg== | Bin 0 -> 1 bytes ...dn4AgU0K4ibnnhcHbzc4ELP6ar0skoF-dxCVhXtw== | Bin 0 -> 1 bytes ...DrbjTZs8hapcvkyEy52mm5ViKS5s1s9Yea8JwScA== | Bin 0 -> 265 bytes ...WU15rLPgOe7OO2uocyEIdZ53LcJucQj1UVJnqhXA== | Bin 0 -> 1 bytes ...-F5ga75TQjJzXUxyw3fTd_NASbes-yWi5na-l0IA== | Bin 0 -> 331 bytes ...UtzFLQpGnRrPfNTA6b8jurui2E_bG4emeF9tKL8w== | Bin 0 -> 133 bytes ...hEz2yZDekBrGgEKmBAxudGkWKMtRsW-WrmQyoAmQ== | Bin 0 -> 133 bytes ...iifCQyyYnQ0MuVBj2C06nvOeflFLlKkkaWf7F1XQ== | Bin 0 -> 1 bytes ...sIRT0yT0_u9BHHWQ_0FarM3ttnGW0lPF6h-qXMQA== | Bin 0 -> 133 bytes ...PLTL-mL18kp6xAp5Y--h0aSxq6lB5G43BfoQYZEA== | Bin 0 -> 1 bytes ...YENoIq7y9oUSDWL5B_P2gkdtWG8JEsJLxPbdWOZA== | Bin 0 -> 1 bytes ..._WLk4w68WdDOyxvsaPpnsnm9WH3baoQMw68qVsDw== | Bin 0 -> 1 bytes ...EUK6F-uAEmMNsIvG_7-_yO8-JbHHdrItXpqUJcFA== | Bin 0 -> 199 bytes ...PbPA9HfKqMspJyJ-cGSwtX9nnA2Ov742R_MmKJTA== | Bin 0 -> 1 bytes ...DZQG4Qn4AIivyW5FWaBrh9sTHIY549_5lbVgxynA== | Bin 0 -> 1 bytes ...f0FiAZWSQFlgyuu9dnXl47hfHxR2NZKEzigTkbnQ== | Bin 0 -> 1 bytes ...LqRL2lCPhqmlFH6nTv0eWCej7DNeTqzqCgteBBIg== | Bin 0 -> 1 bytes ...0fvV0MeYbSaqVk0jByjazeYks80chErkx9EvuJqg== | Bin 0 -> 67 bytes ...nMxqL2D5subdwYpOkEEwzjcfyxBzXh1c-PFi7R3w== | Bin 0 -> 133 bytes ...kXO9l1E_1afR4RrU_UY81-NNe12NuxNnr-LeN2_g== | Bin 0 -> 595 bytes ...pnBIDCpaTLgIP0IgkWg5dBaAU4xe8GCqPIN___aw== | Bin 0 -> 1 bytes TestResult.xcresult/Info.plist | 29 + coverage.txt | 41380 ++++++++++++++++ sonarqube-generic-coverage.xml | 242 + 67 files changed, 41668 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/cpp_coverage.sh create mode 100644 TestResult.xcresult/Data/data.0~8M9pZfzuOlvEs9ZjbSlAe0rVWJ8kmnWQDltpe79EMhRvEFZ6X39bWUJhoHaba_eau-EKsOEKfXox3_nhh1Xnbg== create mode 100644 TestResult.xcresult/Data/data.0~AZgzWgvJfl_hp1UgOGt0YYZHrm06paXNvPahCxwxAZfj7wMYg7qsPastp25n71ro-KS4y9vhm5pIl4iacemMgg== create mode 100644 TestResult.xcresult/Data/data.0~EvsZQiosdIWIy37EZ1SEE8Sq3UZp3mL9zEdHT7DpAEZObWDAWolDj4RqbY3qixDR1tBUHlGt9Doftu10FLeF7Q== create mode 100644 TestResult.xcresult/Data/data.0~O4DEOstFHYmuXxykISnoXc7h3n8ryTXy1_m0-EeHMoSx05ueWFhsLFOfvtxGUfP9DWhtwvIunXzwQ2e5x56qEA== create mode 100644 TestResult.xcresult/Data/data.0~P8mPpsCgAccGkYH-NlIVANrPETOVC5LNO-0a5uVoD4_A4_imFA5DNH4nM3UQS_LeI8lCBwbwTdpdTBURCvvWWQ== create mode 100644 TestResult.xcresult/Data/data.0~Pusf3h7cIllaVbwQ8M-8N471uf_ERdgI5GLgY5d0b6yeIipaOC6P6QCZPb_rJhQT5PB5BA9nuirtvS0CO692mQ== create mode 100644 TestResult.xcresult/Data/data.0~TLjqpFdxiJIRfuFFhKndD4cSlivVpUA6h7AN6C7c4XK7U31D1A5WxNoAthAtSDkObS9kDAWivdIBhLTESkKW6A== create mode 100644 TestResult.xcresult/Data/data.0~UKl-odyGjSKDjDpqDC06BJcVWKNDHXBJmlQNh0y8cvj4oqC3frGCpIBEDOsGmXthDz_qhddkovi-M-5-jyCUaA== create mode 100644 TestResult.xcresult/Data/data.0~VWThOtGgUglta4VfPcGAE-LoiausHVRiibNzAsPI16nrIuZaMCfg2RBRU3-kjsyRjm8kCvahTOGvuqeVcG67XA== create mode 100644 TestResult.xcresult/Data/data.0~X0nojlcYwh2bDIqHykT3aw-21PvbyxMT_8983gRJgZXpeSWDzTxeZBLKWd8iDii3okf2wV9yjskMuNQXr9oQTA== create mode 100644 TestResult.xcresult/Data/data.0~Z-et4iZHtDgEfNxF25MVPFS2SHuhsXvNCOgqU11xJyaeCvotLNPKS4_ZiZk8DoYBkF7bspDO8unXM7a74NdYsg== create mode 100644 TestResult.xcresult/Data/data.0~Zbr7jYftSGf2opsqmDbQYi9s096-CTteWzDx8WUcUfYYa7dn4AgU0K4ibnnhcHbzc4ELP6ar0skoF-dxCVhXtw== create mode 100644 TestResult.xcresult/Data/data.0~f-TW9ZbQRmAXpxzgDSzOLkBL_jJjK8VgwlMH3eFn41E8Y5DrbjTZs8hapcvkyEy52mm5ViKS5s1s9Yea8JwScA== create mode 100644 TestResult.xcresult/Data/data.0~g5SKenOy8VL12VhBb0f_RJ3OY_jmWfwGzRxk-AZkLfl8j-WU15rLPgOe7OO2uocyEIdZ53LcJucQj1UVJnqhXA== create mode 100644 TestResult.xcresult/Data/data.0~gEbQ04FjnsnQaWq6nbEgbHPxVhg8_TEtlDk5i-GwQKGCfI-F5ga75TQjJzXUxyw3fTd_NASbes-yWi5na-l0IA== create mode 100644 TestResult.xcresult/Data/data.0~hI-qLI9hDhPMkZHvs5rWt4irFW3b2JwrFCCdkGi5xgqJmUUtzFLQpGnRrPfNTA6b8jurui2E_bG4emeF9tKL8w== create mode 100644 TestResult.xcresult/Data/data.0~hTaVfLbwsJoo2uTcCi-7QiMyGgC7Hv6sOrkDxFhn2uxkrnhEz2yZDekBrGgEKmBAxudGkWKMtRsW-WrmQyoAmQ== create mode 100644 TestResult.xcresult/Data/data.0~j2WFeQOZmqAiW_n_xM8-R-5l-mO-UzrPNCMbihZzdFMA3BiifCQyyYnQ0MuVBj2C06nvOeflFLlKkkaWf7F1XQ== create mode 100644 TestResult.xcresult/Data/data.0~jK1PIqv0O3YG0AlNW96sDofVqoyD0B7aPuo6b2tJE2YfyPsIRT0yT0_u9BHHWQ_0FarM3ttnGW0lPF6h-qXMQA== create mode 100644 TestResult.xcresult/Data/data.0~o2VCv2R01qJIr8cxdFCFsQcc7O0occlhJUCzmEuoTv4y6iPLTL-mL18kp6xAp5Y--h0aSxq6lB5G43BfoQYZEA== create mode 100644 TestResult.xcresult/Data/data.0~oRMi0sbQLktfDDDGUS-SqBKpdDiD6HCztVES_ShfGr0KVcYENoIq7y9oUSDWL5B_P2gkdtWG8JEsJLxPbdWOZA== create mode 100644 TestResult.xcresult/Data/data.0~pQIYVMtfbTC-aBUkEgjtq0skFlTpHlzy4tbQqhJlqYP3-M_WLk4w68WdDOyxvsaPpnsnm9WH3baoQMw68qVsDw== create mode 100644 TestResult.xcresult/Data/data.0~tc7j2NnpxbOcWB8CAow6AhIJrYJDr3aWBxvAJ-LdnPEGHvEUK6F-uAEmMNsIvG_7-_yO8-JbHHdrItXpqUJcFA== create mode 100644 TestResult.xcresult/Data/data.0~ubIndH3cSUiHhHhRwER9-zGlJoCiuY6_E3jeJ0mq3DW6zmPbPA9HfKqMspJyJ-cGSwtX9nnA2Ov742R_MmKJTA== create mode 100644 TestResult.xcresult/Data/data.0~uxX7NisootIqCZMb2CKohM3zmuFj3tN7QZUGoDk-QszJmqDZQG4Qn4AIivyW5FWaBrh9sTHIY549_5lbVgxynA== create mode 100644 TestResult.xcresult/Data/data.0~waHVBaCwgME4CJdFPepwWH9vPPmWithPCd1nrnFe550frgf0FiAZWSQFlgyuu9dnXl47hfHxR2NZKEzigTkbnQ== create mode 100644 TestResult.xcresult/Data/data.0~xO4PZsidi9CfdBw7Gw3MQdwc-9TSnJ5Q1gr9kCdmXT_J9yLqRL2lCPhqmlFH6nTv0eWCej7DNeTqzqCgteBBIg== create mode 100644 TestResult.xcresult/Data/data.0~yHBe7-6QVIF_XdGegDRw_3irLFO31xUODLBHU8TaDGYTN20fvV0MeYbSaqVk0jByjazeYks80chErkx9EvuJqg== create mode 100644 TestResult.xcresult/Data/data.0~zK2O6I4jLo1PGm9yMOwpMNRaRixLheCMvIGT5IS_qZg8u2nMxqL2D5subdwYpOkEEwzjcfyxBzXh1c-PFi7R3w== create mode 100644 TestResult.xcresult/Data/data.0~zTgpwVDRktI_jW4przYkFft6Vrwh9Y10xRxQvuk5jMXop8kXO9l1E_1afR4RrU_UY81-NNe12NuxNnr-LeN2_g== create mode 100644 TestResult.xcresult/Data/data.0~zuv5rKNJ1tXoXFU3dFE3k7A5EFZmsGMxKiI2643kHFwZePpnBIDCpaTLgIP0IgkWg5dBaAU4xe8GCqPIN___aw== create mode 100644 TestResult.xcresult/Data/refs.0~8M9pZfzuOlvEs9ZjbSlAe0rVWJ8kmnWQDltpe79EMhRvEFZ6X39bWUJhoHaba_eau-EKsOEKfXox3_nhh1Xnbg== create mode 100644 TestResult.xcresult/Data/refs.0~AZgzWgvJfl_hp1UgOGt0YYZHrm06paXNvPahCxwxAZfj7wMYg7qsPastp25n71ro-KS4y9vhm5pIl4iacemMgg== create mode 100644 TestResult.xcresult/Data/refs.0~EvsZQiosdIWIy37EZ1SEE8Sq3UZp3mL9zEdHT7DpAEZObWDAWolDj4RqbY3qixDR1tBUHlGt9Doftu10FLeF7Q== create mode 100644 TestResult.xcresult/Data/refs.0~O4DEOstFHYmuXxykISnoXc7h3n8ryTXy1_m0-EeHMoSx05ueWFhsLFOfvtxGUfP9DWhtwvIunXzwQ2e5x56qEA== create mode 100644 TestResult.xcresult/Data/refs.0~P8mPpsCgAccGkYH-NlIVANrPETOVC5LNO-0a5uVoD4_A4_imFA5DNH4nM3UQS_LeI8lCBwbwTdpdTBURCvvWWQ== create mode 100644 TestResult.xcresult/Data/refs.0~Pusf3h7cIllaVbwQ8M-8N471uf_ERdgI5GLgY5d0b6yeIipaOC6P6QCZPb_rJhQT5PB5BA9nuirtvS0CO692mQ== create mode 100644 TestResult.xcresult/Data/refs.0~TLjqpFdxiJIRfuFFhKndD4cSlivVpUA6h7AN6C7c4XK7U31D1A5WxNoAthAtSDkObS9kDAWivdIBhLTESkKW6A== create mode 100644 TestResult.xcresult/Data/refs.0~UKl-odyGjSKDjDpqDC06BJcVWKNDHXBJmlQNh0y8cvj4oqC3frGCpIBEDOsGmXthDz_qhddkovi-M-5-jyCUaA== create mode 100644 TestResult.xcresult/Data/refs.0~VWThOtGgUglta4VfPcGAE-LoiausHVRiibNzAsPI16nrIuZaMCfg2RBRU3-kjsyRjm8kCvahTOGvuqeVcG67XA== create mode 100644 TestResult.xcresult/Data/refs.0~X0nojlcYwh2bDIqHykT3aw-21PvbyxMT_8983gRJgZXpeSWDzTxeZBLKWd8iDii3okf2wV9yjskMuNQXr9oQTA== create mode 100644 TestResult.xcresult/Data/refs.0~Z-et4iZHtDgEfNxF25MVPFS2SHuhsXvNCOgqU11xJyaeCvotLNPKS4_ZiZk8DoYBkF7bspDO8unXM7a74NdYsg== create mode 100644 TestResult.xcresult/Data/refs.0~Zbr7jYftSGf2opsqmDbQYi9s096-CTteWzDx8WUcUfYYa7dn4AgU0K4ibnnhcHbzc4ELP6ar0skoF-dxCVhXtw== create mode 100644 TestResult.xcresult/Data/refs.0~f-TW9ZbQRmAXpxzgDSzOLkBL_jJjK8VgwlMH3eFn41E8Y5DrbjTZs8hapcvkyEy52mm5ViKS5s1s9Yea8JwScA== create mode 100644 TestResult.xcresult/Data/refs.0~g5SKenOy8VL12VhBb0f_RJ3OY_jmWfwGzRxk-AZkLfl8j-WU15rLPgOe7OO2uocyEIdZ53LcJucQj1UVJnqhXA== create mode 100644 TestResult.xcresult/Data/refs.0~gEbQ04FjnsnQaWq6nbEgbHPxVhg8_TEtlDk5i-GwQKGCfI-F5ga75TQjJzXUxyw3fTd_NASbes-yWi5na-l0IA== create mode 100644 TestResult.xcresult/Data/refs.0~hI-qLI9hDhPMkZHvs5rWt4irFW3b2JwrFCCdkGi5xgqJmUUtzFLQpGnRrPfNTA6b8jurui2E_bG4emeF9tKL8w== create mode 100644 TestResult.xcresult/Data/refs.0~hTaVfLbwsJoo2uTcCi-7QiMyGgC7Hv6sOrkDxFhn2uxkrnhEz2yZDekBrGgEKmBAxudGkWKMtRsW-WrmQyoAmQ== create mode 100644 TestResult.xcresult/Data/refs.0~j2WFeQOZmqAiW_n_xM8-R-5l-mO-UzrPNCMbihZzdFMA3BiifCQyyYnQ0MuVBj2C06nvOeflFLlKkkaWf7F1XQ== create mode 100644 TestResult.xcresult/Data/refs.0~jK1PIqv0O3YG0AlNW96sDofVqoyD0B7aPuo6b2tJE2YfyPsIRT0yT0_u9BHHWQ_0FarM3ttnGW0lPF6h-qXMQA== create mode 100644 TestResult.xcresult/Data/refs.0~o2VCv2R01qJIr8cxdFCFsQcc7O0occlhJUCzmEuoTv4y6iPLTL-mL18kp6xAp5Y--h0aSxq6lB5G43BfoQYZEA== create mode 100644 TestResult.xcresult/Data/refs.0~oRMi0sbQLktfDDDGUS-SqBKpdDiD6HCztVES_ShfGr0KVcYENoIq7y9oUSDWL5B_P2gkdtWG8JEsJLxPbdWOZA== create mode 100644 TestResult.xcresult/Data/refs.0~pQIYVMtfbTC-aBUkEgjtq0skFlTpHlzy4tbQqhJlqYP3-M_WLk4w68WdDOyxvsaPpnsnm9WH3baoQMw68qVsDw== create mode 100644 TestResult.xcresult/Data/refs.0~tc7j2NnpxbOcWB8CAow6AhIJrYJDr3aWBxvAJ-LdnPEGHvEUK6F-uAEmMNsIvG_7-_yO8-JbHHdrItXpqUJcFA== create mode 100644 TestResult.xcresult/Data/refs.0~ubIndH3cSUiHhHhRwER9-zGlJoCiuY6_E3jeJ0mq3DW6zmPbPA9HfKqMspJyJ-cGSwtX9nnA2Ov742R_MmKJTA== create mode 100644 TestResult.xcresult/Data/refs.0~uxX7NisootIqCZMb2CKohM3zmuFj3tN7QZUGoDk-QszJmqDZQG4Qn4AIivyW5FWaBrh9sTHIY549_5lbVgxynA== create mode 100644 TestResult.xcresult/Data/refs.0~waHVBaCwgME4CJdFPepwWH9vPPmWithPCd1nrnFe550frgf0FiAZWSQFlgyuu9dnXl47hfHxR2NZKEzigTkbnQ== create mode 100644 TestResult.xcresult/Data/refs.0~xO4PZsidi9CfdBw7Gw3MQdwc-9TSnJ5Q1gr9kCdmXT_J9yLqRL2lCPhqmlFH6nTv0eWCej7DNeTqzqCgteBBIg== create mode 100644 TestResult.xcresult/Data/refs.0~yHBe7-6QVIF_XdGegDRw_3irLFO31xUODLBHU8TaDGYTN20fvV0MeYbSaqVk0jByjazeYks80chErkx9EvuJqg== create mode 100644 TestResult.xcresult/Data/refs.0~zK2O6I4jLo1PGm9yMOwpMNRaRixLheCMvIGT5IS_qZg8u2nMxqL2D5subdwYpOkEEwzjcfyxBzXh1c-PFi7R3w== create mode 100644 TestResult.xcresult/Data/refs.0~zTgpwVDRktI_jW4przYkFft6Vrwh9Y10xRxQvuk5jMXop8kXO9l1E_1afR4RrU_UY81-NNe12NuxNnr-LeN2_g== create mode 100644 TestResult.xcresult/Data/refs.0~zuv5rKNJ1tXoXFU3dFE3k7A5EFZmsGMxKiI2643kHFwZePpnBIDCpaTLgIP0IgkWg5dBaAU4xe8GCqPIN___aw== create mode 100644 TestResult.xcresult/Info.plist create mode 100644 coverage.txt create mode 100644 sonarqube-generic-coverage.xml diff --git a/.github/workflows/cpp_coverage.sh b/.github/workflows/cpp_coverage.sh new file mode 100644 index 0000000..70b6c2b --- /dev/null +++ b/.github/workflows/cpp_coverage.sh @@ -0,0 +1,6 @@ +PROFILE_DIR=$(ls -t /tmp/Build/ProfileData | head -n 1); +xcrun llvm-cov show \ + /tmp/Build/Products/Debug/tests.xctest/Contents/MacOS/tests \ + -instr-profile="/tmp/Build/ProfileData/${PROFILE_DIR}/Coverage.profdata" \ + -format=text \ + > coverage.txt \ No newline at end of file diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 95336e1..2524193 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -58,21 +58,24 @@ jobs: -destination 'platform=macOS' -resultBundlePath TestResult/ -enableCodeCoverage YES - -derivedDataPath "${RUNNER_TEMP}/Build/DerivedData" + -derivedDataPath "/tmp" HEADER_SEARCH_PATHS="./external/libpqxx/include/pqxx/internal ./external/libpqxx/include/ ./external/libpqxx/build/include/ ./external/" \ LIBRARY_SEARCH_PATHS="./external/libpqxx/src/ ./external/libpqxx/build/src/" \ OTHER_LDFLAGS="-L./external/libpqxx/build/src -lpqxx -lpq -L/opt/homebrew/Cellar/pkgconf/2.3.0_1/lib -L/opt/homebrew/Cellar/pkgconf/2.3.0_1/lib/pkgconfig -L/opt/homebrew/Cellar/postgresql@14/14.15/lib/postgresql@14 -L/opt/homebrew/Cellar/postgresql@14/14.15/lib/postgresql@14/pgxs -L/opt/homebrew/Cellar/postgresql@14/14.15/lib/postgresql@14/pkgconfig" clean build test | xcpretty -r junit && exit ${PIPESTATUS[0]} - - name: Convert coverage report to sonarqube format - run: > - bash ./.github/workflows/xccov-to-sonarqube-generic.sh *.xcresult/ > sonarqube-generic-coverage.xml + - name: Check artifacts + run: | + sh ./.github/workflows/cpp_coverage.sh + # - name: Convert coverage report to sonarqube format + # run: > + # bash ./.github/workflows/xccov-to-sonarqube-generic.sh *.xcresult/ > sonarqube-generic-coverage.xml # Artifact will be available only for 1 day, this is because # it's only used to pass test data to SonarCloud only - name: Upload coverage report uses: actions/upload-artifact@v4 with: - path: sonarqube-generic-coverage.xml + path: coverage.txt retention-days: 1 # This block takes the artifact generated from the build step and uses it for SonarCloud analysis @@ -139,4 +142,5 @@ jobs: with: args: > -Dsonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json - -Dsonar.coverageReportPaths=artifact/sonarqube-generic-coverage.xml \ No newline at end of file + -Dsonar.sonar.cfamily.gcov.reportsPath=artifact/coverage.txt + # -Dsonar.coverageReportPaths=artifact/sonarqube-generic-coverage.xml \ No newline at end of file diff --git a/TestResult.xcresult/Data/data.0~8M9pZfzuOlvEs9ZjbSlAe0rVWJ8kmnWQDltpe79EMhRvEFZ6X39bWUJhoHaba_eau-EKsOEKfXox3_nhh1Xnbg== b/TestResult.xcresult/Data/data.0~8M9pZfzuOlvEs9ZjbSlAe0rVWJ8kmnWQDltpe79EMhRvEFZ6X39bWUJhoHaba_eau-EKsOEKfXox3_nhh1Xnbg== new file mode 100644 index 0000000000000000000000000000000000000000..0ffed5c4a4863ef48a106ff75b9e52bbea8742a4 GIT binary patch literal 204 zcmV;-05kt6wJ-euNF4?MB1w*Tims&_yy=0w8mr{k6*_8;34yC&G zRy6Wn1}T}P3o z-D!9+6?CUzwV%qY7S!?JBRb9XP)@M$zUxOMp6kw=P;`tG>wKvZGh8sxFL{s%jb&RT<;= zes)Wvc=$!e5g;fyT$C+U(_8?&_cMR*rw|)lbglJ_)s~x!61F5k6a_kX7#i|mYt3lv zUZZ&UMcER)C5ASOq(1DidvPRSk@6%R2K{bf~ktLz&DLd Fkpb|(c!B@` literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~EvsZQiosdIWIy37EZ1SEE8Sq3UZp3mL9zEdHT7DpAEZObWDAWolDj4RqbY3qixDR1tBUHlGt9Doftu10FLeF7Q== b/TestResult.xcresult/Data/data.0~EvsZQiosdIWIy37EZ1SEE8Sq3UZp3mL9zEdHT7DpAEZObWDAWolDj4RqbY3qixDR1tBUHlGt9Doftu10FLeF7Q== new file mode 100644 index 0000000000000000000000000000000000000000..f898069d30da5b8e0557e5eca8a34a983a8db7b7 GIT binary patch literal 2201 zcmV;K2xj*vwJ-euNQFcI3V_TTL}02-0Q5Ut$U;|kj{ZP@7c%NRss2teg76Jp0FB5$ zv&m;ES}A54r)D0hj@JKqt_1{c-EA zJg4pk-fANLl7i(so02+x zk?!`PA&Xk*+dM_8?%TnqvMUnIcQkSz52I{vHm>jSrxgrx3Ad=IsD!|*Acde66)+2o zY72{thf$rrNOzx!!2r5Z56}f*Tu;!qX4j!kU!=QByn0Qs@>Z*2JB+6B+<~V^)qRg8 zBtShyaDvd&;Rgi8UNrfn^CPSZz@arG{5mK&c=X z7M9c%7#C2ALRQ#NcqQEGVbttRO5LqT^$A^wH&3-%u}q`oSFgE2%@(uDuE^pNMz?O) z4Vo=xj!bn6ePUD_b8EJDX4Br;e%<#CYu%M+{iZ0kZr2T}e)XE0npjdgV4%P*Nrz9Q zBRedMY}-Vi4!D7iV*REE<`N=8oORG3ykOxgYf36=0*?tn zj(`;IQg-gTubBX&IY3pjX$?fO6QfUZl%KSDs?~~aPsGvXJ+oJ@t!e3-dm~zR-LGEj zi5P$j0HDacm2{}6_+Hs#F$Vg9?uDW_VdAJil#|hYQ*6x^^ZMp9HZ;xi%Za=wr!RGN z*LYE1UtO=uQ@y5LtZZIiy-`-pyeQ2Uk*=!h7H!=vk{5;6x-1W^by;2%>$*i=l*?1S zcFe}E*4=7XXjK(@wT7<6jJEDp`~BKB8`E62eQMpUhPwRsOZtBt?*9k;Kdzg)vfzjl zm@MILHFUS`%GY*Hp;Z*EUDf>Z1QV6VRWpF ztWC4)P<4Z?yYdvMjXEtQh6%+OV3fm#VOWx6nRWuAqaEoP47 zKqNb{_1>9Hdm^+kw|i$c?UBfUVHlP?>ff%}_)t!Kw{FV&`g(I(+V#3Tr!LFpuQ#Wq zU7N4@<>;H!QeM=X)6y=qc76Fq({<dV}y?Vf1)R zr`k0eMId!vEL`E6H9v6#!S&{CzBMnZC8W;W|L2s--R=KP9k?ubG|XRa8MB^#{GzA#{wreh3Ky3dgfWE)AjAJIg8x-18>*&$o6Wa2hEYGZlQm_hvMzZi~9Y9 zNdMpU|2YRr<&l8@H}%|fWkL4@CV?wYb=$f@y>l`1tRBE9Qjfw*9YJU6UTSL^n$yvk z`PRnOOz$@ze?JhRCwCbj<#?mTs)|f9?N|ivIuj|3ydtpZ5O))c-fl|40Ad zT=4%E{y)Le|3mnHrT=I8ey@wU%8?c@dOW66SXz4LA_=5!0vG53 zeRj`f&92I>ZHHsmcQSS{b}e?u-Er6MjFQYGHo7o6Fgh=~F1jtcEV?GTB|4ohr^|!s z;3SrVA4K{zrOr zEvJ<8$r8`9%w`a4T?2y5Sqr4N*y`{8RcV`;>gjJ!PJy$v zOAIB2Qme!&tx8|nD;boB-q06%LODhx*<# zz3z>EY>Sq*CX8mmG7L*L^(R%{F-U@xN;WB zL2s80YBj%Rtv;6VZDv+N$`^t6{{j9#026@!e*=&IzbHVl)RhIJoWLX(Mvca)SEJ=N zbI@vj`H4}a9-%*VsO|uJC1J8eNs<$qJsNY1FuvP>o2W6RF+c$rW&lKj0m4KD08jz} zg=naF5&!@QP@yP?au9L|AcPDMBm@G02qplafIut&uo+VUt_twDoT{x<|8ZSa^~h`I zIcS;?{9F~w2e9eVv~h00&S;&%iLJ8kZ=aQY+k|d+XMa>qHvYzohQlW6D3n_UH23MW zw;2O(1f)I?OJ;=Xjt#`^fgaoIKf(lJa5_9^*9^x^NE-=}>&YvPQ3=NYb@o7+5*}TK zLBHnB$Sj{9@Y9CJvh&nDR?{0Ox_4eZ2q;OZhV}*&S^A3afBT@rdG9r(8gt4+`~h)+ zphKf0whA`-vz{MYM;N}<5VB}aP*l-%385HbzttcE75<58vt0z(Ol-AnBD6<J>rq0@S4fWpQG-`Jq%^YpC?{YsQAcg}78T9}uvWd^(0TB67TS b3LHg>Vj_c1He>Yw-k`3O8LHY+Pd&HpV4DfPTYv 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

05Sijnb>?H*H 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 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~TLjqpFdxiJIRfuFFhKndD4cSlivVpUA6h7AN6C7c4XK7U31D1A5WxNoAthAtSDkObS9kDAWivdIBhLTESkKW6A== b/TestResult.xcresult/Data/data.0~TLjqpFdxiJIRfuFFhKndD4cSlivVpUA6h7AN6C7c4XK7U31D1A5WxNoAthAtSDkObS9kDAWivdIBhLTESkKW6A== new file mode 100644 index 0000000000000000000000000000000000000000..095e8386f9c411137b20f280b3bd3c01b4457564 GIT binary patch literal 3735 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 B4C4R* literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~UKl-odyGjSKDjDpqDC06BJcVWKNDHXBJmlQNh0y8cvj4oqC3frGCpIBEDOsGmXthDz_qhddkovi-M-5-jyCUaA== b/TestResult.xcresult/Data/data.0~UKl-odyGjSKDjDpqDC06BJcVWKNDHXBJmlQNh0y8cvj4oqC3frGCpIBEDOsGmXthDz_qhddkovi-M-5-jyCUaA== new file mode 100644 index 0000000000000000000000000000000000000000..b8e64ccea9a3c0793a0ea1f3a37ba3242be4e271 GIT binary patch literal 1351 zcmV-N1-SYswJ-euNcAZI3SR&bEWoae4hqMaO{Lmo7IO>9evHldWm!W0b~XAxjA8uf z13nR?T2&N9(a4()1PcKT0r~*ntV=!HdPNZC5&=@IwR&Ks7p(MY8fyee|Dx-}yJjHH zHwOAHj+TGXwIc|#z_rdpr{U(?%OHmPjrU!z2=aG*NIS}L9zhbXMrw~zYX+Zs)RO#J zpJ63sS!?J89fjl!_nX_7Wfcj4fXU$iRB!%I6t0(n>jw0_WsU77wOulO-Vz}QrV!L5jMGzC}0hu7x zB(W^fG*u3fWkINDsv=fYK`fQUQBje<>r3wT9WvI|lHN6A0g*6XtUX4`G8bXI@A?y5 z(@0t7B#&Maw~Us&)g4IrEq$|Lw_e=xWA+i|)$QW;p6{A@*N3jRQ3G+)=OF)JnWWh# zMH~&vAyEzk@4~gQcZjWKpX9KZ8j!|A+Awt3giPx8o>mfuwnjUUBYg%Xi6}3!7v<-3 zk-aD-q6f@@iUfouVKH%u$Si;)*DhUeqsFyIn5axx5J*7R+o;Lcxb-Ey;&Z&x=W~&1 z_DQdC>wi>gJYXU+6$Ta&)kNijv6#46l}iMabzXuv-x##{U_V2b4L217imY&uMD$%8 zHTkZe%K7ZT-sHQ+3+;>##>@J?5?Mh>A`LgmaNj92ba|;~)lrg&X0#VkWUPk=vcf?^ zL5@X@UYVItgC<6(TTd${V`XMS4e$EylbH!M_`7~)Ce+aCX~kf`ix)y>Cd81goyO^| z4tACeH`(fGbq&mKm}w`+Tf4l}nh%FV?tPvBs_QuAiJ=jO5tq zK$i_S`8vTt&z2bPyT%Khpjw$@=evGpF)`kM#ZaGbH0-`yT=|%NT!4`zR^<`7SO!2Q z5R!w%KK7xqh1`x;N+a&zNcsUO_qqHzyj>iYldaW~b7D*{E zK^#;hqIozzQ&I>_NqLUYH8g5$Fu}oR(QlYOy|MvwiI9}`&BAy+t4=4pMKD}<#c&+Q zCeg|qC*JjwqTk;0S-WF(;ep|Pw(VT4ODXJY4oYAYRCs_JM$qaGGC+VF@Sqp0lDBoB z)v){0@Eh;d5LOG`H4~AkC?0rQ2U^*%`$B2hec}8<;P~=xES@@UF1=w;wBy^h$qY&y zdgFy_Il*`_-pKn5t86&Ndnw147h>{WWQL?P>{fq5_GVzC14d>nUB#0BlmC*M>K1ctC4T;w7z(|OoY?c4}vVdnm|~Q1{o!v J$TYb%LJgYIeP{px literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~VWThOtGgUglta4VfPcGAE-LoiausHVRiibNzAsPI16nrIuZaMCfg2RBRU3-kjsyRjm8kCvahTOGvuqeVcG67XA== b/TestResult.xcresult/Data/data.0~VWThOtGgUglta4VfPcGAE-LoiausHVRiibNzAsPI16nrIuZaMCfg2RBRU3-kjsyRjm8kCvahTOGvuqeVcG67XA== new file mode 100644 index 0000000000000000000000000000000000000000..2e1fa9269069bf717ad06269207e07421cbf1de5 GIT binary patch literal 272 zcmV+r0q_1OwJ-euNIeJuQVAFwa7!Zy{K>DXssq74u%);O%%rx^8&bCX|9{^Dzg8`( zc0N-WmvWc~Zg)ElpjrGZg|_EK+j9p5!Gc19LQn_IlfaRchEzfc{WMuIC_n)X48xZ% zKh`046O&)YWjv;SsGu%@01yCB6NX~|65y~XP);HQ8i9L3RiFJhi0xngM!ngG-K_RJ z7>mJoo2&Ph04u;Ee84QJ0InvL#1U~O%?txDz^*!_Z^As{$}zSi?27VRNDfZ&s%RT8jC+!0XH+H8nM|VI1`xwcE)z_sBsRi`gvWOV#2zBu|a6fkc WU{B8_ryH$tDOd=o3$^p|kLw4!n0++> literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~X0nojlcYwh2bDIqHykT3aw-21PvbyxMT_8983gRJgZXpeSWDzTxeZBLKWd8iDii3okf2wV9yjskMuNQXr9oQTA== b/TestResult.xcresult/Data/data.0~X0nojlcYwh2bDIqHykT3aw-21PvbyxMT_8983gRJgZXpeSWDzTxeZBLKWd8iDii3okf2wV9yjskMuNQXr9oQTA== new file mode 100644 index 0000000000000000000000000000000000000000..18ae8bc6d3869feab7c3bef3dc75f0a85762583f GIT binary patch literal 1484 zcmV;-1vC06wJ-euNF6Q!N@=_jEYPfq8;Z{b3FVq;`}|e9wi_@DCS5s9O^0guQsc8M ztV<|j#{M!&J!nhK3oHRD0T2PuweNSfIUFz%nF<9)1XWSFU@$5!mdYjK$*^zF^^U^5 zvsBAr-wJv#mj};U&X*IZts=Eh<9eZ|J)CkYUT)^O-cc;9dOkdyavgdw6VG7|n8(dK zm^~f&UGvMWphv#ke-_*8N$6?Kn&xsg-z>uAtfk5C{f<=2GUwPTK8q$h^1H_{%PI|k zfT-cXV_Hy&10pSG0RanP(y<>nI@A2k}vnQBTKnb zU+$~b+|AZL=*2^dCKF0TnjR1;$Wyabd>xG@6Gs%GL=z>N9szE8L=j3NE$HNsNJ{C* z(wC!K#b*%~8egw>nPMi?YL*P7&O1E1U#hPB%zjQ_TBLHhKuiy*VRD%uNu|;NQ4bOb z6nThH5ClS+C%s3W$nQmgr0mCa@~`@Uog;;4Kr*A9ERuh+AN_QbIG)Z<2fBfKcpsnz^)XU0}M ze7mRX%YDt}<8_++UaQi!iqFDffth$NL6a2faiiDk>7d5feGH|p&wu-TJ$G8I`)<}V z-Ro64g-9@WYBm2aX4*L3W0p-!M}CLJpOp+{(PRXV8jCrH*moRuinig-H7wDveYt^Y zO2JezRL>?Qod(=j-5Lf zM0gQC>^p1WR?2|6JWz^zXR(?&yl*R{i|EKwF6MeYorG`qta!PvlzsP7zt??I6&yP9 zXY5a|rCJFL-HQ?!1rr?NrV;o`1{xrM4sh5iQrhgWXz}QN@%XN}@))U!mz#;mP!f8w|Lw-Bal_DC-ll+h`Ug4bC&;Ih|O|R`YEBj+8p2)m-f* zxfx;t;p_#acy!+d<@mY*v-OBle0js)Td`ix8frDalKT>(U%)ws39#f0wO@jKqLbo05j7%P{KjXtOgQ55Qwoc z3WHIMLPS6q5jvtsNhBm>iFFFdqtj>{;++Y=UFrmO#+fi5mk4}M5;ry+!07K7d}how#qk>w!EL#ZdZ zg|h_SM+0q#7`falHz1Ekz*L0^^@=tYMDOgQ>ozum4dQ{x?NlfOph2ll=w2lB?N^|Z z{%4sx$tM6u^Su?O01YUwR>T)HW0x;)4OBrEg?eNqH}a&umy~o_@E~B@WrwtJCQuy? m7dJ{eM){)z!JE2BuoNzboM-W|C~JZlMH(b1`E=*xp3o{}kG;1LNK(x82ET6;(W}gcQiXfc+DBBTK%a_ugON}v; zoDc#s05bqI01vk(`PfLOZRuBv;6L1U*b}t?v2rY2|JmM^>bjNI+UrvKZAi$Gln(R8Vuvcm}#uBzxVT`(!CXnX%GmgEy}@wXk2KT13#zW Um~oiL4pQ0+0svdcA`LPn1*?vE9smFU literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~Zbr7jYftSGf2opsqmDbQYi9s096-CTteWzDx8WUcUfYYa7dn4AgU0K4ibnnhcHbzc4ELP6ar0skoF-dxCVhXtw== b/TestResult.xcresult/Data/data.0~Zbr7jYftSGf2opsqmDbQYi9s096-CTteWzDx8WUcUfYYa7dn4AgU0K4ibnnhcHbzc4ELP6ar0skoF-dxCVhXtw== new file mode 100644 index 0000000000000000000000000000000000000000..3804901b361d837e48aeba7d489fb53416805520 GIT binary patch literal 269 zcmV+o0rLJRwJ-euNF@jWc91n8Kxy>@L%F%U~qu62OHwrv{MP-y?^<8H?-C$W9x)6kw-aQg4Q=Fe7{DM1hXaL1 z9X_k*S}*CF;{Q7Aw4DmJ{<@oDkdLa5QF0@;BCr3mea_P=r`{%s_$B$6(`cjiZ6Sz? zqL(ezmRn5QxO*jh=+50Li!v8JjUEEX;79-v0>n%l6g6}P7!p0m&^b`BC_@MZ00FbY O8RI@@B@57khEPxTv_}#E literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~g5SKenOy8VL12VhBb0f_RJ3OY_jmWfwGzRxk-AZkLfl8j-WU15rLPgOe7OO2uocyEIdZ53LcJucQj1UVJnqhXA== b/TestResult.xcresult/Data/data.0~g5SKenOy8VL12VhBb0f_RJ3OY_jmWfwGzRxk-AZkLfl8j-WU15rLPgOe7OO2uocyEIdZ53LcJucQj1UVJnqhXA== new file mode 100644 index 0000000000000000000000000000000000000000..40aa955fffcee4f719e42a48dc4e0a27203442a8 GIT binary patch literal 268 zcmV+n0rUPSwJ-euNF4|Oc9T6LK&R*dz!jCt9cKvV-gRd859jK3CH24E$hII SYYo91UIPFSehZnUL8j1;c6dJk literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~gEbQ04FjnsnQaWq6nbEgbHPxVhg8_TEtlDk5i-GwQKGCfI-F5ga75TQjJzXUxyw3fTd_NASbes-yWi5na-l0IA== b/TestResult.xcresult/Data/data.0~gEbQ04FjnsnQaWq6nbEgbHPxVhg8_TEtlDk5i-GwQKGCfI-F5ga75TQjJzXUxyw3fTd_NASbes-yWi5na-l0IA== new file mode 100644 index 0000000000000000000000000000000000000000..c6a0a1d98aa5bae08fa88790c32f5ca39a46155a GIT binary patch literal 1274 zcmVPQF57J`MWzX&r$&AySNRx6pXvD9fhI*pQI(%AES(@PQ8`&C)qd+)R=2A&?I2{G%Mm7fv z7o4J}8x;yAJ_CW9NDyP`E{_eT@Zl$I$E*|lF>Qt8Ddo>--nly{(aI|RS| z5ma8#{kz?FNF}py*9t+itx{21wu+JzO;aT+h{kAEF-Cz{<@7EKzeSz$hyUtutCeNv zYo5svyvwcw0>e);re$l)ALd;0+rLI>*&4YUa`_tk_ODY~cJtpK20-_HfB5aMb!sKI zjIH1PwR-3D{gna&DM2+r1O*#3DOmUxUOo;iEp5V2RaL%Sjd=&+??T9Lf5ZgINYbg2 zq(o7Q%1W9LB{{!1&WktnUNfDhSDN=b& zn0D^w3-Rr0tWwi7=Y*t4$*8JgRmqFNT5I=qO$)C|?eOnkc3un)dR{vi?n*67?t_Io7?_S_&D0gj+0{&T*xx?NDEvE+M%?)tC_>hc1ObAxE61d>H(FNBQ zWNr}z^q@6(m^*?nu-tlB$R23$L5NM@-;%(i2k>sS`mms=FI)<;0AAUM#;o4x{$)k~ zM{8h%P%XOTrEy4C&^0ZaQfFbd9w5_mqA*cYO0rsR~Rn;}f0{AL{= zm}P~P@epahi-bGL*DV|@dV>oGtGL4rS1Ee39`~>l$a29m4u|ilgaaESIM0OziVF6l zI(Fv;cvr5PzH$k=X{9LI?qVO_^{)x&p=O%4DNv)1Xg6208c&@{0J#$>)UMW0ZqA;_ k?xngylJk-#i9hZxDNW>bGnmS_tfcVcxkDeVnmed}I%0`b;Q#;t literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~hI-qLI9hDhPMkZHvs5rWt4irFW3b2JwrFCCdkGi5xgqJmUUtzFLQpGnRrPfNTA6b8jurui2E_bG4emeF9tKL8w== b/TestResult.xcresult/Data/data.0~hI-qLI9hDhPMkZHvs5rWt4irFW3b2JwrFCCdkGi5xgqJmUUtzFLQpGnRrPfNTA6b8jurui2E_bG4emeF9tKL8w== new file mode 100644 index 0000000000000000000000000000000000000000..85d07776dff4e93c75520f705c76d2e3b0cfb91c GIT binary patch literal 110 zcmV-!0FnPFwJ-euNG$^Z;>8skU~3!2F7}s=T1KdbyZzcNtn83k&S(P|1mSRq2i+Y< z*kUZ88t{gBGf*t4PIu6Ai^V_$i-NEQ%uP*AY@#Nvreb^JW3Qz(E}U}QNPQ?#j+w{L QIRpa$ZXg~_vOzAC8IW%;mjD0& literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~hTaVfLbwsJoo2uTcCi-7QiMyGgC7Hv6sOrkDxFhn2uxkrnhEz2yZDekBrGgEKmBAxudGkWKMtRsW-WrmQyoAmQ== b/TestResult.xcresult/Data/data.0~hTaVfLbwsJoo2uTcCi-7QiMyGgC7Hv6sOrkDxFhn2uxkrnhEz2yZDekBrGgEKmBAxudGkWKMtRsW-WrmQyoAmQ== new file mode 100644 index 0000000000000000000000000000000000000000..d1d25d47dec6f2fcad9f83c99d16c459097a479c GIT binary patch literal 144 zcmV;B0B`>&wJ-euNIe7qvPd2vKvA6loQo&7A~`n_fox186DBIX6^JadgM6tpdFBNU ziYpnnLE{uPG(cEl2XsK1VuZ#i>IWd85i#PlS`fVE?)D07^xs7xbWgtlsOy?-*gmD2 y;!dpOYE1H@>P(WrzV7XtTi)_tS-bN83+Qo>%1I_!dSY6M0{{=u96=!LOq4xS;Xlp* literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~j2WFeQOZmqAiW_n_xM8-R-5l-mO-UzrPNCMbihZzdFMA3BiifCQyyYnQ0MuVBj2C06nvOeflFLlKkkaWf7F1XQ== b/TestResult.xcresult/Data/data.0~j2WFeQOZmqAiW_n_xM8-R-5l-mO-UzrPNCMbihZzdFMA3BiifCQyyYnQ0MuVBj2C06nvOeflFLlKkkaWf7F1XQ== new file mode 100644 index 0000000000000000000000000000000000000000..b3fe6d87f316468101b5596492372c26e41c0ac6 GIT binary patch literal 713 zcmV;)0yh09wJ-euNCg%EHmiLm0Fk%>?3LM)Krf}bftW-#N3|A|Y1!_9>bL)0YM_h` zEdB4QU;=mmX#j8lde9)T0idB10|rseiJH@3*a5_W1c6SR;ll{qTI)0cfx(?!JHK)U?0NZX15{P{c?NoR^W@{@+yeT} zmj$=V3Fm7jTHF)=J{b2xLiNSaIQylX@EuDzT}!n$wTT&G5(Y^TI}o*!_SjV_@B9v< zjt7kSB#cl;^F^~;uEtLt?OI?5FPa}95Y*xC{5o;2R;oL@*;b5GFTU-hffz3-ppy-6 zuDINOeaY3u?f>fI%tn6d-_x=#ZzQxl!hOf8t|y`8d;u@6Hvo-9;yn7`I+5e_>}G+6 z+TRyxoa9jKc~QiuheSb=2LwUTNfp|Uy>urOH`1X&h?N(qd>2nw2@CM_)-ywm2>>*6HQ zeN@ji$Le4@8lp~7eM~OP;lI&_uw%lAoY3;8skU`-nZ>gbo(%PLrdW(R7cHGEiPrfLf~41;lt=PtR@ ztb4Fn@P>I~SgjVTBL_Wz<(8TJ&^6dYDFhG^LIN|TrZQ5ZCMHeA_O?f6j@I^Y%PmCl QIf?@SXvi+OTwtP{0UuQ_v;Y7A literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~o2VCv2R01qJIr8cxdFCFsQcc7O0occlhJUCzmEuoTv4y6iPLTL-mL18kp6xAp5Y--h0aSxq6lB5G43BfoQYZEA== b/TestResult.xcresult/Data/data.0~o2VCv2R01qJIr8cxdFCFsQcc7O0occlhJUCzmEuoTv4y6iPLTL-mL18kp6xAp5Y--h0aSxq6lB5G43BfoQYZEA== new file mode 100644 index 0000000000000000000000000000000000000000..65ab0ca3c586cc15fbd4a196d35c25962f8742e4 GIT binary patch literal 295 zcmV+?0oeX1wJ-euNc9K+R#H49AgkyBhh4Nqm~jv^=3Bz>6}7%JJXPec(L1|0)&u}T z0zd*pF#s|EF906tJGM=p4SFFm8uF|aDiJD=&rRV*k9+(~@i&3X_zb1xjp{N!Olo{mB+9B703zAoUpN)YMd|HRND2RS*bxR z$v*B?0rhMDM%TypUWd8&uql#GfOQ~1Z+;(Jq# z?;)lGV+yHFi0QyE7z+i{1f&C#fCePSSvZJjVvB9ig(3Q78*}fq=XX#|c~X}#_vZBo t4**d+&^FwGW^BY}<;=UlbV=iV2pW07Hevkm7{Y$`$&HI5GiVP+furE`h^qhq literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~oRMi0sbQLktfDDDGUS-SqBKpdDiD6HCztVES_ShfGr0KVcYENoIq7y9oUSDWL5B_P2gkdtWG8JEsJLxPbdWOZA== b/TestResult.xcresult/Data/data.0~oRMi0sbQLktfDDDGUS-SqBKpdDiD6HCztVES_ShfGr0KVcYENoIq7y9oUSDWL5B_P2gkdtWG8JEsJLxPbdWOZA== new file mode 100644 index 0000000000000000000000000000000000000000..fdd67e34dc951ab44630a0505b3111970fe21488 GIT binary patch literal 199 zcmV;&0670BwJ-euNc9B(VvQ^!FpKB`I~+T%l}4r)U#UzrZ~8ClfTu(Vp0@eNBt=Gm z1eeNv^*EQ6d&i$;wY)gmkp9T|pxo4v0U*+Opt5gK5@-Z@1%|0=o%Yiv}~` zXx3Mcb1|9(xG;DKR!+eH5(4O82}tCRbfR8NX$wn4(kpF-6`=+N2Lb@#A|OQ~8z~O{ BT#Nt! literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~pQIYVMtfbTC-aBUkEgjtq0skFlTpHlzy4tbQqhJlqYP3-M_WLk4w68WdDOyxvsaPpnsnm9WH3baoQMw68qVsDw== b/TestResult.xcresult/Data/data.0~pQIYVMtfbTC-aBUkEgjtq0skFlTpHlzy4tbQqhJlqYP3-M_WLk4w68WdDOyxvsaPpnsnm9WH3baoQMw68qVsDw== new file mode 100644 index 0000000000000000000000000000000000000000..c6aabbfb2924929e622c2b1f3772217e437891c6 GIT binary patch literal 261 zcmV+g0s8(ZwJ-euNaY6r=8!icFp25`U~G2E#WO}*Y&p=Y0}yexm;8C8E2>)%Tn&*C z5rQrNF90k6Em3K}u7GeTxIH*cw;tlAt4B0FHmJnQ9-P!)HZ;-0$%>(*heHO&^-x}_=0jy1Ko=rgH*v@VIA2Pb-vD8B@hhu|qt0?*8Y zySo4e#*}5@ZM-dFHfftMZ5uo7OAuGao zPe7_lCOv(colMie_9Mu+KwkC%wJKzqK4Vh@Y+#yt4+#KB1C=nyD`q=OUN5NdK LMT`V93JawN`}1(h literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~tc7j2NnpxbOcWB8CAow6AhIJrYJDr3aWBxvAJ-LdnPEGHvEUK6F-uAEmMNsIvG_7-_yO8-JbHHdrItXpqUJcFA== b/TestResult.xcresult/Data/data.0~tc7j2NnpxbOcWB8CAow6AhIJrYJDr3aWBxvAJ-LdnPEGHvEUK6F-uAEmMNsIvG_7-_yO8-JbHHdrItXpqUJcFA== new file mode 100644 index 0000000000000000000000000000000000000000..8c16df93ddafdac7fa2603a57461a10e11edccb8 GIT binary patch literal 71 zcmdPcs{fb4<0~VB3v+a}Qb}b&s*;tVj#6G?E|8(*oL`n&l$f5XRIB5emy%lHn_7~X Zl30?cSCErgT%uGP%fw)7ulr$&FaT2l7wZ53 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~ubIndH3cSUiHhHhRwER9-zGlJoCiuY6_E3jeJ0mq3DW6zmPbPA9HfKqMspJyJ-cGSwtX9nnA2Ov742R_MmKJTA== b/TestResult.xcresult/Data/data.0~ubIndH3cSUiHhHhRwER9-zGlJoCiuY6_E3jeJ0mq3DW6zmPbPA9HfKqMspJyJ-cGSwtX9nnA2Ov742R_MmKJTA== new file mode 100644 index 0000000000000000000000000000000000000000..a29f662d589af099b9d0782a0ae36b89ecd9873c GIT binary patch literal 271 zcmV+q0r37PwJ-euNHqumwh%TUFlo#K#M_)<`VRl5TVV0FE%ESDWO~XUx7dYVOF=;a zmMs7-04xA7#`u!!JA`;I`v4l~3F2umpLPV09RBQs3zaGAYTnzS)qIKA#VP2s4=$WV z&LW3IXZ@!3+~#0(3d6LQC=8Mum?b${Yerl56ba8h7<+=QDzOT!=5xKGJp?^j78_J0 z8Qb^%RSt@TXCG`90R#nygVCqS--(X6I`93=-`lAzF=c^{xCSx0x0F}2i(k**y!UT& zO)*`B`FlUJENN&uCE5mw&i8%<$q?(Pk_tu;09BDpnGP^qI*`)+AaIGN^MqKyK_Ox* Vz?_aSt-4?s5KL8^1-@xyiVPYge0u-@ literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~uxX7NisootIqCZMb2CKohM3zmuFj3tN7QZUGoDk-QszJmqDZQG4Qn4AIivyW5FWaBrh9sTHIY549_5lbVgxynA== b/TestResult.xcresult/Data/data.0~uxX7NisootIqCZMb2CKohM3zmuFj3tN7QZUGoDk-QszJmqDZQG4Qn4AIivyW5FWaBrh9sTHIY549_5lbVgxynA== new file mode 100644 index 0000000000000000000000000000000000000000..85e793eba1ea1db0335b829e04bbd125ab875dfa GIT binary patch literal 16846 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 a)hP-zRPH8rx<|% literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~waHVBaCwgME4CJdFPepwWH9vPPmWithPCd1nrnFe550frgf0FiAZWSQFlgyuu9dnXl47hfHxR2NZKEzigTkbnQ== b/TestResult.xcresult/Data/data.0~waHVBaCwgME4CJdFPepwWH9vPPmWithPCd1nrnFe550frgf0FiAZWSQFlgyuu9dnXl47hfHxR2NZKEzigTkbnQ== new file mode 100644 index 0000000000000000000000000000000000000000..c13ea58d7e2520de6d3d6d01a777af2800518294 GIT binary patch literal 284 zcmV+%0ptECwJ-euNSz1(VvZ{!P-~k214tHV5OOWftBoV*P+YLq2;ev)Gqo6rDl-Qj z69P)<0D)_{FF4D$(D`GaXZhCM)7C)_mTz4jjHKMCu1%~+BpaZXd1tuU+ViF-A*n;7TQ(+dQ z$Axo+z5pqma4i=Q+~Ds(35xtp7RcEy7s9|vU{C@8B_RBZE-HwH0HqXkm;p`_=%KC0 iW~jTsRKB4T2$S1~GZ4K3n!yMJ__Ox@0EO~K&+r-FGk&rF literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~xO4PZsidi9CfdBw7Gw3MQdwc-9TSnJ5Q1gr9kCdmXT_J9yLqRL2lCPhqmlFH6nTv0eWCej7DNeTqzqCgteBBIg== b/TestResult.xcresult/Data/data.0~xO4PZsidi9CfdBw7Gw3MQdwc-9TSnJ5Q1gr9kCdmXT_J9yLqRL2lCPhqmlFH6nTv0eWCej7DNeTqzqCgteBBIg== new file mode 100644 index 0000000000000000000000000000000000000000..775877c3b8ddc90406cabf3ca3e525d47790a8b4 GIT binary patch literal 268 zcmV+n0rUPSwJ-euNF4|OhEO#jP)YRzLpeN1Ly2g?p5C`T1B6FnMLA?ewOk=lW@ctg z4J`mH04o47#+O{*AB20^2~VOI4^M>ow4nij=gvCVP+5|y<-Hj?&6kKxT0@<6P{Aky z?L~CfUuw@~4aNgO*gKHs+DihS@)%wGDQXit#u{< literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/data.0~yHBe7-6QVIF_XdGegDRw_3irLFO31xUODLBHU8TaDGYTN20fvV0MeYbSaqVk0jByjazeYks80chErkx9EvuJqg== b/TestResult.xcresult/Data/data.0~yHBe7-6QVIF_XdGegDRw_3irLFO31xUODLBHU8TaDGYTN20fvV0MeYbSaqVk0jByjazeYks80chErkx9EvuJqg== new file mode 100644 index 0000000..ff61f08 --- /dev/null +++ b/TestResult.xcresult/Data/data.0~yHBe7-6QVIF_XdGegDRw_3irLFO31xUODLBHU8TaDGYTN20fvV0MeYbSaqVk0jByjazeYks80chErkx9EvuJqg== @@ -0,0 +1 @@ +[{"type":1,"name":"testmanagerd.log"}] \ No newline at end of file diff --git a/TestResult.xcresult/Data/data.0~zK2O6I4jLo1PGm9yMOwpMNRaRixLheCMvIGT5IS_qZg8u2nMxqL2D5subdwYpOkEEwzjcfyxBzXh1c-PFi7R3w== b/TestResult.xcresult/Data/data.0~zK2O6I4jLo1PGm9yMOwpMNRaRixLheCMvIGT5IS_qZg8u2nMxqL2D5subdwYpOkEEwzjcfyxBzXh1c-PFi7R3w== new file mode 100644 index 0000000000000000000000000000000000000000..586ef9fe344e90a03aec2281df0e0ed676cd76b9 GIT binary patch literal 109 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 Xm{x#g9brXv!7w10syGXL)5sJV%TISX literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~8M9pZfzuOlvEs9ZjbSlAe0rVWJ8kmnWQDltpe79EMhRvEFZ6X39bWUJhoHaba_eau-EKsOEKfXox3_nhh1Xnbg== b/TestResult.xcresult/Data/refs.0~8M9pZfzuOlvEs9ZjbSlAe0rVWJ8kmnWQDltpe79EMhRvEFZ6X39bWUJhoHaba_eau-EKsOEKfXox3_nhh1Xnbg== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~AZgzWgvJfl_hp1UgOGt0YYZHrm06paXNvPahCxwxAZfj7wMYg7qsPastp25n71ro-KS4y9vhm5pIl4iacemMgg== b/TestResult.xcresult/Data/refs.0~AZgzWgvJfl_hp1UgOGt0YYZHrm06paXNvPahCxwxAZfj7wMYg7qsPastp25n71ro-KS4y9vhm5pIl4iacemMgg== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~EvsZQiosdIWIy37EZ1SEE8Sq3UZp3mL9zEdHT7DpAEZObWDAWolDj4RqbY3qixDR1tBUHlGt9Doftu10FLeF7Q== b/TestResult.xcresult/Data/refs.0~EvsZQiosdIWIy37EZ1SEE8Sq3UZp3mL9zEdHT7DpAEZObWDAWolDj4RqbY3qixDR1tBUHlGt9Doftu10FLeF7Q== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~O4DEOstFHYmuXxykISnoXc7h3n8ryTXy1_m0-EeHMoSx05ueWFhsLFOfvtxGUfP9DWhtwvIunXzwQ2e5x56qEA== b/TestResult.xcresult/Data/refs.0~O4DEOstFHYmuXxykISnoXc7h3n8ryTXy1_m0-EeHMoSx05ueWFhsLFOfvtxGUfP9DWhtwvIunXzwQ2e5x56qEA== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~P8mPpsCgAccGkYH-NlIVANrPETOVC5LNO-0a5uVoD4_A4_imFA5DNH4nM3UQS_LeI8lCBwbwTdpdTBURCvvWWQ== b/TestResult.xcresult/Data/refs.0~P8mPpsCgAccGkYH-NlIVANrPETOVC5LNO-0a5uVoD4_A4_imFA5DNH4nM3UQS_LeI8lCBwbwTdpdTBURCvvWWQ== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~Pusf3h7cIllaVbwQ8M-8N471uf_ERdgI5GLgY5d0b6yeIipaOC6P6QCZPb_rJhQT5PB5BA9nuirtvS0CO692mQ== b/TestResult.xcresult/Data/refs.0~Pusf3h7cIllaVbwQ8M-8N471uf_ERdgI5GLgY5d0b6yeIipaOC6P6QCZPb_rJhQT5PB5BA9nuirtvS0CO692mQ== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~TLjqpFdxiJIRfuFFhKndD4cSlivVpUA6h7AN6C7c4XK7U31D1A5WxNoAthAtSDkObS9kDAWivdIBhLTESkKW6A== b/TestResult.xcresult/Data/refs.0~TLjqpFdxiJIRfuFFhKndD4cSlivVpUA6h7AN6C7c4XK7U31D1A5WxNoAthAtSDkObS9kDAWivdIBhLTESkKW6A== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~UKl-odyGjSKDjDpqDC06BJcVWKNDHXBJmlQNh0y8cvj4oqC3frGCpIBEDOsGmXthDz_qhddkovi-M-5-jyCUaA== b/TestResult.xcresult/Data/refs.0~UKl-odyGjSKDjDpqDC06BJcVWKNDHXBJmlQNh0y8cvj4oqC3frGCpIBEDOsGmXthDz_qhddkovi-M-5-jyCUaA== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~VWThOtGgUglta4VfPcGAE-LoiausHVRiibNzAsPI16nrIuZaMCfg2RBRU3-kjsyRjm8kCvahTOGvuqeVcG67XA== b/TestResult.xcresult/Data/refs.0~VWThOtGgUglta4VfPcGAE-LoiausHVRiibNzAsPI16nrIuZaMCfg2RBRU3-kjsyRjm8kCvahTOGvuqeVcG67XA== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~X0nojlcYwh2bDIqHykT3aw-21PvbyxMT_8983gRJgZXpeSWDzTxeZBLKWd8iDii3okf2wV9yjskMuNQXr9oQTA== b/TestResult.xcresult/Data/refs.0~X0nojlcYwh2bDIqHykT3aw-21PvbyxMT_8983gRJgZXpeSWDzTxeZBLKWd8iDii3okf2wV9yjskMuNQXr9oQTA== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~Z-et4iZHtDgEfNxF25MVPFS2SHuhsXvNCOgqU11xJyaeCvotLNPKS4_ZiZk8DoYBkF7bspDO8unXM7a74NdYsg== b/TestResult.xcresult/Data/refs.0~Z-et4iZHtDgEfNxF25MVPFS2SHuhsXvNCOgqU11xJyaeCvotLNPKS4_ZiZk8DoYBkF7bspDO8unXM7a74NdYsg== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~Zbr7jYftSGf2opsqmDbQYi9s096-CTteWzDx8WUcUfYYa7dn4AgU0K4ibnnhcHbzc4ELP6ar0skoF-dxCVhXtw== b/TestResult.xcresult/Data/refs.0~Zbr7jYftSGf2opsqmDbQYi9s096-CTteWzDx8WUcUfYYa7dn4AgU0K4ibnnhcHbzc4ELP6ar0skoF-dxCVhXtw== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~f-TW9ZbQRmAXpxzgDSzOLkBL_jJjK8VgwlMH3eFn41E8Y5DrbjTZs8hapcvkyEy52mm5ViKS5s1s9Yea8JwScA== b/TestResult.xcresult/Data/refs.0~f-TW9ZbQRmAXpxzgDSzOLkBL_jJjK8VgwlMH3eFn41E8Y5DrbjTZs8hapcvkyEy52mm5ViKS5s1s9Yea8JwScA== new file mode 100644 index 0000000000000000000000000000000000000000..584ac876fabcf56c3758ecef351a69461d58be5d GIT binary patch literal 265 zcmV+k0rvg`K>$C=kEXz&0mlZBf&Mm96#&}L5i^wwlFd8q8s_C_50Aj(_@)#NLo|LT zGj$M4^4=rKLI(!$P1;>d6%h*i)>%OSgpaB$k6{iI%#o4rvzpeoh^rNC+t{2d6d;|D zXt~A;iJ3($%u>*#Y0<3r%}frP@;j@#Erk8CxO!)W_R@>&=cPa>=IJ9Y-p2~Atx ztPY3Os*Hos9@;+YI&W)96J{UC`v^rnGEYzL^byBd5A+qP%--8)8EqvzUZMJ>%s@c^ z%&m^-jw3FOPa1D>FzhKX)LKR?ONHQ!yn&PCgukhnJiBSk#-jEQn=WnK7^LY06Aa^V P{ILf$;nmNN7B11><&A)Q literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~g5SKenOy8VL12VhBb0f_RJ3OY_jmWfwGzRxk-AZkLfl8j-WU15rLPgOe7OO2uocyEIdZ53LcJucQj1UVJnqhXA== b/TestResult.xcresult/Data/refs.0~g5SKenOy8VL12VhBb0f_RJ3OY_jmWfwGzRxk-AZkLfl8j-WU15rLPgOe7OO2uocyEIdZ53LcJucQj1UVJnqhXA== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~gEbQ04FjnsnQaWq6nbEgbHPxVhg8_TEtlDk5i-GwQKGCfI-F5ga75TQjJzXUxyw3fTd_NASbes-yWi5na-l0IA== b/TestResult.xcresult/Data/refs.0~gEbQ04FjnsnQaWq6nbEgbHPxVhg8_TEtlDk5i-GwQKGCfI-F5ga75TQjJzXUxyw3fTd_NASbes-yWi5na-l0IA== new file mode 100644 index 0000000000000000000000000000000000000000..7b8d768592acbbdd7a6661665a1fc33117b76e18 GIT binary patch literal 331 zcmV-R0kr-FK>z`mGg=GDeqZ6IRUkNPbYX@^u5CJ{rOmwdp$i-_0hi?Mh?;TfjDkS`WxD%~hwVsb_M)3Am^RR2FKpA^z6m>CTQKqQ zWgJoV7;Cp@;0P4Zt|D%E;c#~IbAby#rmND)C>Q5(30PORK>)e3Cv<(>Nl1r;cu~Ma zefu$`CV-;3j=vLl-X}?_+%>w+W7|9rM|`S`vXXKq=LSm)SN3_p*z5b_WPdVZiA+HN z#O@Df$eoMOpL85M8x71s+#LJV(wv@9)(ZWQCuUtg$@e1aM7^a5_-dL_N9uI%(dB}A zKEpNS>dv5`wctS_K>*I{`K+T!*45}-RX21|H$AMAKo6^B3W8hyb$ouyf=>Zx&OpP*a+le;A59`Z>*joDq1)$kLduJ zJ-_QF6cgm|c?1t)~bUhnRZRDpk8(Vl=baQ}F#EK|4F6%GurM^nVw3}zEIZ6Cc|40(pq zYNce-FmjEo-eOBU(a1!uOnnmjiK;;Wf8^Hnme59E7pENH4J^(sKui8IV=KjA!czy` n;b-GfJY$gSZZz4m$Xcb#%M#=#Ezy!X29oiigTX_iGQf)cf1Z6BGZ>eBJ~}ftBfbC4GZKD7T_V_Q79rj>!zT)EBSX5KKV;XXmZrCP%b51bo~@+mjVMRJKTap|N|-2$@`;X2WvQVDHqgO!LSdkGn``%)yWtA3;R=0vG2i*&hgIipK>(o>BGSgtE=ykwFvd|Y zlBg1?bU1_PaI>{h68$J&8odft#soHkD(^37Q6SbYkbggDBzDz?@R2MeyiaY_j$|aX BU6B9) literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~ubIndH3cSUiHhHhRwER9-zGlJoCiuY6_E3jeJ0mq3DW6zmPbPA9HfKqMspJyJ-cGSwtX9nnA2Ov742R_MmKJTA== b/TestResult.xcresult/Data/refs.0~ubIndH3cSUiHhHhRwER9-zGlJoCiuY6_E3jeJ0mq3DW6zmPbPA9HfKqMspJyJ-cGSwtX9nnA2Ov742R_MmKJTA== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~uxX7NisootIqCZMb2CKohM3zmuFj3tN7QZUGoDk-QszJmqDZQG4Qn4AIivyW5FWaBrh9sTHIY549_5lbVgxynA== b/TestResult.xcresult/Data/refs.0~uxX7NisootIqCZMb2CKohM3zmuFj3tN7QZUGoDk-QszJmqDZQG4Qn4AIivyW5FWaBrh9sTHIY549_5lbVgxynA== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~waHVBaCwgME4CJdFPepwWH9vPPmWithPCd1nrnFe550frgf0FiAZWSQFlgyuu9dnXl47hfHxR2NZKEzigTkbnQ== b/TestResult.xcresult/Data/refs.0~waHVBaCwgME4CJdFPepwWH9vPPmWithPCd1nrnFe550frgf0FiAZWSQFlgyuu9dnXl47hfHxR2NZKEzigTkbnQ== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~xO4PZsidi9CfdBw7Gw3MQdwc-9TSnJ5Q1gr9kCdmXT_J9yLqRL2lCPhqmlFH6nTv0eWCej7DNeTqzqCgteBBIg== b/TestResult.xcresult/Data/refs.0~xO4PZsidi9CfdBw7Gw3MQdwc-9TSnJ5Q1gr9kCdmXT_J9yLqRL2lCPhqmlFH6nTv0eWCej7DNeTqzqCgteBBIg== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~yHBe7-6QVIF_XdGegDRw_3irLFO31xUODLBHU8TaDGYTN20fvV0MeYbSaqVk0jByjazeYks80chErkx9EvuJqg== b/TestResult.xcresult/Data/refs.0~yHBe7-6QVIF_XdGegDRw_3irLFO31xUODLBHU8TaDGYTN20fvV0MeYbSaqVk0jByjazeYks80chErkx9EvuJqg== new file mode 100644 index 0000000000000000000000000000000000000000..4a8d31630d137d1e1f0bb28d9ef9eef1a20eae26 GIT binary patch literal 67 zcmV-J0KESJK>&|sg?R&+nxGXn?6uC;0MwWlEbzK$mAS3_) literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~zK2O6I4jLo1PGm9yMOwpMNRaRixLheCMvIGT5IS_qZg8u2nMxqL2D5subdwYpOkEEwzjcfyxBzXh1c-PFi7R3w== b/TestResult.xcresult/Data/refs.0~zK2O6I4jLo1PGm9yMOwpMNRaRixLheCMvIGT5IS_qZg8u2nMxqL2D5subdwYpOkEEwzjcfyxBzXh1c-PFi7R3w== new file mode 100644 index 0000000000000000000000000000000000000000..a59744f67e64d56d803d11c750f1744d8f972f7c GIT binary patch literal 133 zcmV;00DAudK>$#xexclkjUt1LI%*6pIs}&$SffK7a7mg}4Tns;a`^b7ptpXpf~0^% z4C@A&dtnbh>V?;2qWHcu?tYITlxRT!gOrMTbF%SL_1RcKZ%6+`oz7$U=2`p(%^YO- n24pSye2?Xn*P6>d1D@>Twz`Kh5Qkaka@;285RX+ACVHV!l_8A2*7bcKk^e#B=~gcHQ7-9~BNV*SiVM^CWn07g!2V8B|5Lyv@N zZH?-S5Yg7qR31^S^g185?Q|5kh3!EAJAlMG%S9cDu3sFaAt~rx&f(sFE6FwT*ZH*g zM~5$p+>ZDh3h>{V0;YEb0 z-4BNnmMhhzKstx84d^c1;c~lEeM8g^R>ax>wh%2yISy?vWDEtOz0v`Mw8Tn6mgqqM zfJV^Mfn%P@&}nMAov|QnbMaOfJpC~(lsP$z;jloVf_#sK<_5dvG$SW9)W&p|m3+4Fu$m~^K0GUAmqh&(BWOUY|NUz5+bWnw{2OR9}C~?VQ zB|x*7OQ=r%GU_ACOuwctUnHljK&O^I`W+fe8oHDoM&oc_p#~WcK>(!!7*xw&Z7{xQ z6(kY}?W;>97F6jTT=L@9(5ez;se||U&(L$7w02OGdA;@zC_1|IPgE1`b40VXip2)u9m z`}~gc;#(YdYa-R@sX|;7K>)iI`!*{mqS7h}lN;C~sD#b)n&D&K(|bXc2B0}ULd?mU hpxHof5TAeuiu{)3RhkC4eX%jfW1c<#nOjy2a-3-k93=n% literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Data/refs.0~zuv5rKNJ1tXoXFU3dFE3k7A5EFZmsGMxKiI2643kHFwZePpnBIDCpaTLgIP0IgkWg5dBaAU4xe8GCqPIN___aw== b/TestResult.xcresult/Data/refs.0~zuv5rKNJ1tXoXFU3dFE3k7A5EFZmsGMxKiI2643kHFwZePpnBIDCpaTLgIP0IgkWg5dBaAU4xe8GCqPIN___aw== new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/TestResult.xcresult/Info.plist b/TestResult.xcresult/Info.plist new file mode 100644 index 0000000..b3a6dbd --- /dev/null +++ b/TestResult.xcresult/Info.plist @@ -0,0 +1,29 @@ + + + + + dateCreated + 2025-02-05T20:20:47Z + externalLocations + + rootId + + hash + 0~zTgpwVDRktI_jW4przYkFft6Vrwh9Y10xRxQvuk5jMXop8kXO9l1E_1afR4RrU_UY81-NNe12NuxNnr-LeN2_g== + + storage + + backend + fileBacked2 + compression + standard + + version + + major + 3 + minor + 53 + + + diff --git a/coverage.txt b/coverage.txt new file mode 100644 index 0000000..477a76c --- /dev/null +++ b/coverage.txt @@ -0,0 +1,41380 @@ +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/array.hxx: + 1| |/* Handling of SQL arrays. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/field instead. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_ARRAY + 12| |#define PQXX_H_ARRAY + 13| | + 14| |#if !defined(PQXX_HEADER_PRE) + 15| |# error "Include libpqxx headers as , not ." + 16| |#endif + 17| | + 18| |#include + 19| |#include + 20| |#include + 21| |#include + 22| |#include + 23| |#include + 24| |#include + 25| | + 26| |#include "pqxx/connection.hxx" + 27| |#include "pqxx/internal/array-composite.hxx" + 28| |#include "pqxx/internal/encoding_group.hxx" + 29| |#include "pqxx/internal/encodings.hxx" + 30| | + 31| | + 32| |namespace pqxx + 33| |{ + 34| |// TODO: Specialise for string_view/zview, allocate all strings in one buffer. + 35| | + 36| |/// An SQL array received from the database. + 37| |/** Parses an SQL array from its text format, making it available as a + 38| | * container of C++-side values. + 39| | * + 40| | * The array can have one or more dimensions. You must specify the number of + 41| | * dimensions at compile time. In each dimension, the array has a size which + 42| | * the `array` constructor determines at run time based on the SQL array's + 43| | * textual representation. The sizes of a given SQL array are consistent: if + 44| | * your array has two dimensions, for example, then it will have one + 45| | * "horizontal" size which determines the number of elements in each row; and + 46| | * it will have one "vertical" size which determines the number of rows. + 47| | * + 48| | * Physical memory storage is "row-major." This means that the last of the + 49| | * dimensions represents a row. So in memory, element `a[m][n]` comes right + 50| | * before `a[m][n+1]`. + 51| | */ + 52| |template< + 53| | typename ELEMENT, std::size_t DIMENSIONS = 1u, + 54| | char SEPARATOR = array_separator> + 55| |class array final + 56| |{ + 57| |public: + 58| | /// Parse an SQL array, read as text from a pqxx::result or stream. + 59| | /** Uses `cx` only during construction, to find out the text encoding in + 60| | * which it should interpret `data`. + 61| | * + 62| | * Once the `array` constructor completes, destroying or moving the + 63| | * `connection` will not affect the `array` object in any way. + 64| | * + 65| | * @throws pqxx::unexpected_null if the array contains a null value, and the + 66| | * `ELEMENT` type does not support null values. + 67| | */ + 68| | array(std::string_view data, connection const &cx) : + 69| | array{data, pqxx::internal::enc_group(cx.encoding_id())} + 70| | {} + 71| | + 72| | /// How many dimensions does this array have? + 73| | /** This value is known at compile time. + 74| | */ + 75| | constexpr std::size_t dimensions() noexcept { return DIMENSIONS; } + 76| | + 77| | /// Return the sizes of this array in each of its dimensions. + 78| | /** The last of the sizes is the number of elements in a single row. The + 79| | * size before that is the number of rows of elements, and so on. The first + 80| | * is the "outer" size. + 81| | */ + 82| | std::array const &sizes() noexcept + 83| | { + 84| | return m_extents; + 85| | } + 86| | + 87| | template ELEMENT const &at(INDEX... index) const + 88| | { + 89| | static_assert(sizeof...(index) == DIMENSIONS); + 90| | check_bounds(index...); + 91| | return m_elts.at(locate(index...)); + 92| | } + 93| | + 94| | /// Access element (without bounds check). + 95| | /** Return element at given index. Blindly assumes that the index lies + 96| | * within the bounds of the array. This is likely to be slightly faster than + 97| | * `at()`. + 98| | * + 99| | * Multi-dimensional indexing using `operator[]` only works in C++23 or + 100| | * better. In older versions of C++ it will work only with + 101| | * single-dimensional arrays. + 102| | */ + 103| | template ELEMENT const &operator[](INDEX... index) const + 104| | { + 105| | static_assert(sizeof...(index) == DIMENSIONS); + 106| | return m_elts[locate(index...)]; + 107| | } + 108| | + 109| | /// Begin iteration of individual elements. + 110| | /** If this is a multi-dimensional array, iteration proceeds in row-major + 111| | * order. So for example, a two-dimensional array `a` would start at + 112| | * `a[0, 0]`, then `a[0, 1]`, and so on. Once it reaches the end of that + 113| | * first row, it moves on to element `a[1, 0]`, and continues from there. + 114| | */ + 115| | constexpr auto cbegin() const noexcept { return m_elts.cbegin(); } + 116| | /// Return end point of iteration. + 117| | constexpr auto cend() const noexcept { return m_elts.cend(); } + 118| | /// Begin reverse iteration. + 119| | constexpr auto crbegin() const noexcept { return m_elts.crbegin(); } + 120| | /// Return end point of reverse iteration. + 121| | constexpr auto crend() const noexcept { return m_elts.crend(); } + 122| | + 123| | /// Number of elements in the array. + 124| | /** This includes all elements, in all dimensions. Therefore it is the + 125| | * product of all values in `sizes()`. + 126| | */ + 127| | constexpr std::size_t size() const noexcept { return m_elts.size(); } + 128| | + 129| | /// Number of elements in the array (as a signed number). + 130| | /** This includes all elements, in all dimensions. Therefore it is the + 131| | * product of all values in `sizes()`. + 132| | * + 133| | * In principle, the size could get so large that it had no signed + 134| | * equivalent. If that can ever happen, this is your own problem and + 135| | * behaviour is undefined. + 136| | * + 137| | * In practice however, I don't think `ssize()` could ever overflow. You'd + 138| | * need an array where each element takes up just one byte, such as Booleans, + 139| | * filling up more than half your address space. But the input string for + 140| | * that array would need at least two bytes per value: one for the value, one + 141| | * for the separating comma between elements. So even then you wouldn't have + 142| | * enough address space to create the array, even if your system allowed you + 143| | * to use your full address space. + 144| | */ + 145| | constexpr auto ssize() const noexcept + 146| | { + 147| | return static_cast(size()); + 148| | } + 149| | + 150| | /// Refer to the first element, if any. + 151| | /** If the array is empty, dereferencing this results in undefined behaviour. + 152| | */ + 153| | constexpr auto front() const noexcept { return m_elts.front(); } + 154| | + 155| | /// Refer to the last element, if any. + 156| | /** If the array is empty, dereferencing this results in undefined behaviour. + 157| | */ + 158| | constexpr auto back() const noexcept { return m_elts.back(); } + 159| | + 160| |private: + 161| | /// Throw an error if `data` is not a `DIMENSIONS`-dimensional SQL array. + 162| | /** Sanity-checks two aspects of the array syntax: the opening braces at the + 163| | * beginning, and the closing braces at the end. + 164| | * + 165| | * One syntax error this does not detect, for efficiency reasons, is for too + 166| | * many closing braces at the end. That's a tough one to detect without + 167| | * walking through the entire array sequentially, and identifying all the + 168| | * character boundaries. The main parsing routine detects that one. + 169| | */ + 170| | void check_dims(std::string_view data) + 171| | { + 172| | auto sz{std::size(data)}; + 173| | if (sz < DIMENSIONS * 2) + 174| | throw conversion_error{pqxx::internal::concat( + 175| | "Trying to parse a ", DIMENSIONS, "-dimensional array out of '", data, + 176| | "'.")}; + 177| | + 178| | // Making some assumptions here: + 179| | // * The array holds no extraneous whitespace. + 180| | // * None of the sub-arrays can be null. + 181| | // * Only ASCII characters start off with a byte in the 0-127 range. + 182| | // + 183| | // Given those, the input must start with a sequence of DIMENSIONS bytes + 184| | // with the ASCII value for '{'; and likewise it must end with a sequence + 185| | // of DIMENSIONS bytes with the ASCII value for '}'. + 186| | + 187| | if (data[0] != '{') + 188| | throw conversion_error{"Malformed array: does not start with '{'."}; + 189| | for (std::size_t i{0}; i < DIMENSIONS; ++i) + 190| | if (data[i] != '{') + 191| | throw conversion_error{pqxx::internal::concat( + 192| | "Expecting ", DIMENSIONS, "-dimensional array, but found ", i, ".")}; + 193| | if (data[DIMENSIONS] == '{') + 194| | throw conversion_error{pqxx::internal::concat( + 195| | "Tried to parse ", DIMENSIONS, + 196| | "-dimensional array from array data that has more dimensions.")}; + 197| | for (std::size_t i{0}; i < DIMENSIONS; ++i) + 198| | if (data[sz - 1 - i] != '}') + 199| | throw conversion_error{ + 200| | "Malformed array: does not end in the right number of '}'."}; + 201| | } + 202| | + 203| | // Allow fields to construct arrays passing the encoding group. + 204| | // Couldn't make this work through a call gate, thanks to the templating. + 205| | friend class ::pqxx::field; + 206| | + 207| | array(std::string_view data, pqxx::internal::encoding_group enc) + 208| | { + 209| | using group = pqxx::internal::encoding_group; + 210| | switch (enc) + 211| | { + 212| | case group::MONOBYTE: parse(data); break; + 213| | case group::BIG5: parse(data); break; + 214| | case group::EUC_CN: parse(data); break; + 215| | case group::EUC_JP: parse(data); break; + 216| | case group::EUC_KR: parse(data); break; + 217| | case group::EUC_TW: parse(data); break; + 218| | case group::GB18030: parse(data); break; + 219| | case group::GBK: parse(data); break; + 220| | case group::JOHAB: parse(data); break; + 221| | case group::MULE_INTERNAL: parse(data); break; + 222| | case group::SJIS: parse(data); break; + 223| | case group::UHC: parse(data); break; + 224| | case group::UTF8: parse(data); break; + 225| | default: PQXX_UNREACHABLE; break; + 226| | } + 227| | } + 228| | + 229| | /// Handle the end of a field. + 230| | /** Check for a trailing separator, detect any syntax errors at this somewhat + 231| | * complicated point, and return the offset where parsing should continue. + 232| | */ + 233| | std::size_t parse_field_end(std::string_view data, std::size_t here) const + 234| | { + 235| | auto const sz{std::size(data)}; + 236| | if (here < sz) + 237| | switch (data[here]) + 238| | { + 239| | case SEPARATOR: + 240| | ++here; + 241| | if (here >= sz) + 242| | throw conversion_error{"Array looks truncated."}; + 243| | switch (data[here]) + 244| | { + 245| | case SEPARATOR: + 246| | throw conversion_error{"Array contains double separator."}; + 247| | case '}': throw conversion_error{"Array contains trailing separator."}; + 248| | default: break; + 249| | } + 250| | break; + 251| | case '}': break; + 252| | default: + 253| | throw conversion_error{pqxx::internal::concat( + 254| | "Unexpected character in array: ", + 255| | static_cast(static_cast(data[here])), + 256| | " where separator or closing brace expected.")}; + 257| | } + 258| | return here; + 259| | } + 260| | + 261| | /// Estimate the number of elements in this array. + 262| | /** We use this to pre-allocate internal storage, so that we don't need to + 263| | * keep extending it on the fly. It doesn't need to be too precise, so long + 264| | * as it's fast; doesn't usually underestimate; and never overestimates by + 265| | * orders of magnitude. + 266| | */ + 267| | constexpr std::size_t estimate_elements(std::string_view data) const noexcept + 268| | { + 269| | // Dirty trick: just count the number of bytes that look as if they may be + 270| | // separators. At the very worst we may overestimate by a factor of two or + 271| | // so, in exceedingly rare cases, on some encodings. + 272| | auto const separators{ + 273| | std::count(std::begin(data), std::end(data), SEPARATOR)}; + 274| | // The number of dimensions makes no difference here. It's still one + 275| | // separator between consecutive elements, just possibly with some extra + 276| | // braces as well. + 277| | return static_cast(separators + 1); + 278| | } + 279| | + 280| | template + 281| | void parse(std::string_view data) + 282| | { + 283| | static_assert(DIMENSIONS > 0u, "Can't create a zero-dimensional array."); + 284| | auto const sz{std::size(data)}; + 285| | check_dims(data); + 286| | + 287| | m_elts.reserve(estimate_elements(data)); + 288| | + 289| | // We discover the array's extents along each of the dimensions, starting + 290| | // with the final dimension and working our way towards the first. At any + 291| | // given point during parsing, we know the extents starting at this + 292| | // dimension. + 293| | std::size_t know_extents_from{DIMENSIONS}; + 294| | + 295| | // Currently parsing this dimension. We start off at -1, relying on C++'s + 296| | // well-defined rollover for unsigned numbers. + 297| | // The actual outermost dimension of the array is 0, and the innermost is + 298| | // at the end. But, the array as a whole is enclosed in braces just like + 299| | // each row. So we act like there's an anomalous "outer" dimension holding + 300| | // the entire array. + 301| | constexpr std::size_t outer{std::size_t{0u} - std::size_t{1u}}; + 302| | + 303| | // We start parsing at the fictional outer dimension. The input begins + 304| | // with opening braces, one for each dimension, so we'll start off by + 305| | // bumping all the way to the innermost dimension. + 306| | std::size_t dim{outer}; + 307| | + 308| | // Extent counters, one per "real" dimension. + 309| | // Note initialiser syntax; this zero-initialises all elements. + 310| | std::array extents{}; + 311| | + 312| | // Current parsing position. + 313| | std::size_t here{0}; + 314| | PQXX_ASSUME(here <= sz); + 315| | while (here < sz) + 316| | { + 317| | if (data[here] == '{') + 318| | { + 319| | if (dim == outer) + 320| | { + 321| | // This must be the initial opening brace. + 322| | if (know_extents_from != DIMENSIONS) + 323| | throw conversion_error{ + 324| | "Array text representation closed and reopened its outside " + 325| | "brace pair."}; + 326| | assert(here == 0); + 327| | PQXX_ASSUME(here == 0); + 328| | } + 329| | else + 330| | { + 331| | if (dim >= (DIMENSIONS - 1)) + 332| | throw conversion_error{ + 333| | "Array seems to have inconsistent number of dimensions."}; + 334| | ++extents[dim]; + 335| | } + 336| | // (Rolls over to zero if we're coming from the outer dimension.) + 337| | ++dim; + 338| | extents[dim] = 0u; + 339| | ++here; + 340| | } + 341| | else if (data[here] == '}') + 342| | { + 343| | if (dim == outer) + 344| | throw conversion_error{"Array has spurious '}'."}; + 345| | if (dim < know_extents_from) + 346| | { + 347| | // We just finished parsing our first row in this dimension. + 348| | // Now we know the array dimension's extent. + 349| | m_extents[dim] = extents[dim]; + 350| | know_extents_from = dim; + 351| | } + 352| | else + 353| | { + 354| | if (extents[dim] != m_extents[dim]) + 355| | throw conversion_error{"Rows in array have inconsistent sizes."}; + 356| | } + 357| | // Bump back down to the next-lower dimension. Which may be the outer + 358| | // dimension, through underflow. + 359| | --dim; + 360| | ++here; + 361| | here = parse_field_end(data, here); + 362| | } + 363| | else + 364| | { + 365| | // Found an array element. The actual elements always live in the + 366| | // "inner" dimension. + 367| | if (dim != DIMENSIONS - 1) + 368| | throw conversion_error{ + 369| | "Malformed array: found element where sub-array was expected."}; + 370| | assert(dim != outer); + 371| | ++extents[dim]; + 372| | std::size_t end; + 373| | switch (data[here]) + 374| | { + 375| | case '\0': throw conversion_error{"Unexpected zero byte in array."}; + 376| | case ',': throw conversion_error{"Array contains empty field."}; + 377| | case '"': { + 378| | // Double-quoted string. We parse it into a buffer before parsing + 379| | // the resulting string as an element. This seems wasteful: the + 380| | // string might not contain any special characters. So it's + 381| | // tempting to check, and try to use a string_view and avoid a + 382| | // useless copy step. But. Even besides the branch prediction + 383| | // risk, the very fact that the back-end chose to quote the string + 384| | // indicates that there is some kind of special character in there. + 385| | // So in practice, this optimisation would only apply if the only + 386| | // special characters in the string were commas. + 387| | end = pqxx::internal::scan_double_quoted_string( + 388| | std::data(data), std::size(data), here); + 389| | // TODO: scan_double_quoted_string() with reusable buffer. + 390| | std::string const buf{ + 391| | pqxx::internal::parse_double_quoted_string( + 392| | std::data(data), end, here)}; + 393| | m_elts.emplace_back(from_string(buf)); + 394| | } + 395| | break; + 396| | default: { + 397| | // Unquoted string. An unquoted string is always literal, no + 398| | // escaping or encoding, so we don't need to parse it into a + 399| | // buffer. We can just read it as a string_view. + 400| | end = pqxx::internal::scan_unquoted_string( + 401| | std::data(data), std::size(data), here); + 402| | std::string_view const field{ + 403| | std::string_view{std::data(data) + here, end - here}}; + 404| | if (field == "NULL") + 405| | { + 406| | if constexpr (nullness::has_null) + 407| | m_elts.emplace_back(nullness::null()); + 408| | else + 409| | throw unexpected_null{pqxx::internal::concat( + 410| | "Array contains a null ", type_name, + 411| | ". Consider making it an array of std::optional<", + 412| | type_name, "> instead.")}; + 413| | } + 414| | else + 415| | m_elts.emplace_back(from_string(field)); + 416| | } + 417| | } + 418| | here = end; + 419| | PQXX_ASSUME(here <= sz); + 420| | here = parse_field_end(data, here); + 421| | } + 422| | } + 423| | + 424| | if (dim != outer) + 425| | throw conversion_error{"Malformed array; may be truncated."}; + 426| | assert(know_extents_from == 0); + 427| | PQXX_ASSUME(know_extents_from == 0); + 428| | + 429| | init_factors(); + 430| | } + 431| | + 432| | /// Pre-compute indexing factors. + 433| | void init_factors() noexcept + 434| | { + 435| | std::size_t factor{1}; + 436| | for (std::size_t dim{DIMENSIONS - 1}; dim > 0; --dim) + 437| | { + 438| | factor *= m_extents[dim]; + 439| | m_factors[dim - 1] = factor; + 440| | } + 441| | } + 442| | + 443| | /// Map a multidimensional index to an entry in our linear storage. + 444| | template std::size_t locate(INDEX... index) const noexcept + 445| | { + 446| | static_assert( + 447| | sizeof...(index) == DIMENSIONS, + 448| | "Indexing array with wrong number of dimensions."); + 449| | return add_index(index...); + 450| | } + 451| | + 452| | template + 453| | constexpr std::size_t add_index(OUTER outer, INDEX... indexes) const noexcept + 454| | { + 455| | std::size_t const first{check_cast(outer, "array index"sv)}; + 456| | if constexpr (sizeof...(indexes) == 0) + 457| | { + 458| | return first; + 459| | } + 460| | else + 461| | { + 462| | static_assert(sizeof...(indexes) < DIMENSIONS); + 463| | // (Offset by 1 here because the outer dimension is not in there.) + 464| | constexpr auto dimension{DIMENSIONS - (sizeof...(indexes) + 1)}; + 465| | static_assert(dimension < DIMENSIONS); + 466| | return first * m_factors[dimension] + add_index(indexes...); + 467| | } + 468| | } + 469| | + 470| | /// Check that indexes are within bounds. + 471| | /** @throw pqxx::range_error if not. + 472| | */ + 473| | template + 474| | constexpr void check_bounds(OUTER outer, INDEX... indexes) const + 475| | { + 476| | std::size_t const first{check_cast(outer, "array index"sv)}; + 477| | static_assert(sizeof...(indexes) < DIMENSIONS); + 478| | // (Offset by 1 here because the outer dimension is not in there.) + 479| | constexpr auto dimension{DIMENSIONS - (sizeof...(indexes) + 1)}; + 480| | static_assert(dimension < DIMENSIONS); + 481| | if (first >= m_extents[dimension]) + 482| | throw range_error{pqxx::internal::concat( + 483| | "Array index for dimension ", dimension, " is out of bounds: ", first, + 484| | " >= ", m_extents[dimension])}; + 485| | + 486| | // Now check the rest of the indexes, if any. + 487| | if constexpr (sizeof...(indexes) > 0) + 488| | check_bounds(indexes...); + 489| | } + 490| | + 491| | /// Linear storage for the array's elements. + 492| | std::vector m_elts; + 493| | + 494| | /// Size along each dimension. + 495| | std::array m_extents; + 496| | + 497| | /// Multiplication factors for indexing in each dimension. + 498| | /** This wouldn't make any sense if `locate()` could recurse from the "inner" + 499| | * dimension towards the "outer" one. Unfortunately we've got to recurse in + 500| | * the opposite direction, so it helps to pre-compute the factors. + 501| | * + 502| | * We don't need to cache a factor for the outer dimension, since we never + 503| | * multiply by that number. + 504| | */ + 505| | std::array m_factors; + 506| |}; + 507| | + 508| | + 509| |/// Low-level parser for C++ arrays. @deprecated Use @ref pqxx::array instead. + 510| |/** Clunky old API for parsing SQL arrays. + 511| | * + 512| | * @warning This parser will only work reliably if your client encoding is + 513| | * UTF-8, ASCII, or a "safe ASCII superset" (such as the EUC encodings) where + 514| | * a byte value in the ASCII range can only occur as an actual ASCII character, + 515| | * never as one byte in a multi-byte character. + 516| | * + 517| | * @warning The parser only supports array element types which use a comma + 518| | * (`','`) as the separator between array elements. All built-in SQL types use + 519| | * comma, except for `box` which uses semicolon. However some custom types may + 520| | * not work. + 521| | * + 522| | * The input is a C-style string containing the textual representation of an + 523| | * array, as returned by the database. The parser reads this representation + 524| | * on the fly. The string must remain in memory until parsing is done. + 525| | * + 526| | * Parse the array by making calls to @ref get_next until it returns a + 527| | * @ref juncture of `done`. The @ref juncture tells you what the parser found + 528| | * in that step: did the array "nest" to a deeper level, or "un-nest" back up? + 529| | */ + 530| |class PQXX_LIBEXPORT array_parser + 531| |{ + 532| |public: + 533| | /// What's the latest thing found in the array? + 534| | enum class juncture + 535| | { + 536| | /// Starting a new row. + 537| | row_start, + 538| | /// Ending the current row. + 539| | row_end, + 540| | /// Found a NULL value. + 541| | null_value, + 542| | /// Found a string value. + 543| | string_value, + 544| | /// Parsing has completed. + 545| | done, + 546| | }; + 547| | + 548| | /// Constructor. You don't need this; use @ref field::as_array instead. + 549| | /** The parser only remains valid while the data underlying the @ref result + 550| | * remains valid. Once all `result` objects referring to that data have been + 551| | * destroyed, the parser will no longer refer to valid memory. + 552| | */ + 553| | explicit array_parser( + 554| | std::string_view input, + 555| | internal::encoding_group = internal::encoding_group::MONOBYTE); + 556| | + 557| | /// Parse the next step in the array. + 558| | /** Returns what it found. If the juncture is @ref juncture::string_value, + 559| | * the string will contain the value. Otherwise, it will be empty. + 560| | * + 561| | * Call this until the @ref array_parser::juncture it returns is + 562| | * @ref juncture::done. + 563| | */ + 564| 0| std::pair get_next() { return (this->*m_impl)(); } + 565| | + 566| |private: + 567| | std::string_view m_input; + 568| | + 569| | /// Current parsing position in the input. + 570| | std::size_t m_pos = 0u; + 571| | + 572| | /// A function implementing the guts of `get_next`. + 573| | /** Internally this class uses a template to specialise the implementation of + 574| | * `get_next` for each of the various encoding groups. This allows the + 575| | * compiler to inline the parsing of each text encoding, which happens in + 576| | * very hot loops. + 577| | */ + 578| | using implementation = std::pair (array_parser::*)(); + 579| | + 580| | /// Pick the `implementation` for `enc`. + 581| | static implementation + 582| | specialize_for_encoding(pqxx::internal::encoding_group enc); + 583| | + 584| | /// Our implementation of `parse_array_step`, specialised for our encoding. + 585| | implementation m_impl; + 586| | + 587| | /// Perform one step of array parsing. + 588| | template + 589| | std::pair parse_array_step(); + 590| | + 591| | template + 592| | std::string::size_type scan_double_quoted_string() const; + 593| | template + 594| | std::string parse_double_quoted_string(std::string::size_type end) const; + 595| | template + 596| | std::string::size_type scan_unquoted_string() const; + 597| | template + 598| | std::string_view parse_unquoted_string(std::string::size_type end) const; + 599| | + 600| | template + 601| | std::string::size_type scan_glyph(std::string::size_type pos) const; + 602| | template + 603| | std::string::size_type + 604| | scan_glyph(std::string::size_type pos, std::string::size_type end) const; + 605| |}; + 606| |} // namespace pqxx + 607| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/binarystring.hxx: + 1| |/* Deprecated representation for raw, binary data. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/binarystring instead. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_BINARYSTRING + 12| |#define PQXX_H_BINARYSTRING + 13| | + 14| |#if !defined(PQXX_HEADER_PRE) + 15| |# error "Include libpqxx headers as , not ." + 16| |#endif + 17| | + 18| |#include + 19| |#include + 20| |#include + 21| | + 22| |#include "pqxx/result.hxx" + 23| |#include "pqxx/strconv.hxx" + 24| | + 25| |namespace pqxx + 26| |{ + 27| |class binarystring; + 28| |template<> struct string_traits; + 29| | + 30| | + 31| |/// Binary data corresponding to PostgreSQL's "BYTEA" binary-string type. + 32| |/** @ingroup escaping-functions + 33| | * @deprecated Use @c bytes and @c bytes_view for binary data. In C++20 or + 34| | * better, any @c contiguous_range of @c std::byte will do. + 35| | * + 36| | * This class represents a binary string as stored in a field of type @c bytea. + 37| | * + 38| | * Internally a binarystring is zero-terminated, but it may also contain null + 39| | * bytes, they're just like any other byte value. So don't assume that it's + 40| | * safe to treat the contents as a C-style string. + 41| | * + 42| | * The binarystring retains its value even if the result it was obtained from + 43| | * is destroyed, but it cannot be copied or assigned. + 44| | * + 45| | * \relatesalso transaction_base::quote_raw + 46| | * + 47| | * To include a @c binarystring value in an SQL query, escape and quote it + 48| | * using the transaction's @c quote_raw function. + 49| | * + 50| | * @warning This class is implemented as a reference-counting smart pointer. + 51| | * Copying, swapping, and destroying binarystring objects that refer to the + 52| | * same underlying data block is not thread-safe. If you wish to pass + 53| | * binarystrings around between threads, make sure that each of these + 54| | * operations is protected against concurrency with similar operations on the + 55| | * same object, or other objects pointing to the same data block. + 56| | */ + 57| |class PQXX_LIBEXPORT binarystring + 58| |{ + 59| |public: + 60| | using char_type = unsigned char; + 61| | using value_type = char_type; + 62| | using size_type = std::size_t; + 63| | using difference_type = long; + 64| | using const_reference = value_type const &; + 65| | using const_pointer = value_type const *; + 66| | using const_iterator = const_pointer; + 67| | using const_reverse_iterator = std::reverse_iterator; + 68| | + 69| | [[deprecated("Use std::byte for binary data.")]] binarystring( + 70| | binarystring const &) = default; + 71| | + 72| | /// Read and unescape bytea field. + 73| | /** The field will be zero-terminated, even if the original bytea field + 74| | * isn't. + 75| | * @param F the field to read; must be a bytea field + 76| | */ + 77| | [[deprecated("Use std::byte for binary data.")]] explicit binarystring( + 78| | field const &); + 79| | + 80| | /// Copy binary data from std::string_view on binary data. + 81| | /** This is inefficient in that it copies the data to a buffer allocated on + 82| | * the heap. + 83| | */ + 84| | [[deprecated("Use std::byte for binary data.")]] explicit binarystring( + 85| | std::string_view); + 86| | + 87| | /// Copy binary data of given length straight out of memory. + 88| | [[deprecated("Use std::byte for binary data.")]] binarystring( + 89| | void const *, std::size_t); + 90| | + 91| | /// Efficiently wrap a buffer of binary data in a @c binarystring. + 92| | [[deprecated("Use std::byte for binary data.")]] binarystring( + 93| | std::shared_ptr ptr, size_type size) : + 94| | m_buf{std::move(ptr)}, m_size{size} + 95| 0| {} + 96| | + 97| | /// Size of converted string in bytes. + 98| 0| [[nodiscard]] size_type size() const noexcept { return m_size; } + 99| | /// Size of converted string in bytes. + 100| 0| [[nodiscard]] size_type length() const noexcept { return size(); } + 101| 0| [[nodiscard]] bool empty() const noexcept { return size() == 0; } + 102| | + 103| 0| [[nodiscard]] const_iterator begin() const noexcept { return data(); } + 104| 0| [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); } + 105| 0| [[nodiscard]] const_iterator end() const noexcept { return data() + m_size; } + 106| 0| [[nodiscard]] const_iterator cend() const noexcept { return end(); } + 107| | + 108| 0| [[nodiscard]] const_reference front() const noexcept { return *begin(); } + 109| | [[nodiscard]] const_reference back() const noexcept + 110| 0| { + 111| 0| return *(data() + m_size - 1); + 112| 0| } + 113| | + 114| | [[nodiscard]] const_reverse_iterator rbegin() const + 115| 0| { + 116| 0| return const_reverse_iterator{end()}; + 117| 0| } + 118| 0| [[nodiscard]] const_reverse_iterator crbegin() const { return rbegin(); } + 119| | [[nodiscard]] const_reverse_iterator rend() const + 120| 0| { + 121| 0| return const_reverse_iterator{begin()}; + 122| 0| } + 123| 0| [[nodiscard]] const_reverse_iterator crend() const { return rend(); } + 124| | + 125| | /// Unescaped field contents. + 126| 0| [[nodiscard]] value_type const *data() const noexcept { return m_buf.get(); } + 127| | + 128| | [[nodiscard]] const_reference operator[](size_type i) const noexcept + 129| 0| { + 130| 0| return data()[i]; + 131| 0| } + 132| | + 133| | [[nodiscard]] PQXX_PURE bool operator==(binarystring const &) const noexcept; + 134| | [[nodiscard]] bool operator!=(binarystring const &rhs) const noexcept + 135| 0| { + 136| 0| return not operator==(rhs); + 137| 0| } + 138| | + 139| | binarystring &operator=(binarystring const &); + 140| | + 141| | /// Index contained string, checking for valid index. + 142| | const_reference at(size_type) const; + 143| | + 144| | /// Swap contents with other binarystring. + 145| | void swap(binarystring &); + 146| | + 147| | /// Raw character buffer (no terminating zero is added). + 148| | /** @warning No terminating zero is added! If the binary data did not end in + 149| | * a null character, you will not find one here. + 150| | */ + 151| | [[nodiscard]] char const *get() const noexcept + 152| 0| { + 153| 0| return reinterpret_cast(m_buf.get()); + 154| 0| } + 155| | + 156| | /// Read contents as a std::string_view. + 157| | [[nodiscard]] std::string_view view() const noexcept + 158| 0| { + 159| 0| return std::string_view(get(), size()); + 160| 0| } + 161| | + 162| | /// Read as regular C++ string (may include null characters). + 163| | /** This creates and returns a new string object. Don't call this + 164| | * repeatedly; retrieve your string once and keep it in a local variable. + 165| | * Also, do not expect to be able to compare the string's address to that of + 166| | * an earlier invocation. + 167| | */ + 168| | [[nodiscard]] std::string str() const; + 169| | + 170| | /// Access data as a pointer to @c std::byte. + 171| | [[nodiscard]] std::byte const *bytes() const + 172| 0| { + 173| 0| return reinterpret_cast(get()); + 174| 0| } + 175| | + 176| | /// Read data as a @c bytes_view. + 177| | [[nodiscard]] pqxx::bytes_view bytes_view() const + 178| 0| { + 179| 0| return pqxx::bytes_view{bytes(), size()}; + 180| 0| } + 181| | + 182| |private: + 183| | std::shared_ptr m_buf; + 184| | size_type m_size{0}; + 185| |}; + 186| | + 187| | + 188| |template<> struct nullness : no_null + 189| |{}; + 190| | + 191| | + 192| |/// String conversion traits for @c binarystring. + 193| |/** Defines the conversions between a @c binarystring and its PostgreSQL + 194| | * textual format, for communication with the database. + 195| | * + 196| | * These conversions rely on the "hex" format which was introduced in + 197| | * PostgreSQL 9.0. Both your libpq and the server must be recent enough to + 198| | * speak this format. + 199| | */ + 200| |template<> struct string_traits + 201| |{ + 202| | static std::size_t size_buffer(binarystring const &value) noexcept + 203| 0| { + 204| 0| return internal::size_esc_bin(std::size(value)); + 205| 0| } + 206| | + 207| | static zview to_buf(char *begin, char *end, binarystring const &value) + 208| 0| { + 209| 0| return generic_to_buf(begin, end, value); + 210| 0| } + 211| | + 212| | static char *into_buf(char *begin, char *end, binarystring const &value) + 213| 0| { + 214| 0| auto const budget{size_buffer(value)}; + 215| 0| if (internal::cmp_less(end - begin, budget)) + 216| 0| throw conversion_overrun{ + 217| 0| "Not enough buffer space to escape binary data."}; + 218| 0| std::string_view text{value.view()}; + 219| 0| internal::esc_bin(binary_cast(text), begin); + 220| 0| return begin + budget; + 221| 0| } + 222| | + 223| | static binarystring from_string(std::string_view text) + 224| 0| { + 225| 0| auto const size{pqxx::internal::size_unesc_bin(std::size(text))}; + 226| 0| std::shared_ptr buf{ + 227| 0| new unsigned char[size], [](unsigned char const *x) { delete[] x; }}; + 228| 0| pqxx::internal::unesc_bin(text, reinterpret_cast(buf.get())); + 229| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 230| 0| return binarystring{std::move(buf), size}; + 231| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 232| 0| } + 233| |}; + 234| |} // namespace pqxx + 235| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/blob.hxx: + 1| |/* Binary Large Objects interface. + 2| | * + 3| | * Read or write large objects, stored in their own storage on the server. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/largeobject instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_BLOB + 14| |#define PQXX_H_BLOB + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include + 21| | + 22| |#if defined(PQXX_HAVE_PATH) + 23| |# include + 24| |#endif + 25| | + 26| |// C++20: Assume support. + 27| |#if __has_include() + 28| |# include + 29| |#endif + 30| | + 31| |// C++20: Assume support. + 32| |#if __has_include() + 33| |# include + 34| |#endif + 35| | + 36| |#include "pqxx/dbtransaction.hxx" + 37| | + 38| | + 39| |namespace pqxx + 40| |{ + 41| |/** Binary large object. + 42| | * + 43| | * This is how you store data that may be too large for the `BYTEA` type. + 44| | * Access operations are similar to those for a file: you can read, write, + 45| | * query or set the current reading/writing position, and so on. + 46| | * + 47| | * These large objects live in their own storage on the server, indexed by an + 48| | * integer object identifier ("oid"). + 49| | * + 50| | * Two `blob` objects may refer to the same actual large object in the + 51| | * database at the same time. Each will have its own reading/writing position, + 52| | * but writes to the one will of course affect what the other sees. + 53| | */ + 54| |class PQXX_LIBEXPORT blob + 55| |{ + 56| |public: + 57| | /// Create a new, empty large object. + 58| | /** You may optionally specify an oid for the new blob. If you do, then + 59| | * the new object will have that oid -- or creation will fail if there + 60| | * already is an object with that oid. + 61| | */ + 62| | [[nodiscard]] static oid create(dbtransaction &, oid = 0); + 63| | + 64| | /// Delete a large object, or fail if it does not exist. + 65| | static void remove(dbtransaction &, oid); + 66| | + 67| | /// Open blob for reading. Any attempt to write to it will fail. + 68| | [[nodiscard]] static blob open_r(dbtransaction &, oid); + 69| | // Open blob for writing. Any attempt to read from it will fail. + 70| | [[nodiscard]] static blob open_w(dbtransaction &, oid); + 71| | // Open blob for reading and/or writing. + 72| | [[nodiscard]] static blob open_rw(dbtransaction &, oid); + 73| | + 74| | /// You can default-construct a blob, but it won't do anything useful. + 75| | /** Most operations on a default-constructed blob will throw @ref + 76| | * usage_error. + 77| | */ + 78| | blob() = default; + 79| | + 80| | /// You can move a blob, but not copy it. The original becomes unusable. + 81| | blob(blob &&); + 82| | /// You can move a blob, but not copy it. The original becomes unusable. + 83| | blob &operator=(blob &&); + 84| | + 85| | blob(blob const &) = delete; + 86| | blob &operator=(blob const &) = delete; + 87| | ~blob(); + 88| | + 89| | /// Maximum number of bytes that can be read or written at a time. + 90| | /** The underlying protocol only supports reads and writes up to 2 GB + 91| | * exclusive. + 92| | * + 93| | * If you need to read or write more data to or from a binary large object, + 94| | * you'll have to break it up into chunks. + 95| | */ + 96| | static constexpr std::size_t chunk_limit = 0x7fffffff; + 97| | + 98| | /// Read up to `size` bytes of the object into `buf`. + 99| | /** Uses a buffer that you provide, resizing it as needed. If it suits you, + 100| | * this lets you allocate the buffer once and then re-use it multiple times. + 101| | * + 102| | * Resizes `buf` as needed. + 103| | * + 104| | * @warning The underlying protocol only supports reads up to 2GB at a time. + 105| | * If you need to read more, try making repeated calls to @ref append_to_buf. + 106| | */ + 107| | std::size_t read(bytes &buf, std::size_t size); + 108| | + 109| |#if defined(PQXX_HAVE_SPAN) + 110| | /// Read up to `std::size(buf)` bytes from the object. + 111| | /** Retrieves bytes from the blob, at the current position, until `buf` is + 112| | * full or there are no more bytes to read, whichever comes first. + 113| | * + 114| | * Returns the filled portion of `buf`. This may be empty. + 115| | */ + 116| | template + 117| | std::span read(std::span buf) + 118| | { + 119| | return buf.subspan(0, raw_read(std::data(buf), std::size(buf))); + 120| | } + 121| |#endif // PQXX_HAVE_SPAN + 122| | + 123| |#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN) + 124| | /// Read up to `std::size(buf)` bytes from the object. + 125| | /** Retrieves bytes from the blob, at the current position, until `buf` is + 126| | * full or there are no more bytes to read, whichever comes first. + 127| | * + 128| | * Returns the filled portion of `buf`. This may be empty. + 129| | */ + 130| | template std::span read(DATA &buf) + 131| | { + 132| | return {std::data(buf), raw_read(std::data(buf), std::size(buf))}; + 133| | } + 134| |#else // PQXX_HAVE_CONCEPTS && PQXX_HAVE_SPAN + 135| | /// Read up to `std::size(buf)` bytes from the object. + 136| | /** @deprecated As libpqxx moves to C++20 as its baseline language version, + 137| | * this will take and return `std::span`. + 138| | * + 139| | * Retrieves bytes from the blob, at the current position, until `buf` is + 140| | * full (i.e. its current size is reached), or there are no more bytes to + 141| | * read, whichever comes first. + 142| | * + 143| | * This function will not change either the size or the capacity of `buf`, + 144| | * only its contents. + 145| | * + 146| | * Returns the filled portion of `buf`. This may be empty. + 147| | */ + 148| | template bytes_view read(std::vector &buf) + 149| | { + 150| | return {std::data(buf), raw_read(std::data(buf), std::size(buf))}; + 151| | } + 152| |#endif // PQXX_HAVE_CONCEPTS && PQXX_HAVE_SPAN + 153| | + 154| |#if defined(PQXX_HAVE_CONCEPTS) + 155| | /// Write `data` to large object, at the current position. + 156| | /** If the writing position is at the end of the object, this will append + 157| | * `data` to the object's contents and move the writing position so that + 158| | * it's still at the end. + 159| | * + 160| | * If the writing position was not at the end, writing will overwrite the + 161| | * prior data, but it will not remove data that follows the part where you + 162| | * wrote your new data. + 163| | * + 164| | * @warning This is a big difference from writing to a file. You can + 165| | * overwrite some data in a large object, but this does not truncate the + 166| | * data that was already there. For example, if the object contained binary + 167| | * data "abc", and you write "12" at the starting position, the object will + 168| | * contain "12c". + 169| | * + 170| | * @warning The underlying protocol only supports writes up to 2 GB at a + 171| | * time. If you need to write more, try making repeated calls to + 172| | * @ref append_from_buf. + 173| | */ + 174| | template void write(DATA const &data) + 175| | { + 176| | raw_write(std::data(data), std::size(data)); + 177| | } + 178| |#else + 179| | /// Write `data` large object, at the current position. + 180| | /** If the writing position is at the end of the object, this will append + 181| | * `data` to the object's contents and move the writing position so that + 182| | * it's still at the end. + 183| | * + 184| | * If the writing position was not at the end, writing will overwrite the + 185| | * prior data, but it will not remove data that follows the part where you + 186| | * wrote your new data. + 187| | * + 188| | * @warning This is a big difference from writing to a file. You can + 189| | * overwrite some data in a large object, but this does not truncate the + 190| | * data that was already there. For example, if the object contained binary + 191| | * data "abc", and you write "12" at the starting position, the object will + 192| | * contain "12c". + 193| | * + 194| | * @warning The underlying protocol only supports writes up to 2 GB at a + 195| | * time. If you need to write more, try making repeated calls to + 196| | * @ref append_from_buf. + 197| | */ + 198| | template void write(DATA const &data) + 199| | { + 200| | raw_write(std::data(data), std::size(data)); + 201| | } + 202| |#endif + 203| | + 204| | /// Resize large object to `size` bytes. + 205| | /** If the blob is more than `size` bytes long, this removes the end so as + 206| | * to make the blob the desired length. + 207| | * + 208| | * If the blob is less than `size` bytes long, it adds enough zero bytes to + 209| | * make it the desired length. + 210| | */ + 211| | void resize(std::int64_t size); + 212| | + 213| | /// Return the current reading/writing position in the large object. + 214| | [[nodiscard]] std::int64_t tell() const; + 215| | + 216| | /// Set the current reading/writing position to an absolute offset. + 217| | /** Returns the new file offset. */ + 218| | std::int64_t seek_abs(std::int64_t offset = 0); + 219| | /// Move the current reading/writing position forwards by an offset. + 220| | /** To move backwards, pass a negative offset. + 221| | * + 222| | * Returns the new file offset. + 223| | */ + 224| | std::int64_t seek_rel(std::int64_t offset = 0); + 225| | /// Set the current position to an offset relative to the end of the blob. + 226| | /** You'll probably want an offset of zero or less. + 227| | * + 228| | * Returns the new file offset. + 229| | */ + 230| | std::int64_t seek_end(std::int64_t offset = 0); + 231| | + 232| | /// Create a binary large object containing given `data`. + 233| | /** You may optionally specify an oid for the new object. If you do, and an + 234| | * object with that oid already exists, creation will fail. + 235| | */ + 236| | static oid from_buf(dbtransaction &tx, bytes_view data, oid id = 0); + 237| | + 238| | /// Append `data` to binary large object. + 239| | /** The underlying protocol only supports appending blocks up to 2 GB. + 240| | */ + 241| | static void append_from_buf(dbtransaction &tx, bytes_view data, oid id); + 242| | + 243| | /// Read client-side file and store it server-side as a binary large object. + 244| | [[nodiscard]] static oid from_file(dbtransaction &, char const path[]); + 245| | + 246| |#if defined(PQXX_HAVE_PATH) && !defined(_WIN32) + 247| | /// Read client-side file and store it server-side as a binary large object. + 248| | /** This overload is not available on Windows, where `std::filesystem::path` + 249| | * converts to a `wchar_t` string rather than a `char` string. + 250| | */ + 251| | [[nodiscard]] static oid + 252| | from_file(dbtransaction &tx, std::filesystem::path const &path) + 253| 0| { + 254| 0| return from_file(tx, path.c_str()); + 255| 0| } + 256| |#endif + 257| | + 258| | /// Read client-side file and store it server-side as a binary large object. + 259| | /** In this version, you specify the binary large object's oid. If that oid + 260| | * is already in use, the operation will fail. + 261| | */ + 262| | static oid from_file(dbtransaction &, char const path[], oid); + 263| | + 264| |#if defined(PQXX_HAVE_PATH) && !defined(_WIN32) + 265| | /// Read client-side file and store it server-side as a binary large object. + 266| | /** In this version, you specify the binary large object's oid. If that oid + 267| | * is already in use, the operation will fail. + 268| | * + 269| | * This overload is not available on Windows, where `std::filesystem::path` + 270| | * converts to a `wchar_t` string rather than a `char` string. + 271| | */ + 272| | static oid + 273| | from_file(dbtransaction &tx, std::filesystem::path const &path, oid id) + 274| 0| { + 275| 0| return from_file(tx, path.c_str(), id); + 276| 0| } + 277| |#endif + 278| | + 279| | /// Convenience function: Read up to `max_size` bytes from blob with `id`. + 280| | /** You could easily do this yourself using the @ref open_r and @ref read + 281| | * functions, but it can save you a bit of code to do it this way. + 282| | */ + 283| | static void to_buf(dbtransaction &, oid, bytes &, std::size_t max_size); + 284| | + 285| | /// Read part of the binary large object with `id`, and append it to `buf`. + 286| | /** Use this to break up a large read from one binary large object into one + 287| | * massive buffer. Just keep calling this function until it returns zero. + 288| | * + 289| | * The `offset` is how far into the large object your desired chunk is, and + 290| | * `append_max` says how much to try and read in one go. + 291| | */ + 292| | static std::size_t append_to_buf( + 293| | dbtransaction &tx, oid id, std::int64_t offset, bytes &buf, + 294| | std::size_t append_max); + 295| | + 296| | /// Write a binary large object's contents to a client-side file. + 297| | static void to_file(dbtransaction &, oid, char const path[]); + 298| | + 299| |#if defined(PQXX_HAVE_PATH) && !defined(_WIN32) + 300| | /// Write a binary large object's contents to a client-side file. + 301| | /** This overload is not available on Windows, where `std::filesystem::path` + 302| | * converts to a `wchar_t` string rather than a `char` string. + 303| | */ + 304| | static void + 305| | to_file(dbtransaction &tx, oid id, std::filesystem::path const &path) + 306| 0| { + 307| 0| to_file(tx, id, path.c_str()); + 308| 0| } + 309| |#endif + 310| | + 311| | /// Close this blob. + 312| | /** This does not delete the blob from the database; it only terminates your + 313| | * local object for accessing the blob. + 314| | * + 315| | * Resets the blob to a useless state similar to one that was + 316| | * default-constructed. + 317| | * + 318| | * The destructor will do this for you automatically. Still, there is a + 319| | * reason to `close()` objects explicitly where possible: if an error should + 320| | * occur while closing, `close()` can throw an exception. A destructor + 321| | * cannot. + 322| | */ + 323| | void close(); + 324| | + 325| |private: + 326| 0| PQXX_PRIVATE blob(connection &cx, int fd) noexcept : m_conn{&cx}, m_fd{fd} {} + 327| | static PQXX_PRIVATE blob open_internal(dbtransaction &, oid, int); + 328| | static PQXX_PRIVATE pqxx::internal::pq::PGconn * + 329| | raw_conn(pqxx::connection *) noexcept; + 330| | static PQXX_PRIVATE pqxx::internal::pq::PGconn * + 331| | raw_conn(pqxx::dbtransaction const &) noexcept; + 332| | static PQXX_PRIVATE std::string errmsg(connection const *); + 333| | static PQXX_PRIVATE std::string errmsg(dbtransaction const &tx) + 334| 0| { + 335| 0| return errmsg(&tx.conn()); + 336| 0| } + 337| 0| PQXX_PRIVATE std::string errmsg() const { return errmsg(m_conn); } + 338| | PQXX_PRIVATE std::int64_t seek(std::int64_t offset, int whence); + 339| | std::size_t raw_read(std::byte buf[], std::size_t size); + 340| | void raw_write(std::byte const buf[], std::size_t size); + 341| | + 342| | connection *m_conn = nullptr; + 343| | int m_fd = -1; + 344| |}; + 345| |} // namespace pqxx + 346| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/connection.hxx: + 1| |/* Definition of the connection class. + 2| | * + 3| | * pqxx::connection encapsulates a connection to a database. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/connection instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_CONNECTION + 14| |#define PQXX_H_CONNECTION + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include + 21| |#include + 22| |#include + 23| |#include + 24| |#include + 25| |#include + 26| |#include + 27| |#include + 28| |#include + 29| |#include + 30| | + 31| |// Double-check in order to suppress an overzealous Visual C++ warning (#418). + 32| |#if defined(PQXX_HAVE_CONCEPTS) && __has_include() + 33| |# include + 34| |#endif + 35| | + 36| |#include "pqxx/errorhandler.hxx" + 37| |#include "pqxx/except.hxx" + 38| |#include "pqxx/internal/concat.hxx" + 39| |#include "pqxx/params.hxx" + 40| |#include "pqxx/separated_list.hxx" + 41| |#include "pqxx/strconv.hxx" + 42| |#include "pqxx/types.hxx" + 43| |#include "pqxx/util.hxx" + 44| |#include "pqxx/zview.hxx" + 45| | + 46| | + 47| |/** + 48| | * @addtogroup connections + 49| | * + 50| | * Use of the libpqxx library starts here. + 51| | * + 52| | * Everything that can be done with a database through libpqxx must go through + 53| | * a @ref pqxx::connection object. It connects to a database when you create + 54| | * it, and it terminates that communication during destruction. + 55| | * + 56| | * Many things come together in this class. For example, if you want custom + 57| | * handling of error andwarning messages, you control that in the context of a + 58| | * connection. You also define prepared statements here. For actually + 59| | * executing SQL, however, you'll also need a transaction object which operates + 60| | * "on top of" the connection. (See @ref transactions for more about these.) + 61| | * + 62| | * When you connect to a database, you pass a connection string containing any + 63| | * parameters and options, such as the server address and the database name. + 64| | * + 65| | * These are identical to the ones in libpq, the C language binding upon which + 66| | * libpqxx itself is built: + 67| | * + 68| | * https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING + 69| | * + 70| | * There are also environment variables you can set to provide defaults, again + 71| | * as defined by libpq: + 72| | * + 73| | * https://www.postgresql.org/docs/current/libpq-envars.html + 74| | * + 75| | * You can also create a database connection _asynchronously_ using an + 76| | * intermediate @ref pqxx::connecting object. + 77| | */ + 78| | + 79| |namespace pqxx::internal + 80| |{ + 81| |class sql_cursor; + 82| | + 83| |#if defined(PQXX_HAVE_CONCEPTS) + 84| |/// Concept: T is a range of pairs of zero-terminated strings. + 85| |template + 86| |concept ZKey_ZValues = std::ranges::input_range and requires(T t) { + 87| | { std::cbegin(t) }; + 88| | { std::get<0>(*std::cbegin(t)) } -> ZString; + 89| | { std::get<1>(*std::cbegin(t)) } -> ZString; + 90| |} and std::tuple_size_v::value_type> == 2; + 91| |#endif // PQXX_HAVE_CONCEPTS + 92| | + 93| | + 94| |/// Control OpenSSL/crypto library initialisation. + 95| |/** This is an internal helper. Unless you're working on libpqxx itself, use + 96| | * @ref pqxx::skip_init_ssl instead. + 97| | * + 98| | * @param flags a bitmask of `1 << flag` for each of the `skip_init` flags. + 99| | * + 100| | * Ignores the `skip_init::nothing` flag. + 101| | */ + 102| |void PQXX_COLD PQXX_LIBEXPORT skip_init_ssl(int skips) noexcept; + 103| |} // namespace pqxx::internal + 104| | + 105| | + 106| |namespace pqxx::internal::gate + 107| |{ + 108| |class connection_dbtransaction; + 109| |class connection_errorhandler; + 110| |class connection_largeobject; + 111| |class connection_notification_receiver; + 112| |class connection_pipeline; + 113| |class connection_sql_cursor; + 114| |struct connection_stream_from; + 115| |class connection_stream_to; + 116| |class connection_transaction; + 117| |class const_connection_largeobject; + 118| |} // namespace pqxx::internal::gate + 119| | + 120| | + 121| |namespace pqxx + 122| |{ + 123| |/// An incoming notification. + 124| |/** PostgreSQL extends SQL with a "message bus" using the `LISTEN` and `NOTIFY` + 125| | * commands. In libpqxx you use @ref connection::listen() and (optionally) + 126| | * @ref transaction_base::notify(). + 127| | * + 128| | * When you receive a notification for which you have been listening, your + 129| | * handler receives it in the form of a `notification` object. + 130| | * + 131| | * @warning These structs are meant for extremely short lifespans: the fields + 132| | * reference memory that may become invalid as soon as your handler has been + 133| | * called. + 134| | */ + 135| |struct notification + 136| |{ + 137| | /// The connection which received the notification. + 138| | /** There will be no _backend_ transaction active on the connection when your + 139| | * handler gets called, but there may be a @ref nontransaction. (This is a + 140| | * special transaction type in libpqxx which does not start a transaction on + 141| | * the backend.) + 142| | */ + 143| | connection &conn; + 144| | + 145| | /// Channel name. + 146| | /** The notification logic will only pass the notification to a handler which + 147| | * was registered to listen on this exact name. + 148| | */ + 149| | zview channel; + 150| | + 151| | /// Optional payload text. + 152| | /** If the notification did not carry a payload, the string will be empty. + 153| | */ + 154| | zview payload; + 155| | + 156| | /// Process ID of the backend that sent the notification. + 157| | /** This can be useful in situations where a multiple clients are listening + 158| | * on the same channel, and also send notifications on it. + 159| | * + 160| | * In those situations, it often makes sense for a client to ignore its own + 161| | * incoming notifications, but handle all others on the same channel in some + 162| | * way. + 163| | * + 164| | * To check for that, compare this process ID to the return value of the + 165| | * connection's `backendpid()`. + 166| | */ + 167| | int backend_pid; + 168| |}; + 169| | + 170| | + 171| |/// Flags for skipping initialisation of SSL-related libraries. + 172| |/** When a running process makes its first SSL connection to a database through + 173| | * libpqxx, libpq automatically initialises the OpenSSL and libcrypto + 174| | * libraries. But there are scenarios in which you may want to suppress that. + 175| | * + 176| | * This enum is a way to express this. Pass values of this enum to + 177| | * @ref pqxx::skip_init_ssl as template arguments. + 178| | */ + 179| |enum skip_init : int + 180| |{ + 181| | /// A do-nothing flag that does not affect anything. + 182| | nothing, + 183| | + 184| | /// Skip initialisation of OpenSSL library. + 185| | openssl, + 186| | + 187| | /// Skip initialisation of libcrypto. + 188| | crypto, + 189| |}; + 190| | + 191| | + 192| |/// Control initialisation of OpenSSL and libcrypto libraries. + 193| |/** By default, libpq initialises the openssl and libcrypto libraries when your + 194| | * process first opens an SSL connection to a database. But this may not be + 195| | * what you want: perhaps your application (or some other library it uses) + 196| | * already initialises one or both of these libraries. + 197| | * + 198| | * Call this function to stop libpq from initialising one or the other of + 199| | * these. Pass as arguments each of the `skip_init` flags for which of the + 200| | * libraries whose initialisation you want to prevent. + 201| | * + 202| | * @warning Each call to this function _overwrites_ the effects of any previous + 203| | * call. So if you make one call to skip OpenSSL initialisation, and then + 204| | * another to skip libcrypto initialisation, the first call will do nothing. + 205| | * + 206| | * Examples: + 207| | * * To let libpq initialise libcrypto but not OpenSSL: + 208| | * `skip_init_ssl();` + 209| | * * To let libpq know that it should not initialise either: + 210| | * ```cxx + 211| | * skip_init_ssl(); + 212| | * ``` + 213| | * * To say explicitly that you want libpq to initialise both: + 214| | * `skip_init_ssl();` + 215| | */ + 216| |template inline void skip_init_ssl() noexcept + 217| |{ + 218| | // (Normalise skip flags to one per.) + 219| | pqxx::internal::skip_init_ssl(((1 << SKIP) | ...)); + 220| |} + 221| | + 222| | + 223| |/// Representation of a PostgreSQL table path. + 224| |/** A "table path" consists of a table name, optionally prefixed by a schema + 225| | * name, which in turn is optionally prefixed by a database name. + 226| | * + 227| | * A minimal example of a table path would be `{mytable}`. But a table path + 228| | * may also take the forms `{myschema,mytable}` or + 229| | * `{mydb,myschema,mytable}`. + 230| | */ + 231| |using table_path = std::initializer_list; + 232| | + 233| | + 234| |/// Error verbosity levels. + 235| |enum class error_verbosity : int + 236| |{ + 237| | // These values must match those in libpq's PGVerbosity enum. + 238| | terse = 0, + 239| | normal = 1, + 240| | verbose = 2 + 241| |}; + 242| | + 243| | + 244| |/// Connection to a database. + 245| |/** This is the first class to look at when you wish to work with a database + 246| | * through libpqxx. As per RAII principles, the connection opens during + 247| | * construction, and closes upon destruction. If the connection attempt fails, + 248| | * you will not get a @ref connection object; the constructor will fail with a + 249| | * @ref pqxx::broken_connection exception. + 250| | * + 251| | * When creating a connection, you can pass a connection URI or a postgres + 252| | * connection string, to specify the database server's address, a login + 253| | * username, and so on. If you don't, the connection will try to obtain them + 254| | * from certain environment variables. If those are not set either, the + 255| | * default is to try and connect to the local system's port 5432. + 256| | * + 257| | * Find more about connection strings here: + 258| | * + 259| | * https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING + 260| | * + 261| | * The variables are documented here: + 262| | * + 263| | * https://www.postgresql.org/docs/current/libpq-envars.html + 264| | * + 265| | * To query or manipulate the database once connected, use one of the + 266| | * transaction classes (see pqxx/transaction_base.hxx) and perhaps also the + 267| | * transactor framework (see pqxx/transactor.hxx). + 268| | * + 269| | * When a connection breaks, or fails to establish itself in the first place, + 270| | * you will typically get a @ref broken_connection exception. This can happen + 271| | * at almost any point. + 272| | * + 273| | * @warning On Unix-like systems, including GNU and BSD systems, your program + 274| | * may receive the SIGPIPE signal when the connection to the backend breaks. By + 275| | * default this signal will abort your program. Use "signal(SIGPIPE, SIG_IGN)" + 276| | * if you want your program to continue running after a connection fails. + 277| | */ + 278| |class PQXX_LIBEXPORT connection + 279| |{ + 280| |public: + 281| 0| connection() : connection{""} {} + 282| | + 283| | /// Connect to a database, using `options` string. + 284| | explicit connection(char const options[]) + 285| 0| { + 286| 0| check_version(); + 287| 0| init(options); + 288| 0| } + 289| | + 290| | /// Connect to a database, using `options` string. + 291| | explicit connection(zview options) : connection{options.c_str()} + 292| 0| { + 293| | // (Delegates to other constructor which calls check_version for us.) + 294| 0| } + ------------------ + | Unexecuted instantiation: _ZN4pqxx10connectionC1ENS_5zviewE + ------------------ + | Unexecuted instantiation: _ZN4pqxx10connectionC2ENS_5zviewE + ------------------ + 295| | + 296| | /// Move constructor. + 297| | /** Moving a connection is not allowed if it has an open transaction, or has + 298| | * error handlers or is listening for notifications. In those situations, + 299| | * other objects may hold references to the old object which would become + 300| | * invalid and might produce hard-to-diagnose bugs. + 301| | */ + 302| | connection(connection &&rhs); + 303| | + 304| |#if defined(PQXX_HAVE_CONCEPTS) + 305| | /// Connect to a database, passing options as a range of key/value pairs. + 306| | /** @warning Experimental. Requires C++20 "concepts" support. Define + 307| | * `PQXX_HAVE_CONCEPTS` to enable it. + 308| | * + 309| | * There's no need to escape the parameter values. + 310| | * + 311| | * See the PostgreSQL libpq documentation for the full list of possible + 312| | * options: + 313| | * + 314| | * https://postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS + 315| | * + 316| | * The options can be anything that can be iterated as a series of pairs of + 317| | * zero-terminated strings: `std::pair`, or + 318| | * `std::tuple`, or + 319| | * `std::map`, and so on. + 320| | */ + 321| | template + 322| | inline connection(MAPPING const ¶ms); + 323| |#endif // PQXX_HAVE_CONCEPTS + 324| | + 325| | ~connection() + 326| 0| { + 327| 0| try + 328| 0| { + 329| 0| close(); + 330| 0| } + 331| 0| catch (std::exception const &) + 332| 0| {} + 333| 0| } + 334| | + 335| | // TODO: Once we drop notification_receiver/errorhandler, move is easier. + 336| | /// Move assignment. + 337| | /** Neither connection can have an open transaction, `errorhandler`, or + 338| | * `notification_receiver`. + 339| | */ + 340| | connection &operator=(connection &&rhs); + 341| | + 342| | connection(connection const &) = delete; + 343| | connection &operator=(connection const &) = delete; + 344| | + 345| | /// Is this connection open at the moment? + 346| | /** @warning Most code does **not** need this function. Resist the + 347| | * temptation to check your connection after opening it: if the connection + 348| | * attempt failed, the constructor will never even return, throwing a + 349| | * @ref broken_connection exception instead. + 350| | */ + 351| | [[nodiscard]] bool PQXX_PURE is_open() const noexcept; + 352| | + 353| | /// Invoke notice processor function. The message should end in newline. + 354| | void process_notice(char const[]) noexcept; + 355| | /// Invoke notice processor function. Newline at end is recommended. + 356| | /** The zview variant, with a message ending in newline, is the most + 357| | * efficient way to call process_notice. + 358| | */ + 359| | void process_notice(zview) noexcept; + 360| | + 361| | /// Enable tracing to a given output stream, or nullptr to disable. + 362| | void trace(std::FILE *) noexcept; + 363| | + 364| | /** + 365| | * @name Connection properties + 366| | * + 367| | * These are probably not of great interest, since most are derived from + 368| | * information supplied by the client program itself, but they are included + 369| | * for completeness. + 370| | * + 371| | * The connection needs to be currently active for these to work. + 372| | */ + 373| | //@{ + 374| | /// Name of the database to which we're connected, if any. + 375| | /** Returns nullptr when not connected. */ + 376| | [[nodiscard]] char const *dbname() const; + 377| | + 378| | /// Database user ID under which we are connected, if any. + 379| | /** Returns nullptr when not connected. */ + 380| | [[nodiscard]] char const *username() const; + 381| | + 382| | /// Database server address, if given. + 383| | /** This may be an IP address, or a hostname, or (for a Unix domain socket) + 384| | * a socket path. Returns nullptr when not connected. + 385| | */ + 386| | [[nodiscard]] char const *hostname() const; + 387| | + 388| | /// Server port number on which we are connected to the database. + 389| | [[nodiscard]] char const *port() const; + 390| | + 391| | /// Process ID for backend process, or 0 if inactive. + 392| | [[nodiscard]] int PQXX_PURE backendpid() const & noexcept; + 393| | + 394| | /// Socket currently used for connection, or -1 for none. + 395| | /** Query the current socket number. This is intended for event loops based + 396| | * on functions such as select() or poll(), where you're waiting for any of + 397| | * multiple file descriptors to become ready for communication. + 398| | * + 399| | * Please try to stay away from this function. It is really only meant for + 400| | * event loops that need to wait on more than one file descriptor. If all + 401| | * you need is to block until a notification arrives, for instance, use + 402| | * await_notification(). If you want to issue queries and retrieve results + 403| | * in nonblocking fashion, check out the pipeline class. + 404| | */ + 405| | [[nodiscard]] int PQXX_PURE sock() const & noexcept; + 406| | + 407| | /// What version of the PostgreSQL protocol is this connection using? + 408| | /** The answer can be 0 (when there is no connection); 3 for protocol 3.0; or + 409| | * possibly higher values as newer protocol versions come into use. + 410| | */ + 411| | [[nodiscard]] int PQXX_PURE protocol_version() const noexcept; + 412| | + 413| | /// What version of the PostgreSQL server are we connected to? + 414| | /** The result is a bit complicated: each of the major, medium, and minor + 415| | * release numbers is written as a two-digit decimal number, and the three + 416| | * are then concatenated. Thus server version 9.4.2 will be returned as the + 417| | * decimal number 90402. If there is no connection to the server, this + 418| | * returns zero. + 419| | * + 420| | * @warning When writing version numbers in your code, don't add zero at the + 421| | * beginning! Numbers beginning with zero are interpreted as octal (base-8) + 422| | * in C++. Thus, 070402 is not the same as 70402, and 080000 is not a number + 423| | * at all because there is no digit "8" in octal notation. Use strictly + 424| | * decimal notation when it comes to these version numbers. + 425| | */ + 426| | [[nodiscard]] int PQXX_PURE server_version() const noexcept; + 427| | //@} + 428| | + 429| | /// @name Text encoding + 430| | /** + 431| | * Each connection is governed by a "client encoding," which dictates how + 432| | * strings and other text is represented in bytes. The database server will + 433| | * send text data to you in this encoding, and you should use it for the + 434| | * queries and data which you send to the server. + 435| | * + 436| | * Search the PostgreSQL documentation for "character set encodings" to find + 437| | * out more about the available encodings, how to extend them, and how to use + 438| | * them. Not all server-side encodings are compatible with all client-side + 439| | * encodings or vice versa. + 440| | * + 441| | * Encoding names are case-insensitive, so e.g. "UTF8" is equivalent to + 442| | * "utf8". + 443| | * + 444| | * You can change the client encoding, but this may not work when the + 445| | * connection is in a special state, such as when streaming a table. It's + 446| | * not clear what happens if you change the encoding during a transaction, + 447| | * and then abort the transaction. + 448| | */ + 449| | //@{ + 450| | /// Get client-side character encoding, by name. + 451| | [[nodiscard]] std::string get_client_encoding() const; + 452| | + 453| | /// Set client-side character encoding, by name. + 454| | /** + 455| | * @param encoding Name of the character set encoding to use. + 456| | */ + 457| | void set_client_encoding(zview encoding) & + 458| 0| { + 459| 0| set_client_encoding(encoding.c_str()); + 460| 0| } + 461| | + 462| | /// Set client-side character encoding, by name. + 463| | /** + 464| | * @param encoding Name of the character set encoding to use. + 465| | */ + 466| | void set_client_encoding(char const encoding[]) &; + 467| | + 468| | /// Get the connection's encoding, as a PostgreSQL-defined code. + 469| | [[nodiscard]] int encoding_id() const; + 470| | + 471| | //@} + 472| | + 473| | /// Set one of the session variables to a new value. + 474| | /** This executes SQL, so do not do it while a pipeline or stream is active + 475| | * on the connection. + 476| | * + 477| | * The value you set here will last for the rest of the connection's + 478| | * duration, or until you set a new value. + 479| | * + 480| | * If you set the value while in a @ref dbtransaction (i.e. any transaction + 481| | * that is not a @ref nontransaction), then rolling back the transaction will + 482| | * undo the change. + 483| | * + 484| | * All applies to setting _session_ variables. You can also set the same + 485| | * variables as _local_ variables, in which case they will always revert to + 486| | * their previous value when the transaction ends (or when you overwrite them + 487| | * of course). To set a local variable, simply execute an SQL statement + 488| | * along the lines of "`SET LOCAL var = 'value'`" inside your transaction. + 489| | * + 490| | * @param var The variable to set. + 491| | * @param value The new value for the variable. + 492| | * @throw @ref variable_set_to_null if the value is null; this is not + 493| | * allowed. + 494| | */ + 495| | template + 496| | void set_session_var(std::string_view var, TYPE const &value) & + 497| | { + 498| | if constexpr (nullness::has_null) + 499| | { + 500| | if (nullness::is_null(value)) + 501| | throw variable_set_to_null{ + 502| | internal::concat("Attempted to set variable ", var, " to null.")}; + 503| | } + 504| | exec(internal::concat("SET ", quote_name(var), "=", quote(value))); + 505| | } + 506| | + 507| | /// Read currently applicable value of a variable. + 508| | /** This function executes an SQL statement, so it won't work while a + 509| | * @ref pipeline or query stream is active on the connection. + 510| | * + 511| | * @return a blank `std::optional` if the variable's value is null, or its + 512| | * string value otherwise. + 513| | */ + 514| | std::string get_var(std::string_view var); + 515| | + 516| | /// Read currently applicable value of a variable. + 517| | /** This function executes an SQL statement, so it won't work while a + 518| | * @ref pipeline or query stream is active on the connection. + 519| | * + 520| | * If there is any possibility that the variable is null, ensure that `TYPE` + 521| | * can represent null values. + 522| | */ + 523| | template TYPE get_var_as(std::string_view var) + 524| | { + 525| | return from_string(get_var(var)); + 526| | } + 527| | + 528| | /** + 529| | * @name Notifications and Receivers + 530| | * + 531| | * This is PostgreSQL-specific extension that goes beyond standard SQL. It's + 532| | * a communications mechanism between clients on a database, akin to a + 533| | * transactional message bus. + 534| | * + 535| | * A notification happens on a _channel,_ identified by a name. You can set + 536| | * a connection to _listen_ for notifications on the channel, using the + 537| | * connection's @ref listen() function. (Internally this will issue a + 538| | * `LISTEN` SQL command). Any client on the database can send a + 539| | * notification on that channel by executing a `NOTIFY` SQL command. The + 540| | * transaction classes implement a convenience function for this, called + 541| | * @ref transaction_base::notify(). + 542| | * + 543| | * Notifications can carry an optional _payload_ string. This is free-form + 544| | * text which carries additional information to the receiver. + 545| | * + 546| | * @warning There are a few pitfalls with the channel names: case sensitivity + 547| | * and encodings. They are not too hard to avoid, but the safest thing to do + 548| | * is use only lower-case ASCII names. + 549| | * + 550| | * + 551| | * ### Case sensitivity + 552| | * + 553| | * Channel names are _case-sensitive._ By default, however, PostgreSQL does + 554| | * convert the channel name in a `NOTIFY` or `LISTEN` command to lower-case, + 555| | * to give the impression that it is _not_ case-sensitive while keeping the + 556| | * performance cost low. + 557| | * + 558| | * Thus, a `LISTEN Hello` will pick up a notification from `NOTIFY Hello` but + 559| | * also one from `NOTIFY hello`, because the database converts `Hello` into + 560| | * `hello` going in either direction. + 561| | * + 562| | * You can prevent this conversion by putting the name in double quotes, as + 563| | * @ref quote_name() does. This is what libpqxx's notification functions do. + 564| | * If you use libpqxx to lisen on `Hello` but raw SQL to notify `Hello`, the + 565| | * notification will not arrive because the notification actually uses the + 566| | * string `hello` instead. + 567| | * + 568| | * Confused? Safest thing to do is to use only lower-case letters in the + 569| | * channel names! + 570| | * + 571| | * + 572| | * ### Transactions + 573| | * + 574| | * Both listening and notifying are _transactional_ in the backend: they + 575| | * only take effect once the back-end transaction in which you do them is + 576| | * committed. + 577| | * + 578| | * For an outgoing notification, this means that the transaction holds on to + 579| | * the outgoing message until you commit. (A @ref nontransaction does not + 580| | * start a backend transaction, so if that's the transaction type you're + 581| | * using, the message does go out immediately.) + 582| | * + 583| | * For listening to incoming notifications, it gets a bit more complicated. + 584| | * To avoid complicating its internal bookkeeping, libpqxx only lets you + 585| | * start listening while no transaction is open. + 586| | * + 587| | * No notifications will come in while you're in a transaction... again + 588| | * unless it's a @ref nontransaction of course, because that does not open a + 589| | * transaction on the backend. + 590| | * + 591| | * + 592| | * ### Exceptions + 593| | * + 594| | * If your handler throws an exception, that will simply propagate up the + 595| | * call chain to wherever you were when you received it. + 596| | * + 597| | * This is differnt from the old `notification_receiver` mechanism which + 598| | * logged exceptions but did not propagate them. + 599| | * + 600| | * + 601| | * ### Encoding + 602| | * + 603| | * When a client sends a notification, it does so in its client encoding. If + 604| | * necessary, the back-end converts them to its internal encoding. And then + 605| | * when a client receives the notification, the database converts it to the + 606| | * receiver's client encoding. + 607| | * + 608| | * Simple enough, right? + 609| | * + 610| | * However if you should _change_ your connection's client encoding after you + 611| | * start listening on a channel, then any notifications you receive may have + 612| | * different channel names than the ones for which you are listening. + 613| | * + 614| | * If this could be a problem in your scenario, stick to names in pure + 615| | * ASCII. Those will look the same in all the encodings postgres supports. + 616| | */ + 617| | //@{ + 618| | /// Check for pending notifications and take appropriate action. + 619| | /** This does not block. To wait for incoming notifications, either call + 620| | * @ref await_notification() (it calls this function); or wait for incoming + 621| | * data on the connection's socket (i.e. wait to read), and then call this + 622| | * function repeatedly until it returns zero. After that, there are no more + 623| | * pending notifications so you may want to wait again, or move on and do + 624| | * other work. + 625| | * + 626| | * If any notifications are pending when you call this function, it + 627| | * processes them by checking for a matching notification handler, and if it + 628| | * finds one, invoking it. If there is no matching handler, nothing happens. + 629| | * + 630| | * If your notifcation handler throws an exception, `get_notifs()` will just + 631| | * propagate it back to you. (This is different from the old + 632| | * `notification_receiver` mechanism, which would merely log them.) + 633| | * + 634| | * @return Number of notifications processed. + 635| | */ + 636| | int get_notifs(); + 637| | + 638| | /// Wait for a notification to come in. + 639| | /** There are other events that will also cancel the wait, such as the + 640| | * backend failing. Also, _the function will wake up by itself from time to + 641| | * time._ Your code must be ready to handle this; don't assume after waking + 642| | * up that there will always be a pending notifiation. + 643| | * + 644| | * If a notification comes in, the call to this function will process it, + 645| | * along with any other notifications that may have been pending. + 646| | * + 647| | * To wait for notifications into your own event loop instead, wait until + 648| | * there is incoming data on the connection's socket to be read, then call + 649| | * @ref get_notifs() repeatedly until it returns zero. + 650| | * + 651| | * @return Number of notifications processed. + 652| | */ + 653| | int await_notification(); + 654| | + 655| | /// Wait for a notification to come in, or for given timeout to pass. + 656| | /** There are other events that will also cancel the wait, such as the + 657| | * backend failing, some kinds of signal coming in, or timeout expiring. + 658| | * + 659| | * If a notification comes in, the call will process it, along with any other + 660| | * notifications that may have been pending. + 661| | * + 662| | * To wait for notifications into your own event loop instead, wait until + 663| | * there is incoming data on the connection's socket to be read, then call + 664| | * @ref get_notifs repeatedly until it returns zero. + 665| | * + 666| | * If your notifcation handler throws an exception, `get_notifs()` will just + 667| | * propagate it back to you. (This is different from the old + 668| | * `notification_receiver` mechanism, which would merely log them.) + 669| | * + 670| | * @return Number of notifications processed. + 671| | */ + 672| | int await_notification(std::time_t seconds, long microseconds = 0); + 673| | + 674| | /// A handler callback for incoming notifications on a given channel. + 675| | /** Your callback must accept a @ref notification object. This object can + 676| | * and will exist only for the duration of the handling of that one incoming + 677| | * notification. + 678| | * + 679| | * The handler can be "empty," i.e. contain no code. Setting an empty + 680| | * handler on a channel disables listening on that channel. + 681| | */ + 682| | using notification_handler = std::function; + 683| | + 684| | /// Attach a handler to a notification channel. + 685| | /** Issues a `LISTEN` SQL command for channel `channel`, and stores `handler` + 686| | * as the callback for when a notification comes in on that channel. + 687| | * + 688| | * The handler is a `std::function` (see @ref notification_handler), but you + 689| | * can simply pass in a lambda with the right parameters, or a function, or + 690| | * an object of a type you define that happens to implemnt the right function + 691| | * call operator. + 692| | * + 693| | * Your handler probably needs to interact with your application's data; the + 694| | * simple way to get that working is to pass a lambda with a closure + 695| | * referencing the data items you need. + 696| | * + 697| | * If the handler is empty (the default), then that stops the connection + 698| | * listening on the channel. It cancels your subscription, so to speak. + 699| | * You can do that as many times as you like, even when you never started + 700| | * listening to that channel in the first place. + 701| | * + 702| | * A connection can only have one handler per channel, so if you register two + 703| | * different handlers on the same channel, then the second overwrites the + 704| | * first. + 705| | */ + 706| | void listen(std::string_view channel, notification_handler handler = {}); + 707| | + 708| | //@} + 709| | + 710| | /** + 711| | * @name Password encryption + 712| | * + 713| | * Use this when setting a new password for the user if password encryption + 714| | * is enabled. Inputs are the SQL name for the user for whom you with to + 715| | * encrypt a password; the plaintext password; and the hash algorithm. + 716| | * + 717| | * The algorithm must be one of "md5", "scram-sha-256" (introduced in + 718| | * PostgreSQL 10), or `nullptr`. If the pointer is null, this will query + 719| | * the `password_encryption setting` from the server, and use the default + 720| | * algorithm as defined there. + 721| | * + 722| | * @return encrypted version of the password, suitable for encrypted + 723| | * PostgreSQL authentication. + 724| | * + 725| | * Thus you can change a user's password with: + 726| | * ```cxx + 727| | * void setpw(transaction_base &t, string const &user, string const &pw) + 728| | * { + 729| | * t.exec0("ALTER USER " + user + " " + 730| | * "PASSWORD '" + t.conn().encrypt_password(user,pw) + "'"); + 731| | * } + 732| | * ``` + 733| | * + 734| | * When building this against a libpq older than version 10, this will use + 735| | * an older function which only supports md5. In that case, requesting a + 736| | * different algorithm than md5 will result in a @ref feature_not_supported + 737| | * exception. + 738| | */ + 739| | //@{ + 740| | /// Encrypt a password for a given user. + 741| | [[nodiscard]] std::string + 742| | encrypt_password(zview user, zview password, zview algorithm) + 743| 0| { + 744| 0| return encrypt_password(user.c_str(), password.c_str(), algorithm.c_str()); + 745| 0| } + 746| | /// Encrypt a password for a given user. + 747| | [[nodiscard]] std::string encrypt_password( + 748| | char const user[], char const password[], char const *algorithm = nullptr); + 749| | //@} + 750| | + 751| | /** + 752| | * @name Prepared statements + 753| | * + 754| | * PostgreSQL supports prepared SQL statements, i.e. statements that you can + 755| | * register under a name you choose, optimized once by the backend, and + 756| | * executed any number of times under the given name. + 757| | * + 758| | * Prepared statement definitions are not sensitive to transaction + 759| | * boundaries. A statement defined inside a transaction will remain defined + 760| | * outside that transaction, even if the transaction itself is subsequently + 761| | * aborted. Once a statement has been prepared, it will only go away if you + 762| | * close the connection or explicitly "unprepare" the statement. + 763| | * + 764| | * Use the `pqxx::transaction_base::exec_prepared` functions to execute a + 765| | * prepared statement. See @ref prepared for a full discussion. + 766| | * + 767| | * @warning Using prepared statements can save time, but if your statement + 768| | * takes parameters, it may also make your application significantly slower! + 769| | * The reason is that the server works out a plan for executing the query + 770| | * when you prepare it. At that time, of course it does not know the values + 771| | * for the parameters that you will pass. If you execute a query without + 772| | * preparing it, then the server works out the plan on the spot, with full + 773| | * knowledge of the parameter values. + 774| | * + 775| | * A statement's definition can refer to its parameters as `$1`, `$2`, etc. + 776| | * The first parameter you pass to the call provides a value for `$1`, and + 777| | * so on. + 778| | * + 779| | * Here's an example of how to use prepared statements. + 780| | * + 781| | * ```cxx + 782| | * using namespace pqxx; + 783| | * void foo(connection &c) + 784| | * { + 785| | * c.prepare("findtable", "select * from pg_tables where name=$1"); + 786| | * work tx{c}; + 787| | * result r = tx.exec_prepared("findtable", "mytable"); + 788| | * if (std::empty(r)) throw runtime_error{"mytable not found!"}; + 789| | * } + 790| | * ``` + 791| | */ + 792| | //@{ + 793| | + 794| | /// Define a prepared statement. + 795| | /** + 796| | * @param name unique name for the new prepared statement. + 797| | * @param definition SQL statement to prepare. + 798| | */ + 799| | void prepare(zview name, zview definition) & + 800| 0| { + 801| 0| prepare(name.c_str(), definition.c_str()); + 802| 0| } + 803| | + 804| | /** + 805| | * @param name unique name for the new prepared statement. + 806| | * @param definition SQL statement to prepare. + 807| | */ + 808| | void prepare(char const name[], char const definition[]) &; + 809| | + 810| | /// Define a nameless prepared statement. + 811| | /** + 812| | * This can be useful if you merely want to pass large binary parameters to a + 813| | * statement without otherwise wishing to prepare it. If you use this + 814| | * feature, always keep the definition and the use close together to avoid + 815| | * the nameless statement being redefined unexpectedly by code somewhere + 816| | * else. + 817| | */ + 818| | void prepare(char const definition[]) &; + 819| 0| void prepare(zview definition) & { return prepare(definition.c_str()); } + 820| | + 821| | /// Drop prepared statement. + 822| | void unprepare(std::string_view name); + 823| | + 824| | //@} + 825| | + 826| | // C++20: constexpr. Breaks ABI. + 827| | /// Suffix unique number to name to make it unique within session context. + 828| | /** Used internally to generate identifiers for SQL objects (such as cursors + 829| | * and nested transactions) based on a given human-readable base name. + 830| | */ + 831| | [[nodiscard]] std::string adorn_name(std::string_view); + 832| | + 833| | /** + 834| | * @defgroup escaping-functions String-escaping functions + 835| | */ + 836| | //@{ + 837| | + 838| | /// Escape string for use as SQL string literal on this connection. + 839| | [[nodiscard]] std::string esc(char const text[]) const + 840| 0| { + 841| 0| return esc(std::string_view{text}); + 842| 0| } + 843| | + 844| |#if defined(PQXX_HAVE_SPAN) + 845| | /// Escape string for use as SQL string literal, into `buffer`. + 846| | /** Use this variant when you want to re-use the same buffer across multiple + 847| | * calls. If that's not the case, or convenience and simplicity are more + 848| | * important, use the single-argument variant. + 849| | * + 850| | * For every byte in `text`, there must be at least 2 bytes of space in + 851| | * `buffer`; plus there must be one byte of space for a trailing zero. + 852| | * Throws @ref range_error if this space is not available. + 853| | * + 854| | * Returns a reference to the escaped string, which is actually stored in + 855| | * `buffer`. + 856| | */ + 857| | [[nodiscard]] std::string_view + 858| | esc(std::string_view text, std::span buffer) + 859| 0| { + 860| 0| auto const size{std::size(text)}, space{std::size(buffer)}; + 861| 0| auto const needed{2 * size + 1}; + 862| 0| if (space < needed) + 863| 0| throw range_error{internal::concat( + 864| 0| "Not enough room to escape string of ", size, " byte(s): need ", + 865| 0| needed, " bytes of buffer space, but buffer size is ", space, ".")}; + 866| 0| auto const data{buffer.data()}; + 867| 0| return {data, esc_to_buf(text, data)}; + 868| 0| } + 869| |#endif + 870| | + 871| | /// Escape string for use as SQL string literal on this connection. + 872| | /** @warning This is meant for text strings only. It cannot contain bytes + 873| | * whose value is zero ("nul bytes"). + 874| | */ + 875| | [[nodiscard]] std::string esc(std::string_view text) const; + 876| | + 877| |#if defined(PQXX_HAVE_CONCEPTS) + 878| | /// Escape binary string for use as SQL string literal on this connection. + 879| | /** This is identical to `esc_raw(data)`. */ + 880| | template [[nodiscard]] std::string esc(DATA const &data) const + 881| | { + 882| | return esc_raw(data); + 883| | } + 884| |#endif + 885| | + 886| |#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN) + 887| | /// Escape binary string for use as SQL string literal, into `buffer`. + 888| | /** Use this variant when you want to re-use the same buffer across multiple + 889| | * calls. If that's not the case, or convenience and simplicity are more + 890| | * important, use the single-argument variant. + 891| | * + 892| | * For every byte in `data`, there must be at least two bytes of space in + 893| | * `buffer`; plus there must be two bytes of space for a header and one for + 894| | * a trailing zero. Throws @ref range_error if this space is not available. + 895| | * + 896| | * Returns a reference to the escaped string, which is actually stored in + 897| | * `buffer`. + 898| | */ + 899| | template + 900| | [[nodiscard]] zview esc(DATA const &data, std::span buffer) const + 901| | { + 902| | auto const size{std::size(data)}, space{std::size(buffer)}; + 903| | auto const needed{internal::size_esc_bin(std::size(data))}; + 904| | if (space < needed) + 905| | throw range_error{internal::concat( + 906| | "Not enough room to escape binary string of ", size, " byte(s): need ", + 907| | needed, " bytes of buffer space, but buffer size is ", space, ".")}; + 908| | + 909| | bytes_view view{std::data(data), std::size(data)}; + 910| | auto const out{std::data(buffer)}; + 911| | // Actually, in the modern format, we know beforehand exactly how many + 912| | // bytes we're going to fill. Just leave out the trailing zero. + 913| | internal::esc_bin(view, out); + 914| | return zview{out, needed - 1}; + 915| | } + 916| |#endif + 917| | + 918| | /// Escape binary string for use as SQL string literal on this connection. + 919| | [[deprecated("Use std::byte for binary data.")]] std::string + 920| | esc_raw(unsigned char const bin[], std::size_t len) const; + 921| | + 922| | /// Escape binary string for use as SQL string literal on this connection. + 923| | /** You can also just use @ref esc with a binary string. */ + 924| | [[nodiscard]] std::string esc_raw(bytes_view) const; + 925| | + 926| |#if defined(PQXX_HAVE_SPAN) + 927| | /// Escape binary string for use as SQL string literal, into `buffer`. + 928| | /** You can also just use @ref esc with a binary string. */ + 929| | [[nodiscard]] std::string esc_raw(bytes_view, std::span buffer) const; + 930| |#endif + 931| | + 932| |#if defined(PQXX_HAVE_CONCEPTS) + 933| | /// Escape binary string for use as SQL string literal on this connection. + 934| | /** You can also just use @ref esc with a binary string. */ + 935| | template + 936| | [[nodiscard]] std::string esc_raw(DATA const &data) const + 937| | { + 938| | return esc_raw(bytes_view{std::data(data), std::size(data)}); + 939| | } + 940| |#endif + 941| | + 942| |#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN) + 943| | /// Escape binary string for use as SQL string literal, into `buffer`. + 944| | template + 945| | [[nodiscard]] zview esc_raw(DATA const &data, std::span buffer) const + 946| | { + 947| | return this->esc(binary_cast(data), buffer); + 948| | } + 949| |#endif + 950| | + 951| | // TODO: Make "into buffer" variant to eliminate a string allocation. + 952| | /// Unescape binary data, e.g. from a `bytea` field. + 953| | /** Takes a binary string as escaped by PostgreSQL, and returns a restored + 954| | * copy of the original binary data. + 955| | * + 956| | * (The data must be encoded in PostgreSQL's "hex" format. The legacy + 957| | * "bytea" escape format, used prior to PostgreSQL 9.0, is no longer + 958| | * supported.) + 959| | */ + 960| | [[nodiscard]] bytes unesc_bin(std::string_view text) const + 961| 0| { + 962| 0| bytes buf; + 963| 0| buf.resize(pqxx::internal::size_unesc_bin(std::size(text))); + 964| 0| pqxx::internal::unesc_bin(text, buf.data()); + 965| 0| return buf; + 966| 0| } + 967| | + 968| | /// Escape and quote a string of binary data. + 969| | std::string quote_raw(bytes_view) const; + 970| | + 971| |#if defined(PQXX_HAVE_CONCEPTS) + 972| | /// Escape and quote a string of binary data. + 973| | /** You can also just use @ref quote with binary data. */ + 974| | template + 975| | [[nodiscard]] std::string quote_raw(DATA const &data) const + 976| | { + 977| | return quote_raw(bytes_view{std::data(data), std::size(data)}); + 978| | } + 979| |#endif + 980| | + 981| | // TODO: Make "into buffer" variant to eliminate a string allocation. + 982| | /// Escape and quote an SQL identifier for use in a query. + 983| | [[nodiscard]] std::string quote_name(std::string_view identifier) const; + 984| | + 985| | // TODO: Make "into buffer" variant to eliminate a string allocation. + 986| | /// Escape and quote a table name. + 987| | /** When passing just a table name, this is just another name for + 988| | * @ref quote_name. + 989| | */ + 990| | [[nodiscard]] std::string quote_table(std::string_view name) const; + 991| | + 992| | // TODO: Make "into buffer" variant to eliminate a string allocation. + 993| | /// Escape and quote a table path. + 994| | /** A table path consists of a table name, optionally prefixed by a schema + 995| | * name; and if both are given, they are in turn optionally prefixed by a + 996| | * database name. + 997| | * + 998| | * Each portion of the path (database name, schema name, table name) will be + 999| | * quoted separately, and they will be joined together by dots. So for + 1000| | * example, `myschema.mytable` will become `"myschema"."mytable"`. + 1001| | */ + 1002| | [[nodiscard]] std::string quote_table(table_path) const; + 1003| | + 1004| | // TODO: Make "into buffer" variant to eliminate a string allocation. + 1005| | /// Quote and comma-separate a series of column names. + 1006| | /** Use this to save a bit of work in cases where you repeatedly need to pass + 1007| | * the same list of column names, e.g. with @ref stream_to and @ref + 1008| | * stream_from. Some functions that need to quote the columns list + 1009| | * internally, will have a "raw" alternative which let you do the quoting + 1010| | * yourself. It's a bit of extra work, but it can in rare cases let you + 1011| | * eliminate some duplicate work in quoting them repeatedly. + 1012| | */ + 1013| | template + 1014| | inline std::string quote_columns(STRINGS const &columns) const; + 1015| | + 1016| | // TODO: Make "into buffer" variant to eliminate a string allocation. + 1017| | /// Represent object as SQL string, including quoting & escaping. + 1018| | /** + 1019| | * Recognises nulls and represents them as SQL nulls. They get no quotes. + 1020| | */ + 1021| | template + 1022| | [[nodiscard]] inline std::string quote(T const &t) const; + 1023| | + 1024| | [[deprecated("Use std::byte for binary data.")]] std::string + 1025| | quote(binarystring const &) const; + 1026| | + 1027| | // TODO: Make "into buffer" variant to eliminate a string allocation. + 1028| | /// Escape and quote binary data for use as a BYTEA value in SQL statement. + 1029| | [[nodiscard]] std::string quote(bytes_view bytes) const; + 1030| | + 1031| | // TODO: Make "into buffer" variant to eliminate a string allocation. + 1032| | /// Escape string for literal LIKE match. + 1033| | /** Use this when part of an SQL "LIKE" pattern should match only as a + 1034| | * literal string, not as a pattern, even if it contains "%" or "_" + 1035| | * characters that would normally act as wildcards. + 1036| | * + 1037| | * The string does not get string-escaped or quoted. You do that later. + 1038| | * + 1039| | * For instance, let's say you have a string `name` entered by the user, + 1040| | * and you're searching a `file` column for items that match `name` + 1041| | * followed by a dot and three letters. Even if `name` contains wildcard + 1042| | * characters "%" or "_", you only want those to match literally, so "_" + 1043| | * only matches "_" and "%" only matches a single "%". + 1044| | * + 1045| | * You do that by "like-escaping" `name`, appending the wildcard pattern + 1046| | * `".___"`, and finally, escaping and quoting the result for inclusion in + 1047| | * your query: + 1048| | * + 1049| | * ```cxx + 1050| | * tx.exec( + 1051| | * "SELECT file FROM item WHERE file LIKE " + + 1052| | * tx.quote(tx.esc_like(name) + ".___")); + 1053| | * ``` + 1054| | * + 1055| | * The SQL "LIKE" operator also lets you choose your own escape character. + 1056| | * This is supported, but must be a single-byte character. + 1057| | */ + 1058| | [[nodiscard]] std::string + 1059| | esc_like(std::string_view text, char escape_char = '\\') const; + 1060| | + 1061| | /// Escape string for use as SQL string literal on this connection. + 1062| | /** @warning This accepts a length, and it does not require a terminating + 1063| | * zero byte. But if there is a zero byte, escaping stops there even if + 1064| | * it's not at the end of the string! + 1065| | */ + 1066| | [[deprecated("Use std::string_view or pqxx:zview.")]] std::string + 1067| | esc(char const text[], std::size_t maxlen) const + 1068| 0| { + 1069| 0| return esc(std::string_view{text, maxlen}); + 1070| 0| } + 1071| | + 1072| | /// Unescape binary data, e.g. from a `bytea` field. + 1073| | /** Takes a binary string as escaped by PostgreSQL, and returns a restored + 1074| | * copy of the original binary data. + 1075| | */ + 1076| | [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string + 1077| | unesc_raw(zview text) const + 1078| 0| { + 1079| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 1080| 0| return unesc_raw(text.c_str()); + 1081| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 1082| 0| } + 1083| | + 1084| | /// Unescape binary data, e.g. from a `bytea` field. + 1085| | /** Takes a binary string as escaped by PostgreSQL, and returns a restored + 1086| | * copy of the original binary data. + 1087| | */ + 1088| | [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string + 1089| | unesc_raw(char const text[]) const; + 1090| | + 1091| | /// Escape and quote a string of binary data. + 1092| | [[deprecated("Use quote(bytes_view).")]] std::string + 1093| | quote_raw(unsigned char const bin[], std::size_t len) const; + 1094| | //@} + 1095| | + 1096| | /// Attempt to cancel the ongoing query, if any. + 1097| | /** You can use this from another thread, and/or while a query is executing + 1098| | * in a pipeline, but it's up to you to ensure that you're not canceling the + 1099| | * wrong query. This may involve locking. + 1100| | */ + 1101| | void cancel_query(); + 1102| | + 1103| |#if defined(_WIN32) || __has_include() + 1104| | /// Set socket to blocking (true) or nonblocking (false). + 1105| | /** @warning Do not use this unless you _really_ know what you're doing. + 1106| | * @warning This function is available on most systems, but not necessarily + 1107| | * all. + 1108| | */ + 1109| | void set_blocking(bool block) &; + 1110| |#endif // defined(_WIN32) || __has_include() + 1111| | + 1112| | /// Set session verbosity. + 1113| | /** Set the verbosity of error messages to "terse", "normal" (the default), + 1114| | * or "verbose." + 1115| | * + 1116| | * This affects the notices that the `connection` and its `result` objects + 1117| | * will pass to your notice handler. + 1118| | * + 1119| | * If "terse", returned messages include severity, primary text, and + 1120| | * position only; this will normally fit on a single line. "normal" produces + 1121| | * messages that include the above plus any detail, hint, or context fields + 1122| | * (these might span multiple lines). "verbose" includes all available + 1123| | * fields. + 1124| | */ + 1125| | void set_verbosity(error_verbosity verbosity) & noexcept; + 1126| | + 1127| | // C++20: Use std::callable. + 1128| | + 1129| | /// Set a notice handler to the connection. + 1130| | /** When a notice comes in (a warning or error message), the connection or + 1131| | * result object on which it happens will call the notice handler, passing + 1132| | * the message as its argument. + 1133| | * + 1134| | * The handler must not throw any exceptions. If it does, the program will + 1135| | * terminate. + 1136| | * + 1137| | * @warning It's not just the `connection` that can call a notice handler, + 1138| | * but any of the `result` objects that it produces as well. So, be prepared + 1139| | * for the possibility that the handler may still receive a call after the + 1140| | * connection has been closed. + 1141| | */ + 1142| | void set_notice_handler(std::function handler) + 1143| 0| { + 1144| 0| m_notice_waiters->notice_handler = std::move(handler); + 1145| 0| } + 1146| | + 1147| | /// @deprecated Return pointers to the active errorhandlers. + 1148| | /** The entries are ordered from oldest to newest handler. + 1149| | * + 1150| | * The pointers point to the real errorhandlers. The container it returns + 1151| | * however is a copy of the one internal to the connection, not a reference. + 1152| | */ + 1153| | [[nodiscard, deprecated("Use a notice handler instead.")]] + 1154| | std::vector get_errorhandlers() const; + 1155| | + 1156| | /// Return a connection string encapsulating this connection's options. + 1157| | /** The connection must be currently open for this to work. + 1158| | * + 1159| | * Returns a reconstruction of this connection's connection string. It may + 1160| | * not exactly match the connection string you passed in when creating this + 1161| | * connection. + 1162| | */ + 1163| | [[nodiscard]] std::string connection_string() const; + 1164| | + 1165| | /// Explicitly close the connection. + 1166| | /** The destructor will do this for you automatically. Still, there is a + 1167| | * reason to `close()` objects explicitly where possible: if an error should + 1168| | * occur while closing, `close()` can throw an exception. A destructor + 1169| | * cannot. + 1170| | * + 1171| | * Closing a connection is idempotent. Closing a connection that's already + 1172| | * closed does nothing. + 1173| | */ + 1174| | void close(); + 1175| | + 1176| | /// Seize control of a raw libpq connection. + 1177| | /** @warning Do not do this. Please. It's for very rare, very specific + 1178| | * use-cases. The mechanism may change (or break) in unexpected ways in + 1179| | * future versions. + 1180| | * + 1181| | * @param raw_conn a raw libpq `PQconn` pointer. + 1182| | */ + 1183| | static connection seize_raw_connection(internal::pq::PGconn *raw_conn) + 1184| 0| { + 1185| 0| return connection{raw_conn}; + 1186| 0| } + 1187| | + 1188| | /// Release the raw connection without closing it. + 1189| | /** @warning Do not do this. It's for very rare, very specific use-cases. + 1190| | * The mechanism may change (or break) in unexpected ways in future versions. + 1191| | * + 1192| | * The `connection` object becomes unusable after this. + 1193| | */ + 1194| | internal::pq::PGconn *release_raw_connection() && + 1195| 0| { + 1196| 0| return std::exchange(m_conn, nullptr); + 1197| 0| } + 1198| | + 1199| | /// Set session variable, using SQL's `SET` command. + 1200| | /** @deprecated To set a session variable, use @ref set_session_var. To set + 1201| | * a transaction-local variable, execute an SQL `SET` command. + 1202| | * + 1203| | * @warning When setting a string value, you must escape and quote it first. + 1204| | * Use the @ref quote() function to do that. + 1205| | * + 1206| | * @warning This executes an SQL query, so do not get or set variables while + 1207| | * a table stream or pipeline is active on the same connection. + 1208| | * + 1209| | * @param var Variable to set. + 1210| | * @param value New value for Var. This can be any SQL expression. If it's + 1211| | * a string, be sure that it's properly escaped and quoted. + 1212| | */ + 1213| | [[deprecated("To set session variables, use set_session_var.")]] void + 1214| | set_variable(std::string_view var, std::string_view value) &; + 1215| | + 1216| | /// Read session variable, using SQL's `SHOW` command. + 1217| | /** @warning This executes an SQL query, so do not get or set variables while + 1218| | * a table stream or pipeline is active on the same connection. + 1219| | */ + 1220| | [[deprecated("Use get_var instead.")]] std::string + 1221| | get_variable(std::string_view); + 1222| | + 1223| |private: + 1224| | friend class connecting; + 1225| | enum connect_mode + 1226| | { + 1227| | connect_nonblocking + 1228| | }; + 1229| | connection(connect_mode, zview connection_string); + 1230| | + 1231| | /// For use by @ref seize_raw_connection. + 1232| | explicit connection(internal::pq::PGconn *raw_conn); + 1233| | + 1234| | /// Poll for ongoing connection, try to progress towards completion. + 1235| | /** Returns a pair of "now please wait to read data from socket" and "now + 1236| | * please wait to write data to socket." Both will be false when done. + 1237| | * + 1238| | * Throws an exception if polling indicates that the connection has failed. + 1239| | */ + 1240| | std::pair poll_connect(); + 1241| | + 1242| | // Initialise based on connection string. + 1243| | void init(char const options[]); + 1244| | // Initialise based on parameter names and values. + 1245| | void init(char const *params[], char const *values[]); + 1246| | void set_up_notice_handlers(); + 1247| | void complete_init(); + 1248| | + 1249| | result make_result( + 1250| | internal::pq::PGresult *pgr, std::shared_ptr const &query, + 1251| | std::string_view desc = ""sv); + 1252| | + 1253| | void PQXX_PRIVATE set_up_state(); + 1254| | + 1255| | int PQXX_PRIVATE PQXX_PURE status() const noexcept; + 1256| | + 1257| | /// Escape a string, into a buffer allocated by the caller. + 1258| | /** The buffer must have room for at least `2*std::size(text) + 1` bytes. + 1259| | * + 1260| | * Returns the number of bytes written, including the trailing zero. + 1261| | */ + 1262| | std::size_t esc_to_buf(std::string_view text, char *buf) const; + 1263| | + 1264| | friend class internal::gate::const_connection_largeobject; + 1265| | char const *PQXX_PURE err_msg() const noexcept; + 1266| | + 1267| | result exec_prepared(std::string_view statement, internal::c_params const &); + 1268| | + 1269| | /// Throw @ref usage_error if this connection is not in a movable state. + 1270| | void check_movable() const; + 1271| | /// Throw @ref usage_error if not in a state where it can be move-assigned. + 1272| | void check_overwritable() const; + 1273| | + 1274| | friend class internal::gate::connection_errorhandler; + 1275| | void PQXX_PRIVATE register_errorhandler(errorhandler *); + 1276| | void PQXX_PRIVATE unregister_errorhandler(errorhandler *) noexcept; + 1277| | + 1278| | friend class internal::gate::connection_transaction; + 1279| | result exec(std::string_view, std::string_view = ""sv); + 1280| | result PQXX_PRIVATE + 1281| | exec(std::shared_ptr const &, std::string_view = ""sv); + 1282| | void PQXX_PRIVATE register_transaction(transaction_base *); + 1283| | void PQXX_PRIVATE unregister_transaction(transaction_base *) noexcept; + 1284| | + 1285| | friend struct internal::gate::connection_stream_from; + 1286| | /// Read a line of COPY output. + 1287| | /** If the output indicates that the COPY has ended, the buffer pointer + 1288| | * will be null and the size will be zero. Otherwise, the pointer will hold + 1289| | * a buffer containing the line, and size will be its length not including + 1290| | * the newline at the end. + 1291| | */ + 1292| | std::pair, std::size_t> + 1293| | read_copy_line(); + 1294| | + 1295| | friend class internal::gate::connection_stream_to; + 1296| | void PQXX_PRIVATE write_copy_line(std::string_view); + 1297| | void PQXX_PRIVATE end_copy_write(); + 1298| | + 1299| | friend class internal::gate::connection_largeobject; + 1300| 0| internal::pq::PGconn *raw_connection() const { return m_conn; } + 1301| | + 1302| | friend class internal::gate::connection_notification_receiver; + 1303| | void add_receiver(notification_receiver *); + 1304| | void remove_receiver(notification_receiver *) noexcept; + 1305| | + 1306| | friend class internal::gate::connection_pipeline; + 1307| | void PQXX_PRIVATE start_exec(char const query[]); + 1308| | bool PQXX_PRIVATE consume_input() noexcept; + 1309| | bool PQXX_PRIVATE is_busy() const noexcept; + 1310| | internal::pq::PGresult *get_result(); + 1311| | + 1312| | friend class internal::gate::connection_dbtransaction; + 1313| | friend class internal::gate::connection_sql_cursor; + 1314| | + 1315| | result exec_params(std::string_view query, internal::c_params const &args); + 1316| | + 1317| | /// Connection handle. + 1318| | internal::pq::PGconn *m_conn = nullptr; + 1319| | + 1320| | /// Active transaction on connection, if any. + 1321| | /** We don't use this for anything, except to check for open transactions + 1322| | * when we close the connection or start a new transaction. + 1323| | * + 1324| | * We also don't allow move construction or move assignment while there's a + 1325| | * transaction, since moving the connection in that case would leave one or + 1326| | * more pointers back from the transaction to the connection dangling. + 1327| | */ + 1328| | transaction_base const *m_trans = nullptr; + 1329| | + 1330| | /// 9.0: Replace with just notice handler. + 1331| | std::shared_ptr m_notice_waiters; + 1332| | + 1333| | // TODO: Remove these when we retire notification_receiver. + 1334| | // TODO: Can we make these movable? + 1335| | using receiver_list = + 1336| | std::multimap; + 1337| | /// Notification receivers. + 1338| | receiver_list m_receivers; + 1339| | + 1340| | /// Notification handlers. + 1341| | /** These are the functions we call when notifications come in. Each + 1342| | * corresponds to a `LISTEN` we have executed. + 1343| | * + 1344| | * The map does not contain any `std::function` which are empty. If the + 1345| | * caller registers an empty function, that simply cancels any subscription + 1346| | * to that channel. + 1347| | */ + 1348| | std::map m_notification_handlers; + 1349| | + 1350| | /// Unique number to use as suffix for identifiers (see adorn_name()). + 1351| | int m_unique_id = 0; + 1352| |}; + 1353| | + 1354| | + 1355| |/// @deprecated Old base class for connection. They are now the same class. + 1356| |using connection_base = connection; + 1357| | + 1358| | + 1359| |/// An ongoing, non-blocking stepping stone to a connection. + 1360| |/** Use this when you want to create a connection to the database, but without + 1361| | * blocking your whole thread. It is only available on systems that have + 1362| | * the `` header, and Windows. + 1363| | * + 1364| | * Connecting in this way is probably not "faster" (it's more complicated and + 1365| | * has some extra overhead), but in some situations you can use it to make your + 1366| | * application as a whole faster. It all depends on having other useful work + 1367| | * to do in the same thread, and being able to wait on a socket. If you have + 1368| | * other I/O going on at the same time, your event loop can wait for both the + 1369| | * libpqxx socket and your own sockets, and wake up whenever any of them is + 1370| | * ready to do work. + 1371| | * + 1372| | * Connecting in this way is not properly "asynchronous;" it's merely + 1373| | * "nonblocking." This means it's not a super-high-performance mechanism like + 1374| | * you might get with e.g. `io_uring`. In particular, if we need to look up + 1375| | * the database hostname in DNS, that will happen synchronously. + 1376| | * + 1377| | * To use this, create the `connecting` object, passing a connection string. + 1378| | * Then loop: If @ref wait_to_read returns true, wait for the socket to have + 1379| | * incoming data on it. If @ref wait_to_write returns true, wait for the + 1380| | * socket to be ready for writing. Then call @ref process to process any + 1381| | * incoming or outgoing data. Do all of this until @ref done returns true (or + 1382| | * there is an exception). Finally, call @ref produce to get the completed + 1383| | * connection. + 1384| | * + 1385| | * For example: + 1386| | * + 1387| | * ```cxx + 1388| | * pqxx::connecting cg{}; + 1389| | * + 1390| | * // Loop until we're done connecting. + 1391| | * while (!cg.done()) + 1392| | * { + 1393| | * wait_for_fd(cg.sock(), cg.wait_to_read(), cg.wait_to_write()); + 1394| | * cg.process(); + 1395| | * } + 1396| | * + 1397| | * pqxx::connection cx = std::move(cg).produce(); + 1398| | * + 1399| | * // At this point, cx is a working connection. You can no longer use + 1400| | * // cg at all. + 1401| | * ``` + 1402| | */ + 1403| |class PQXX_LIBEXPORT connecting + 1404| |{ + 1405| |public: + 1406| | /// Start connecting. + 1407| | connecting(zview connection_string = ""_zv); + 1408| | + 1409| | connecting(connecting const &) = delete; + 1410| | connecting(connecting &&) = default; + 1411| | connecting &operator=(connecting const &) = delete; + 1412| | connecting &operator=(connecting &&) = default; + 1413| | + 1414| | /// Get the socket. The socket may change during the connection process. + 1415| 0| [[nodiscard]] int sock() const & noexcept { return m_conn.sock(); } + 1416| | + 1417| | /// Should we currently wait to be able to _read_ from the socket? + 1418| | [[nodiscard]] constexpr bool wait_to_read() const & noexcept + 1419| 0| { + 1420| 0| return m_reading; + 1421| 0| } + 1422| | + 1423| | /// Should we currently wait to be able to _write_ to the socket? + 1424| | [[nodiscard]] constexpr bool wait_to_write() const & noexcept + 1425| 0| { + 1426| 0| return m_writing; + 1427| 0| } + 1428| | + 1429| | /// Progress towards completion (but don't block). + 1430| | void process() &; + 1431| | + 1432| | /// Is our connection finished? + 1433| | [[nodiscard]] constexpr bool done() const & noexcept + 1434| 0| { + 1435| 0| return not m_reading and not m_writing; + 1436| 0| } + 1437| | + 1438| | /// Produce the completed connection object. + 1439| | /** Use this only once, after @ref done returned `true`. Once you have + 1440| | * called this, the `connecting` instance has no more use or meaning. You + 1441| | * can't call any of its member functions afterwards. + 1442| | * + 1443| | * This member function is rvalue-qualified, meaning that you can only call + 1444| | * it on an rvalue instance of the class. If what you have is not an rvalue, + 1445| | * turn it into one by wrapping it in `std::move()`. + 1446| | */ + 1447| | [[nodiscard]] connection produce() &&; + 1448| | + 1449| |private: + 1450| | connection m_conn; + 1451| | bool m_reading{false}; + 1452| | bool m_writing{true}; + 1453| |}; + 1454| | + 1455| | + 1456| |template inline std::string connection::quote(T const &t) const + 1457| |{ + 1458| | if constexpr (nullness::always_null) + 1459| | { + 1460| | return "NULL"; + 1461| | } + 1462| | else + 1463| | { + 1464| | if (is_null(t)) + 1465| | return "NULL"; + 1466| | auto const text{to_string(t)}; + 1467| | + 1468| | // Okay, there's an easy way to do this and there's a hard way. The easy + 1469| | // way was "quote, esc(to_string(t)), quote". I'm going with the hard way + 1470| | // because it's going to save some string manipulation that will probably + 1471| | // incur some unnecessary memory allocations and deallocations. + 1472| | std::string buf{'\''}; + 1473| | buf.resize(2 + 2 * std::size(text) + 1); + 1474| | auto const content_bytes{esc_to_buf(text, buf.data() + 1)}; + 1475| | auto const closing_quote{1 + content_bytes}; + 1476| | buf[closing_quote] = '\''; + 1477| | auto const end{closing_quote + 1}; + 1478| | buf.resize(end); + 1479| | return buf; + 1480| | } + 1481| |} + 1482| | + 1483| | + 1484| |template + 1485| |inline std::string connection::quote_columns(STRINGS const &columns) const + 1486| 0|{ + 1487| 0| return separated_list( + 1488| 0| ","sv, std::cbegin(columns), std::cend(columns), + 1489| 0| [this](auto col) { return this->quote_name(*col); }); + 1490| 0|} + 1491| | + 1492| | + 1493| |#if defined(PQXX_HAVE_CONCEPTS) + 1494| |template + 1495| |inline connection::connection(MAPPING const ¶ms) + 1496| |{ + 1497| | check_version(); + 1498| | + 1499| | std::vector keys, values; + 1500| | if constexpr (std::ranges::sized_range) + 1501| | { + 1502| | auto const size{std::ranges::size(params) + 1}; + 1503| | keys.reserve(size); + 1504| | values.reserve(size); + 1505| | } + 1506| | for (auto const &[key, value] : params) + 1507| | { + 1508| | keys.push_back(internal::as_c_string(key)); + 1509| | values.push_back(internal::as_c_string(value)); + 1510| | } + 1511| | keys.push_back(nullptr); + 1512| | values.push_back(nullptr); + 1513| | init(std::data(keys), std::data(values)); + 1514| |} + 1515| |#endif // PQXX_HAVE_CONCEPTS + 1516| | + 1517| | + 1518| |/// Encrypt a password. @deprecated Use connection::encrypt_password instead. + 1519| |[[nodiscard, + 1520| | deprecated("Use connection::encrypt_password instead.")]] std::string + 1521| | PQXX_LIBEXPORT + 1522| | encrypt_password(char const user[], char const password[]); + 1523| | + 1524| |/// Encrypt password. @deprecated Use connection::encrypt_password instead. + 1525| |[[nodiscard, + 1526| | deprecated("Use connection::encrypt_password instead.")]] inline std::string + 1527| |encrypt_password(zview user, zview password) + 1528| 0|{ + 1529| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 1530| 0| return encrypt_password(user.c_str(), password.c_str()); + 1531| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 1532| 0|} + 1533| |} // namespace pqxx + 1534| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/cursor.hxx: + 1| |/* Definition of the iterator/container-style cursor classes. + 2| | * + 3| | * C++-style wrappers for SQL cursors. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/cursor instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_CURSOR + 14| |#define PQXX_H_CURSOR + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include + 21| |#include + 22| | + 23| |#include "pqxx/result.hxx" + 24| |#include "pqxx/transaction_base.hxx" + 25| | + 26| | + 27| |namespace pqxx + 28| |{ + 29| |/// Common definitions for cursor types + 30| |/** In C++ terms, fetches are always done in pre-increment or pre-decrement + 31| | * fashion--i.e. the result does not include the row the cursor is on at the + 32| | * beginning of the fetch, and the cursor ends up being positioned on the last + 33| | * row in the result. + 34| | * + 35| | * There are singular positions akin to `end()` at both the beginning and the + 36| | * end of the cursor's range of movement, although these fit in so naturally + 37| | * with the semantics that one rarely notices them. The cursor begins at the + 38| | * first of these, but any fetch in the forward direction will move the cursor + 39| | * off this position and onto the first row before returning anything. + 40| | */ + 41| |class PQXX_LIBEXPORT cursor_base + 42| |{ + 43| |public: + 44| | using size_type = result_size_type; + 45| | using difference_type = result_difference_type; + 46| | + 47| | /// Cursor access-pattern policy + 48| | /** Allowing a cursor to move forward only can result in better performance, + 49| | * so use this access policy whenever possible. + 50| | */ + 51| | enum access_policy + 52| | { + 53| | /// Cursor can move forward only + 54| | forward_only, + 55| | /// Cursor can move back and forth + 56| | random_access + 57| | }; + 58| | + 59| | /// Cursor update policy + 60| | /** + 61| | * @warning Not all PostgreSQL versions support updatable cursors. + 62| | */ + 63| | enum update_policy + 64| | { + 65| | /// Cursor can be used to read data but not to write + 66| | read_only, + 67| | /// Cursor can be used to update data as well as read it + 68| | update + 69| | }; + 70| | + 71| | /// Cursor destruction policy + 72| | /** The normal thing to do is to make a cursor object the owner of the SQL + 73| | * cursor it represents. There may be cases, however, where a cursor needs + 74| | * to persist beyond the end of the current transaction (and thus also beyond + 75| | * the lifetime of the cursor object that created it!), where it can be + 76| | * "adopted" into a new cursor object. See the basic_cursor documentation + 77| | * for an explanation of cursor adoption. + 78| | * + 79| | * If a cursor is created with "loose" ownership policy, the object + 80| | * representing the underlying SQL cursor will not take the latter with it + 81| | * when its own lifetime ends, nor will its originating transaction. + 82| | * + 83| | * @warning Use this feature with care and moderation. Only one cursor + 84| | * object should be responsible for any one underlying SQL cursor at any + 85| | * given time. + 86| | */ + 87| | enum ownership_policy + 88| | { + 89| | /// Destroy SQL cursor when cursor object is closed at end of transaction + 90| | owned, + 91| | /// Leave SQL cursor in existence after close of object and transaction + 92| | loose + 93| | }; + 94| | + 95| | cursor_base() = delete; + 96| | cursor_base(cursor_base const &) = delete; + 97| | cursor_base &operator=(cursor_base const &) = delete; + 98| | + 99| | /** + 100| | * @name Special movement distances. + 101| | */ + 102| | //@{ + 103| | + 104| | /// Special value: read until end. + 105| | /** @return Maximum value for result::difference_type, so the cursor will + 106| | * attempt to read the largest possible result set. + 107| | */ + 108| | [[nodiscard]] static constexpr difference_type all() noexcept + 109| 0| { + 110| 0| return (std::numeric_limits::max)() - 1; + 111| 0| } + 112| | + 113| | /// Special value: read one row only. + 114| | /** @return Unsurprisingly, 1. + 115| | */ + 116| 0| [[nodiscard]] static constexpr difference_type next() noexcept { return 1; } + 117| | + 118| | /// Special value: read backwards, one row only. + 119| | /** @return Unsurprisingly, -1. + 120| | */ + 121| | [[nodiscard]] static constexpr difference_type prior() noexcept + 122| 0| { + 123| 0| return -1; + 124| 0| } + 125| | + 126| | /// Special value: read backwards from current position back to origin. + 127| | /** @return Minimum value for result::difference_type. + 128| | */ + 129| | [[nodiscard]] static constexpr difference_type backward_all() noexcept + 130| 0| { + 131| 0| return (std::numeric_limits::min)() + 1; + 132| 0| } + 133| | + 134| | //@} + 135| | + 136| | /// Name of underlying SQL cursor + 137| | /** + 138| | * @returns Name of SQL cursor, which may differ from original given name. + 139| | * @warning Don't use this to access the SQL cursor directly without going + 140| | * through the provided wrapper classes! + 141| | */ + 142| | [[nodiscard]] constexpr std::string const &name() const noexcept + 143| 0| { + 144| 0| return m_name; + 145| 0| } + 146| | + 147| |protected: + 148| | cursor_base(connection &, std::string_view Name, bool embellish_name = true); + 149| | + 150| | std::string const m_name; + 151| |}; + 152| |} // namespace pqxx + 153| | + 154| | + 155| |#include + 156| | + 157| | + 158| |namespace pqxx + 159| |{ + 160| |/// "Stateless cursor" class: easy API for retrieving parts of result sets + 161| |/** This is a front-end for SQL cursors, but with a more C++-like API. + 162| | * + 163| | * Actually, stateless_cursor feels entirely different from SQL cursors. You + 164| | * don't keep track of positions, fetches, and moves; you just say which rows + 165| | * you want. See the retrieve() member function. + 166| | */ + 167| |template + 168| |class stateless_cursor + 169| |{ + 170| |public: + 171| | using size_type = result_size_type; + 172| | using difference_type = result_difference_type; + 173| | + 174| | /// Create cursor. + 175| | /** + 176| | * @param tx The transaction within which you want to create the cursor. + 177| | * @param query The SQL query whose results the cursor should traverse. + 178| | * @param cname A hint for the cursor's name. The actual SQL cursor's name + 179| | * will be based on this (though not necessarily identical). + 180| | * @param hold Create a `WITH HOLD` cursor? Such cursors stay alive after + 181| | * the transaction has ended, so you can continue to use it. + 182| | */ + 183| | stateless_cursor( + 184| | transaction_base &tx, std::string_view query, std::string_view cname, + 185| | bool hold) : + 186| | m_cur{tx, query, cname, cursor_base::random_access, up, op, hold} + 187| | {} + 188| | + 189| | /// Adopt an existing scrolling SQL cursor. + 190| | /** This lets you define a cursor yourself, and then wrap it in a + 191| | * libpqxx-managed `stateless_cursor` object. + 192| | * + 193| | * @param tx The transaction within which you want to manage the cursor. + 194| | * @param adopted_cursor Your cursor's SQL name. + 195| | */ + 196| | stateless_cursor(transaction_base &tx, std::string_view adopted_cursor) : + 197| | m_cur{tx, adopted_cursor, op} + 198| | { + 199| | // Put cursor in known position + 200| | m_cur.move(cursor_base::backward_all()); + 201| | } + 202| | + 203| | /// Close this cursor. + 204| | /** The destructor will do this for you automatically. + 205| | * + 206| | * Closing a cursor is idempotent. Closing a cursor that's already closed + 207| | * does nothing. + 208| | */ + 209| | void close() noexcept { m_cur.close(); } + 210| | + 211| | /// Number of rows in cursor's result set + 212| | /** @note This function is not const; it may need to scroll to find the size + 213| | * of the result set. + 214| | */ + 215| | [[nodiscard]] size_type size() + 216| | { + 217| | return internal::obtain_stateless_cursor_size(m_cur); + 218| | } + 219| | + 220| | /// Retrieve rows from begin_pos (inclusive) to end_pos (exclusive) + 221| | /** Rows are numbered starting from 0 to size()-1. + 222| | * + 223| | * @param begin_pos First row to retrieve. May be one row beyond the end of + 224| | * the result set, to avoid errors for empty result sets. Otherwise, must be + 225| | * a valid row number in the result set. + 226| | * @param end_pos Row up to which to fetch. Rows are returned ordered from + 227| | * begin_pos to end_pos, i.e. in ascending order if begin_pos < end_pos but + 228| | * in descending order if begin_pos > end_pos. The end_pos may be + 229| | * arbitrarily inside or outside the result set; only existing rows are + 230| | * included in the result. + 231| | */ + 232| | result retrieve(difference_type begin_pos, difference_type end_pos) + 233| | { + 234| | return internal::stateless_cursor_retrieve( + 235| | m_cur, result::difference_type(size()), begin_pos, end_pos); + 236| | } + 237| | + 238| | /// Return this cursor's name. + 239| | [[nodiscard]] constexpr std::string const &name() const noexcept + 240| | { + 241| | return m_cur.name(); + 242| | } + 243| | + 244| |private: + 245| | internal::sql_cursor m_cur; + 246| |}; + 247| | + 248| | + 249| |class icursor_iterator; + 250| |} // namespace pqxx + 251| | + 252| | + 253| |namespace pqxx::internal::gate + 254| |{ + 255| |class icursor_iterator_icursorstream; + 256| |class icursorstream_icursor_iterator; + 257| |} // namespace pqxx::internal::gate + 258| | + 259| | + 260| |namespace pqxx + 261| |{ + 262| |/// Simple read-only cursor represented as a stream of results + 263| |/** SQL cursors can be tricky, especially in C++ since the two languages seem + 264| | * to have been designed on different planets. An SQL cursor has two singular + 265| | * positions akin to `end()` on either side of the underlying result set. + 266| | * + 267| | * These cultural differences are hidden from view somewhat by libpqxx, which + 268| | * tries to make SQL cursors behave more like familiar C++ entities such as + 269| | * iterators, sequences, streams, and containers. + 270| | * + 271| | * Data is fetched from the cursor as a sequence of result objects. Each of + 272| | * these will contain the number of rows defined as the stream's stride, except + 273| | * of course the last block of data which may contain fewer rows. + 274| | * + 275| | * This class can create or adopt cursors that live outside any backend + 276| | * transaction, which your backend version may not support. + 277| | */ + 278| |class PQXX_LIBEXPORT icursorstream + 279| |{ + 280| |public: + 281| | using size_type = cursor_base::size_type; + 282| | using difference_type = cursor_base::difference_type; + 283| | + 284| | /// Set up a read-only, forward-only cursor. + 285| | /** Roughly equivalent to a C++ Standard Library istream, this cursor type + 286| | * supports only two operations: reading a block of rows while moving + 287| | * forward, and moving forward without reading any data. + 288| | * + 289| | * @param context Transaction context in which this cursor will be active. + 290| | * @param query SQL query whose results this cursor shall iterate. + 291| | * @param basename Suggested name for the SQL cursor; the library will append + 292| | * a unique code to ensure its uniqueness. + 293| | * @param sstride Number of rows to fetch per read operation; must be a + 294| | * positive number. + 295| | */ + 296| | icursorstream( + 297| | transaction_base &context, std::string_view query, + 298| | std::string_view basename, difference_type sstride = 1); + 299| | + 300| | /// Adopt existing SQL cursor. Use with care. + 301| | /** Forms a cursor stream around an existing SQL cursor, as returned by e.g. + 302| | * a server-side function. The SQL cursor will be cleaned up by the stream's + 303| | * destructor as if it had been created by the stream; cleaning it up by hand + 304| | * or adopting the same cursor twice is an error. + 305| | * + 306| | * Passing the name of the cursor as a string is not allowed, both to avoid + 307| | * confusion with the other constructor and to discourage unnecessary use of + 308| | * adopted cursors. + 309| | * + 310| | * @warning It is technically possible to adopt a "WITH HOLD" cursor, i.e. a + 311| | * cursor that stays alive outside its creating transaction. However, any + 312| | * cursor stream (including the underlying SQL cursor, naturally) must be + 313| | * destroyed before its transaction context object is destroyed. Therefore + 314| | * the only way to use SQL's WITH HOLD feature is to adopt the cursor, but + 315| | * defer doing so until after entering the transaction context that will + 316| | * eventually destroy it. + 317| | * + 318| | * @param context Transaction context in which this cursor will be active. + 319| | * @param cname Result field containing the name of the SQL cursor to adopt. + 320| | * @param sstride Number of rows to fetch per read operation; must be a + 321| | * positive number. + 322| | * @param op Ownership policy. Determines whether the cursor underlying this + 323| | * stream will be destroyed when the stream is closed. + 324| | */ + 325| | icursorstream( + 326| | transaction_base &context, field const &cname, difference_type sstride = 1, + 327| | cursor_base::ownership_policy op = cursor_base::owned); + 328| | + 329| | /// Return `true` if this stream may still return more data. + 330| 0| constexpr operator bool() const & noexcept { return not m_done; } + 331| | + 332| | /// Read new value into given result object; same as operator `>>`. + 333| | /** The result set may continue any number of rows from zero to the chosen + 334| | * stride, inclusive. An empty result will only be returned if there are no + 335| | * more rows to retrieve. + 336| | * + 337| | * @param res Write the retrieved data into this result object. + 338| | * @return Reference to this very stream, to facilitate "chained" invocations + 339| | * ("C.get(r1).get(r2);") + 340| | */ + 341| | icursorstream &get(result &res) + 342| 0| { + 343| 0| res = fetchblock(); + 344| 0| return *this; + 345| 0| } + 346| | /// Read new value into given result object; same as `get(result&)`. + 347| | /** The result set may continue any number of rows from zero to the chosen + 348| | * stride, inclusive. An empty result will only be returned if there are no + 349| | * more rows to retrieve. + 350| | * + 351| | * @param res Write the retrieved data into this result object. + 352| | * @return Reference to this very stream, to facilitate "chained" invocations + 353| | * ("C >> r1 >> r2;") + 354| | */ + 355| 0| icursorstream &operator>>(result &res) { return get(res); } + 356| | + 357| | /// Move given number of rows forward without reading data. + 358| | /** Ignores any stride that you may have set. It moves by a given number of + 359| | * rows, not a number of strides. + 360| | * + 361| | * @return Reference to this stream itself, to facilitate "chained" + 362| | * invocations. + 363| | */ + 364| | icursorstream &ignore(std::streamsize n = 1) &; + 365| | + 366| | /// Change stride, i.e. the number of rows to fetch per read operation. + 367| | /** + 368| | * @param stride Must be a positive number. + 369| | */ + 370| | void set_stride(difference_type stride) &; + 371| | [[nodiscard]] constexpr difference_type stride() const noexcept + 372| 0| { + 373| 0| return m_stride; + 374| 0| } + 375| | + 376| |private: + 377| | result fetchblock(); + 378| | + 379| | friend class internal::gate::icursorstream_icursor_iterator; + 380| | size_type forward(size_type n = 1); + 381| | void insert_iterator(icursor_iterator *) noexcept; + 382| | void remove_iterator(icursor_iterator *) const noexcept; + 383| | + 384| | void service_iterators(difference_type); + 385| | + 386| | internal::sql_cursor m_cur; + 387| | + 388| | difference_type m_stride; + 389| | difference_type m_realpos, m_reqpos; + 390| | + 391| | mutable icursor_iterator *m_iterators; + 392| | + 393| | bool m_done; + 394| |}; + 395| | + 396| | + 397| |/// Approximate istream_iterator for icursorstream. + 398| |/** Intended as an implementation of an input_iterator (as defined by the C++ + 399| | * Standard Library), this class supports only two basic operations: reading + 400| | * the current element, and moving forward. In addition to the minimal + 401| | * guarantees for istream_iterators, this class supports multiple successive + 402| | * reads of the same position (the current result set is cached in the + 403| | * iterator) even after copying and even after new data have been read from the + 404| | * stream. This appears to be a requirement for input_iterators. Comparisons + 405| | * are also supported in the general case. + 406| | * + 407| | * The iterator does not care about its own position, however. Moving an + 408| | * iterator forward moves the underlying stream forward and reads the data from + 409| | * the new stream position, regardless of the iterator's old position in the + 410| | * stream. + 411| | * + 412| | * The stream's stride defines the granularity for all iterator movement or + 413| | * access operations, i.e. "ici += 1" advances the stream by one stride's worth + 414| | * of rows, and "*ici++" reads one stride's worth of rows from the stream. + 415| | * + 416| | * @warning Do not read from the underlying stream or its cursor, move its read + 417| | * position, or change its stride, between the time the first icursor_iterator + 418| | * on it is created and the time its last icursor_iterator is destroyed. + 419| | * + 420| | * @warning Manipulating these iterators within the context of a single cursor + 421| | * stream is not thread-safe. Creating a new iterator, copying one, + 422| | * or destroying one affects the stream as a whole. + 423| | */ + 424| |class PQXX_LIBEXPORT icursor_iterator + 425| |{ + 426| |public: + 427| | using iterator_category = std::input_iterator_tag; + 428| | using value_type = result; + 429| | using pointer = result const *; + 430| | using reference = result const &; + 431| | using istream_type = icursorstream; + 432| | using size_type = istream_type::size_type; + 433| | using difference_type = istream_type::difference_type; + 434| | + 435| | icursor_iterator() noexcept; + 436| | explicit icursor_iterator(istream_type &) noexcept; + 437| | icursor_iterator(icursor_iterator const &) noexcept; + 438| | ~icursor_iterator() noexcept; + 439| | + 440| | result const &operator*() const + 441| 0| { + 442| 0| refresh(); + 443| 0| return m_here; + 444| 0| } + 445| | result const *operator->() const + 446| 0| { + 447| 0| refresh(); + 448| 0| return &m_here; + 449| 0| } + 450| | icursor_iterator &operator++(); + 451| | icursor_iterator operator++(int) &; + 452| | icursor_iterator &operator+=(difference_type); + 453| | icursor_iterator &operator=(icursor_iterator const &) noexcept; + 454| | + 455| | [[nodiscard]] bool operator==(icursor_iterator const &rhs) const; + 456| | [[nodiscard]] bool operator!=(icursor_iterator const &rhs) const noexcept + 457| 0| { + 458| 0| return not operator==(rhs); + 459| 0| } + 460| | [[nodiscard]] bool operator<(icursor_iterator const &rhs) const; + 461| | [[nodiscard]] bool operator>(icursor_iterator const &rhs) const + 462| 0| { + 463| 0| return rhs < *this; + 464| 0| } + 465| | [[nodiscard]] bool operator<=(icursor_iterator const &rhs) const + 466| 0| { + 467| 0| return not(*this > rhs); + 468| 0| } + 469| | [[nodiscard]] bool operator>=(icursor_iterator const &rhs) const + 470| 0| { + 471| 0| return not(*this < rhs); + 472| 0| } + 473| | + 474| |private: + 475| | void refresh() const; + 476| | + 477| | friend class internal::gate::icursor_iterator_icursorstream; + 478| 0| difference_type pos() const noexcept { return m_pos; } + 479| | void fill(result const &); + 480| | + 481| | icursorstream *m_stream{nullptr}; + 482| | result m_here; + 483| | difference_type m_pos; + 484| | icursor_iterator *m_prev{nullptr}, *m_next{nullptr}; + 485| |}; + 486| |} // namespace pqxx + 487| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/dbtransaction.hxx: + 1| |/* Definition of the pqxx::dbtransaction abstract base class. + 2| | * + 3| | * pqxx::dbransaction defines a real transaction on the database. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/dbtransaction instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_DBTRANSACTION + 14| |#define PQXX_H_DBTRANSACTION + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include "pqxx/transaction_base.hxx" + 21| | + 22| |namespace pqxx + 23| |{ + 24| |/// Abstract transaction base class: bracket transactions on the database. + 25| |/** + 26| | * @ingroup transactions + 27| | * + 28| | * Use a dbtransaction-derived object such as "work" (transaction<>) to enclose + 29| | * operations on a database in a single "unit of work." This ensures that the + 30| | * whole series of operations either succeeds as a whole or fails completely. + 31| | * In no case will it leave half-finished work behind in the database. + 32| | * + 33| | * Once processing on a transaction has succeeded and any changes should be + 34| | * allowed to become permanent in the database, call commit(). If something + 35| | * has gone wrong and the changes should be forgotten, call abort() instead. + 36| | * If you do neither, an implicit abort() is executed at destruction time. + 37| | * + 38| | * It is an error to abort a transaction that has already been committed, or to + 39| | * commit a transaction that has already been aborted. Aborting an already + 40| | * aborted transaction or committing an already committed one is allowed, to + 41| | * make error handling easier. Repeated aborts or commits have no effect after + 42| | * the first one. + 43| | * + 44| | * Database transactions are not suitable for guarding long-running processes. + 45| | * If your transaction code becomes too long or too complex, consider ways to + 46| | * break it up into smaller ones. Unfortunately there is no universal recipe + 47| | * for this. + 48| | * + 49| | * The actual operations for committing/aborting the backend transaction are + 50| | * implemented by a derived class. The implementing concrete class must also + 51| | * call @ref close from its destructor. + 52| | */ + 53| |class PQXX_LIBEXPORT PQXX_NOVTABLE dbtransaction : public transaction_base + 54| |{ + 55| |protected: + 56| | /// Begin transaction. + 57| 0| explicit dbtransaction(connection &cx) : transaction_base{cx} {} + 58| | /// Begin transaction. + 59| | dbtransaction(connection &cx, std::string_view tname) : + 60| | transaction_base{cx, tname} + 61| 0| {} + 62| | /// Begin transaction. + 63| | dbtransaction( + 64| | connection &cx, std::string_view tname, + 65| | std::shared_ptr rollback_cmd) : + 66| | transaction_base{cx, tname, rollback_cmd} + 67| 0| {} + 68| |}; + 69| |} // namespace pqxx + 70| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/errorhandler.hxx: + 1| |/* Definition of the pqxx::errorhandler class. + 2| | * + 3| | * pqxx::errorhandler handlers errors and warnings in a database session. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/errorhandler instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_ERRORHANDLER + 14| |#define PQXX_H_ERRORHANDLER + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include "pqxx/types.hxx" + 21| | + 22| | + 23| |namespace pqxx::internal::gate + 24| |{ + 25| |class errorhandler_connection; + 26| |} + 27| | + 28| | + 29| |namespace pqxx + 30| |{ + 31| |/** + 32| | * @addtogroup errorhandler + 33| | */ + 34| |//@{ + 35| | + 36| |/// @deprecated Base class for obsolete error-handler callbacks. + 37| |/** This method of handling errors is obsolete. Use a "notice handler" + 38| | * instead. + 39| | * + 40| | * @warning Strange things happen when a result object outlives its parent + 41| | * connection. If you register an error handler on a connection, then you must + 42| | * not access the result after destroying the connection. This applies even if + 43| | * you destroy the error handler first! + 44| | */ + 45| |class PQXX_LIBEXPORT errorhandler + 46| |{ + 47| |public: + 48| | [[deprecated("Use a notice handler instead.")]] + 49| | explicit errorhandler(connection &); + 50| | virtual ~errorhandler(); + 51| | + 52| | /// Define in subclass: receive an error or warning message from the + 53| | /// database. + 54| | /** + 55| | * @return Whether the same error message should also be passed to the + 56| | * remaining, older errorhandlers. + 57| | */ + 58| | virtual bool operator()(char const msg[]) noexcept = 0; + 59| | + 60| | errorhandler() = delete; + 61| | errorhandler(errorhandler const &) = delete; + 62| | errorhandler &operator=(errorhandler const &) = delete; + 63| | + 64| |private: + 65| | connection *m_home; + 66| | + 67| | friend class internal::gate::errorhandler_connection; + 68| | void unregister() noexcept; + 69| |}; + 70| | + 71| | + 72| |/// @deprecated Use a notice handler instead. + 73| |class quiet_errorhandler : public errorhandler + 74| |{ + 75| |public: + 76| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 77| | /// Suppress error notices. + 78| | [[deprecated("Use notice handlers instead.")]] + 79| | quiet_errorhandler(connection &cx) : + 80| | errorhandler{cx} + 81| 0| {} + 82| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 83| | + 84| | /// Revert to previous handling of error notices. + 85| 0| virtual bool operator()(char const[]) noexcept override { return false; } + 86| |}; + 87| | + 88| |//@} + 89| |} // namespace pqxx + 90| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/except.hxx: + 1| |/* Definition of libpqxx exception classes. + 2| | * + 3| | * pqxx::sql_error, pqxx::broken_connection, pqxx::in_doubt_error, ... + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/except instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_EXCEPT + 14| |#define PQXX_H_EXCEPT + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 21| |# include + 22| |#endif + 23| | + 24| |#include + 25| |#include + 26| | + 27| | + 28| |namespace pqxx + 29| |{ + 30| |/** + 31| | * @addtogroup exception Exception classes + 32| | * + 33| | * These exception classes follow, roughly, the two-level hierarchy defined by + 34| | * the PostgreSQL SQLSTATE error codes (see Appendix A of the PostgreSQL + 35| | * documentation corresponding to your server version). This is not a complete + 36| | * mapping though. There are other differences as well, e.g. the error code + 37| | * for `statement_completion_unknown` has a separate status in libpqxx as + 38| | * @ref in_doubt_error, and `too_many_connections` is classified as a + 39| | * `broken_connection` rather than a subtype of `insufficient_resources`. + 40| | * + 41| | * @see http://www.postgresql.org/docs/9.4/interactive/errcodes-appendix.html + 42| | * + 43| | * @{ + 44| | */ + 45| | + 46| |/// Run-time failure encountered by libpqxx, similar to std::runtime_error. + 47| |struct PQXX_LIBEXPORT failure : std::runtime_error + 48| |{ + 49| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 50| | explicit failure( + 51| | std::string const &, + 52| | std::source_location = std::source_location::current()); + 53| | std::source_location location; + 54| |#else + 55| | explicit failure(std::string const &); + 56| |#endif + 57| |}; + 58| | + 59| | + 60| |/// Exception class for lost or failed backend connection. + 61| |/** + 62| | * @warning When this happens on Unix-like systems, you may also get a SIGPIPE + 63| | * signal. That signal aborts the program by default, so if you wish to be + 64| | * able to continue after a connection breaks, be sure to disarm this signal. + 65| | * + 66| | * If you're working on a Unix-like system, see the manual page for + 67| | * `signal` (2) on how to deal with SIGPIPE. The easiest way to make this + 68| | * signal harmless is to make your program ignore it: + 69| | * + 70| | * ```cxx + 71| | * #include + 72| | * + 73| | * int main() + 74| | * { + 75| | * std::signal(SIGPIPE, SIG_IGN); + 76| | * // ... + 77| | * } + 78| | * ``` + 79| | */ + 80| |struct PQXX_LIBEXPORT broken_connection : failure + 81| |{ + 82| | broken_connection(); + 83| | explicit broken_connection( + 84| | std::string const & + 85| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 86| | , + 87| | std::source_location = std::source_location::current() + 88| |#endif + 89| | ); + 90| |}; + 91| | + 92| | + 93| |/// Exception class for micommunication with the server. + 94| |/** This happens when the conversation between libpq and the server gets messed + 95| | * up. There aren't many situations where this happens, but one known instance + 96| | * is when you call a parameterised or prepared statement with th ewrong number + 97| | * of parameters. + 98| | * + 99| | * So even though this is a `broken_connection`, it signals that retrying is + 100| | * _not_ likely to make the problem go away. + 101| | */ + 102| |struct PQXX_LIBEXPORT protocol_violation : broken_connection + 103| |{ + 104| | explicit protocol_violation( + 105| | std::string const & + 106| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 107| | , + 108| | std::source_location = std::source_location::current() + 109| |#endif + 110| | ); + 111| |}; + 112| | + 113| | + 114| |/// The caller attempted to set a variable to null, which is not allowed. + 115| |struct PQXX_LIBEXPORT variable_set_to_null : failure + 116| |{ + 117| | explicit variable_set_to_null( + 118| | std::string const & + 119| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 120| | , + 121| | std::source_location = std::source_location::current() + 122| |#endif + 123| | ); + 124| |}; + 125| | + 126| | + 127| |/// Exception class for failed queries. + 128| |/** Carries, in addition to a regular error message, a copy of the failed query + 129| | * and (if available) the SQLSTATE value accompanying the error. + 130| | */ + 131| |class PQXX_LIBEXPORT sql_error : public failure + 132| |{ + 133| | /// Query string. Empty if unknown. + 134| | std::string const m_query; + 135| | /// SQLSTATE string describing the error type, if known; or empty string. + 136| | std::string const m_sqlstate; + 137| | + 138| |public: + 139| | explicit sql_error( + 140| | std::string const &whatarg = "", std::string Q = "", + 141| | char const *sqlstate = nullptr + 142| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 143| | , + 144| | std::source_location = std::source_location::current() + 145| |#endif + 146| | ); + 147| | virtual ~sql_error() noexcept override; + 148| | + 149| | /// The query whose execution triggered the exception + 150| | [[nodiscard]] PQXX_PURE std::string const &query() const noexcept; + 151| | + 152| | /// SQLSTATE error code if known, or empty string otherwise. + 153| | [[nodiscard]] PQXX_PURE std::string const &sqlstate() const noexcept; + 154| |}; + 155| | + 156| | + 157| |/// "Help, I don't know whether transaction was committed successfully!" + 158| |/** Exception that might be thrown in rare cases where the connection to the + 159| | * database is lost while finishing a database transaction, and there's no way + 160| | * of telling whether it was actually executed by the backend. In this case + 161| | * the database is left in an indeterminate (but consistent) state, and only + 162| | * manual inspection will tell which is the case. + 163| | */ + 164| |struct PQXX_LIBEXPORT in_doubt_error : failure + 165| |{ + 166| | explicit in_doubt_error( + 167| | std::string const & + 168| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 169| | , + 170| | std::source_location = std::source_location::current() + 171| |#endif + 172| | ); + 173| |}; + 174| | + 175| | + 176| |/// The backend saw itself forced to roll back the ongoing transaction. + 177| |struct PQXX_LIBEXPORT transaction_rollback : sql_error + 178| |{ + 179| | explicit transaction_rollback( + 180| | std::string const &whatarg, std::string const &q = "", + 181| | char const sqlstate[] = nullptr + 182| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 183| | , + 184| | std::source_location = std::source_location::current() + 185| |#endif + 186| | ); + 187| |}; + 188| | + 189| | + 190| |/// Transaction failed to serialize. Please retry it. + 191| |/** Can only happen at transaction isolation levels REPEATABLE READ and + 192| | * SERIALIZABLE. + 193| | * + 194| | * The current transaction cannot be committed without violating the guarantees + 195| | * made by its isolation level. This is the effect of a conflict with another + 196| | * ongoing transaction. The transaction may still succeed if you try to + 197| | * perform it again. + 198| | */ + 199| |struct PQXX_LIBEXPORT serialization_failure : transaction_rollback + 200| |{ + 201| | explicit serialization_failure( + 202| | std::string const &whatarg, std::string const &q, + 203| | char const sqlstate[] = nullptr + 204| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 205| | , + 206| | std::source_location = std::source_location::current() + 207| |#endif + 208| | ); + 209| |}; + 210| | + 211| | + 212| |/// We can't tell whether our last statement succeeded. + 213| |struct PQXX_LIBEXPORT statement_completion_unknown : transaction_rollback + 214| |{ + 215| | explicit statement_completion_unknown( + 216| | std::string const &whatarg, std::string const &q, + 217| | char const sqlstate[] = nullptr + 218| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 219| | , + 220| | std::source_location = std::source_location::current() + 221| |#endif + 222| | ); + 223| |}; + 224| | + 225| | + 226| |/// The ongoing transaction has deadlocked. Retrying it may help. + 227| |struct PQXX_LIBEXPORT deadlock_detected : transaction_rollback + 228| |{ + 229| | explicit deadlock_detected( + 230| | std::string const &whatarg, std::string const &q, + 231| | char const sqlstate[] = nullptr + 232| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 233| | , + 234| | std::source_location = std::source_location::current() + 235| |#endif + 236| | ); + 237| |}; + 238| | + 239| | + 240| |/// Internal error in libpqxx library + 241| |struct PQXX_LIBEXPORT internal_error : std::logic_error + 242| |{ + 243| | explicit internal_error(std::string const &); + 244| |}; + 245| | + 246| | + 247| |/// Error in usage of libpqxx library, similar to std::logic_error + 248| |struct PQXX_LIBEXPORT usage_error : std::logic_error + 249| |{ + 250| | explicit usage_error( + 251| | std::string const & + 252| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 253| | , + 254| | std::source_location = std::source_location::current() + 255| |#endif + 256| | ); + 257| | + 258| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 259| | std::source_location location; + 260| |#endif + 261| |}; + 262| | + 263| | + 264| |/// Invalid argument passed to libpqxx, similar to std::invalid_argument + 265| |struct PQXX_LIBEXPORT argument_error : std::invalid_argument + 266| |{ + 267| | explicit argument_error( + 268| | std::string const & + 269| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 270| | , + 271| | std::source_location = std::source_location::current() + 272| |#endif + 273| | ); + 274| | + 275| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 276| | std::source_location location; + 277| |#endif + 278| |}; + 279| | + 280| | + 281| |/// Value conversion failed, e.g. when converting "Hello" to int. + 282| |struct PQXX_LIBEXPORT conversion_error : std::domain_error + 283| |{ + 284| | explicit conversion_error( + 285| | std::string const & + 286| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 287| | , + 288| | std::source_location = std::source_location::current() + 289| |#endif + 290| | ); + 291| | + 292| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 293| | std::source_location location; + 294| |#endif + 295| |}; + 296| | + 297| | + 298| |/// Could not convert null value: target type does not support null. + 299| |struct PQXX_LIBEXPORT unexpected_null : conversion_error + 300| |{ + 301| | explicit unexpected_null( + 302| | std::string const & + 303| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 304| | , + 305| | std::source_location = std::source_location::current() + 306| |#endif + 307| | ); + 308| |}; + 309| | + 310| | + 311| |/// Could not convert value to string: not enough buffer space. + 312| |struct PQXX_LIBEXPORT conversion_overrun : conversion_error + 313| |{ + 314| | explicit conversion_overrun( + 315| | std::string const & + 316| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 317| | , + 318| | std::source_location = std::source_location::current() + 319| |#endif + 320| | ); + 321| |}; + 322| | + 323| | + 324| |/// Something is out of range, similar to std::out_of_range + 325| |struct PQXX_LIBEXPORT range_error : std::out_of_range + 326| |{ + 327| | explicit range_error( + 328| | std::string const & + 329| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 330| | , + 331| | std::source_location = std::source_location::current() + 332| |#endif + 333| | ); + 334| | + 335| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 336| | std::source_location location; + 337| |#endif + 338| |}; + 339| | + 340| | + 341| |/// Query returned an unexpected number of rows. + 342| |struct PQXX_LIBEXPORT unexpected_rows : public range_error + 343| |{ + 344| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 345| | explicit unexpected_rows( + 346| | std::string const &msg, + 347| | std::source_location loc = std::source_location::current()) : + 348| | range_error{msg, loc} + 349| 0| {} + 350| |#else + 351| | explicit unexpected_rows(std::string const &msg) : range_error{msg} {} + 352| |#endif + 353| |}; + 354| | + 355| | + 356| |/// Database feature not supported in current setup. + 357| |struct PQXX_LIBEXPORT feature_not_supported : sql_error + 358| |{ + 359| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 360| | explicit feature_not_supported( + 361| | std::string const &err, std::string const &Q = "", + 362| | char const sqlstate[] = nullptr, + 363| | std::source_location loc = std::source_location::current()) : + 364| | sql_error{err, Q, sqlstate, loc} + 365| 0| {} + 366| |#else + 367| | explicit feature_not_supported( + 368| | std::string const &err, std::string const &Q = "", + 369| | char const sqlstate[] = nullptr) : + 370| | sql_error{err, Q, sqlstate} + 371| | {} + 372| |#endif + 373| |}; + 374| | + 375| |/// Error in data provided to SQL statement. + 376| |struct PQXX_LIBEXPORT data_exception : sql_error + 377| |{ + 378| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 379| | explicit data_exception( + 380| | std::string const &err, std::string const &Q = "", + 381| | char const sqlstate[] = nullptr, + 382| | std::source_location loc = std::source_location::current()) : + 383| | sql_error{err, Q, sqlstate, loc} + 384| 0| {} + 385| |#else + 386| | explicit data_exception( + 387| | std::string const &err, std::string const &Q = "", + 388| | char const sqlstate[] = nullptr) : + 389| | sql_error{err, Q, sqlstate} + 390| | {} + 391| |#endif + 392| |}; + 393| | + 394| |struct PQXX_LIBEXPORT integrity_constraint_violation : sql_error + 395| |{ + 396| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 397| | explicit integrity_constraint_violation( + 398| | std::string const &err, std::string const &Q = "", + 399| | char const sqlstate[] = nullptr, + 400| | std::source_location loc = std::source_location::current()) : + 401| | sql_error{err, Q, sqlstate, loc} + 402| 0| {} + 403| |#else + 404| | explicit integrity_constraint_violation( + 405| | std::string const &err, std::string const &Q = "", + 406| | char const sqlstate[] = nullptr) : + 407| | sql_error{err, Q, sqlstate} + 408| | {} + 409| |#endif + 410| |}; + 411| | + 412| |struct PQXX_LIBEXPORT restrict_violation : integrity_constraint_violation + 413| |{ + 414| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 415| | explicit restrict_violation( + 416| | std::string const &err, std::string const &Q = "", + 417| | char const sqlstate[] = nullptr, + 418| | std::source_location loc = std::source_location::current()) : + 419| | integrity_constraint_violation{err, Q, sqlstate, loc} + 420| 0| {} + 421| |#else + 422| | explicit restrict_violation( + 423| | std::string const &err, std::string const &Q = "", + 424| | char const sqlstate[] = nullptr) : + 425| | integrity_constraint_violation{err, Q, sqlstate} + 426| | {} + 427| |#endif + 428| |}; + 429| | + 430| |struct PQXX_LIBEXPORT not_null_violation : integrity_constraint_violation + 431| |{ + 432| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 433| | explicit not_null_violation( + 434| | std::string const &err, std::string const &Q = "", + 435| | char const sqlstate[] = nullptr, + 436| | std::source_location loc = std::source_location::current()) : + 437| | integrity_constraint_violation{err, Q, sqlstate, loc} + 438| 0| {} + 439| |#else + 440| | explicit not_null_violation( + 441| | std::string const &err, std::string const &Q = "", + 442| | char const sqlstate[] = nullptr) : + 443| | integrity_constraint_violation{err, Q, sqlstate} + 444| | {} + 445| |#endif + 446| |}; + 447| | + 448| |struct PQXX_LIBEXPORT foreign_key_violation : integrity_constraint_violation + 449| |{ + 450| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 451| | explicit foreign_key_violation( + 452| | std::string const &err, std::string const &Q = "", + 453| | char const sqlstate[] = nullptr, + 454| | std::source_location loc = std::source_location::current()) : + 455| | integrity_constraint_violation{err, Q, sqlstate, loc} + 456| 0| {} + 457| |#else + 458| | explicit foreign_key_violation( + 459| | std::string const &err, std::string const &Q = "", + 460| | char const sqlstate[] = nullptr) : + 461| | integrity_constraint_violation{err, Q, sqlstate} + 462| | {} + 463| |#endif + 464| |}; + 465| | + 466| |struct PQXX_LIBEXPORT unique_violation : integrity_constraint_violation + 467| |{ + 468| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 469| | explicit unique_violation( + 470| | std::string const &err, std::string const &Q = "", + 471| | char const sqlstate[] = nullptr, + 472| | std::source_location loc = std::source_location::current()) : + 473| | integrity_constraint_violation{err, Q, sqlstate, loc} + 474| 0| {} + 475| |#else + 476| | explicit unique_violation( + 477| | std::string const &err, std::string const &Q = "", + 478| | char const sqlstate[] = nullptr) : + 479| | integrity_constraint_violation{err, Q, sqlstate} + 480| | {} + 481| |#endif + 482| |}; + 483| | + 484| |struct PQXX_LIBEXPORT check_violation : integrity_constraint_violation + 485| |{ + 486| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 487| | explicit check_violation( + 488| | std::string const &err, std::string const &Q = "", + 489| | char const sqlstate[] = nullptr, + 490| | std::source_location loc = std::source_location::current()) : + 491| | integrity_constraint_violation{err, Q, sqlstate, loc} + 492| 0| {} + 493| |#else + 494| | explicit check_violation( + 495| | std::string const &err, std::string const &Q = "", + 496| | char const sqlstate[] = nullptr) : + 497| | integrity_constraint_violation{err, Q, sqlstate} + 498| | {} + 499| |#endif + 500| |}; + 501| | + 502| |struct PQXX_LIBEXPORT invalid_cursor_state : sql_error + 503| |{ + 504| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 505| | explicit invalid_cursor_state( + 506| | std::string const &err, std::string const &Q = "", + 507| | char const sqlstate[] = nullptr, + 508| | std::source_location loc = std::source_location::current()) : + 509| | sql_error{err, Q, sqlstate, loc} + 510| 0| {} + 511| |#else + 512| | explicit invalid_cursor_state( + 513| | std::string const &err, std::string const &Q = "", + 514| | char const sqlstate[] = nullptr) : + 515| | sql_error{err, Q, sqlstate} + 516| | {} + 517| |#endif + 518| |}; + 519| | + 520| |struct PQXX_LIBEXPORT invalid_sql_statement_name : sql_error + 521| |{ + 522| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 523| | explicit invalid_sql_statement_name( + 524| | std::string const &err, std::string const &Q = "", + 525| | char const sqlstate[] = nullptr, + 526| | std::source_location loc = std::source_location::current()) : + 527| | sql_error{err, Q, sqlstate, loc} + 528| 0| {} + 529| |#else + 530| | explicit invalid_sql_statement_name( + 531| | std::string const &err, std::string const &Q = "", + 532| | char const sqlstate[] = nullptr) : + 533| | sql_error{err, Q, sqlstate} + 534| | {} + 535| |#endif + 536| |}; + 537| | + 538| |struct PQXX_LIBEXPORT invalid_cursor_name : sql_error + 539| |{ + 540| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 541| | explicit invalid_cursor_name( + 542| | std::string const &err, std::string const &Q = "", + 543| | char const sqlstate[] = nullptr, + 544| | std::source_location loc = std::source_location::current()) : + 545| | sql_error{err, Q, sqlstate, loc} + 546| 0| {} + 547| |#else + 548| | explicit invalid_cursor_name( + 549| | std::string const &err, std::string const &Q = "", + 550| | char const sqlstate[] = nullptr) : + 551| | sql_error{err, Q, sqlstate} + 552| | {} + 553| |#endif + 554| |}; + 555| | + 556| |struct PQXX_LIBEXPORT syntax_error : sql_error + 557| |{ + 558| | /// Approximate position in string where error occurred, or -1 if unknown. + 559| | int const error_position; + 560| | + 561| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 562| | explicit syntax_error( + 563| | std::string const &err, std::string const &Q = "", + 564| | char const sqlstate[] = nullptr, int pos = -1, + 565| | std::source_location loc = std::source_location::current()) : + 566| | sql_error{err, Q, sqlstate, loc}, error_position{pos} + 567| 0| {} + 568| |#else + 569| | explicit syntax_error( + 570| | std::string const &err, std::string const &Q = "", + 571| | char const sqlstate[] = nullptr, int pos = -1) : + 572| | sql_error{err, Q, sqlstate}, error_position{pos} + 573| | {} + 574| |#endif + 575| |}; + 576| | + 577| |struct PQXX_LIBEXPORT undefined_column : syntax_error + 578| |{ + 579| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 580| | explicit undefined_column( + 581| | std::string const &err, std::string const &Q = "", + 582| | char const sqlstate[] = nullptr, + 583| | std::source_location loc = std::source_location::current()) : + 584| | // TODO: Can we get the column? + 585| | syntax_error{err, Q, sqlstate, -1, loc} + 586| 0| {} + 587| |#else + 588| | explicit undefined_column( + 589| | std::string const &err, std::string const &Q = "", + 590| | char const sqlstate[] = nullptr) : + 591| | syntax_error{err, Q, sqlstate} + 592| | {} + 593| |#endif + 594| |}; + 595| | + 596| |struct PQXX_LIBEXPORT undefined_function : syntax_error + 597| |{ + 598| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 599| | explicit undefined_function( + 600| | std::string const &err, std::string const &Q = "", + 601| | char const sqlstate[] = nullptr, + 602| | std::source_location loc = std::source_location::current()) : + 603| | // TODO: Can we get the column? + 604| | syntax_error{err, Q, sqlstate, -1, loc} + 605| 0| {} + 606| |#else + 607| | explicit undefined_function( + 608| | std::string const &err, std::string const &Q = "", + 609| | char const sqlstate[] = nullptr) : + 610| | syntax_error{err, Q, sqlstate} + 611| | {} + 612| |#endif + 613| |}; + 614| | + 615| |struct PQXX_LIBEXPORT undefined_table : syntax_error + 616| |{ + 617| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 618| | explicit undefined_table( + 619| | std::string const &err, std::string const &Q = "", + 620| | char const sqlstate[] = nullptr, + 621| | std::source_location loc = std::source_location::current()) : + 622| | // TODO: Can we get the column? + 623| | syntax_error{err, Q, sqlstate, -1, loc} + 624| 0| {} + 625| |#else + 626| | explicit undefined_table( + 627| | std::string const &err, std::string const &Q = "", + 628| | char const sqlstate[] = nullptr) : + 629| | syntax_error{err, Q, sqlstate} + 630| | {} + 631| |#endif + 632| |}; + 633| | + 634| |struct PQXX_LIBEXPORT insufficient_privilege : sql_error + 635| |{ + 636| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 637| | explicit insufficient_privilege( + 638| | std::string const &err, std::string const &Q = "", + 639| | char const sqlstate[] = nullptr, + 640| | std::source_location loc = std::source_location::current()) : + 641| | sql_error{err, Q, sqlstate, loc} + 642| 0| {} + 643| |#else + 644| | explicit insufficient_privilege( + 645| | std::string const &err, std::string const &Q = "", + 646| | char const sqlstate[] = nullptr) : + 647| | sql_error{err, Q, sqlstate} + 648| | {} + 649| |#endif + 650| |}; + 651| | + 652| |/// Resource shortage on the server + 653| |struct PQXX_LIBEXPORT insufficient_resources : sql_error + 654| |{ + 655| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 656| | explicit insufficient_resources( + 657| | std::string const &err, std::string const &Q = "", + 658| | char const sqlstate[] = nullptr, + 659| | std::source_location loc = std::source_location::current()) : + 660| | sql_error{err, Q, sqlstate, loc} + 661| 0| {} + 662| |#else + 663| | explicit insufficient_resources( + 664| | std::string const &err, std::string const &Q = "", + 665| | char const sqlstate[] = nullptr) : + 666| | sql_error{err, Q, sqlstate} + 667| | {} + 668| |#endif + 669| |}; + 670| | + 671| |struct PQXX_LIBEXPORT disk_full : insufficient_resources + 672| |{ + 673| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 674| | explicit disk_full( + 675| | std::string const &err, std::string const &Q = "", + 676| | char const sqlstate[] = nullptr, + 677| | std::source_location loc = std::source_location::current()) : + 678| | insufficient_resources{err, Q, sqlstate, loc} + 679| 0| {} + 680| |#else + 681| | explicit disk_full( + 682| | std::string const &err, std::string const &Q = "", + 683| | char const sqlstate[] = nullptr) : + 684| | insufficient_resources{err, Q, sqlstate} + 685| | {} + 686| |#endif + 687| |}; + 688| | + 689| |struct PQXX_LIBEXPORT out_of_memory : insufficient_resources + 690| |{ + 691| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 692| | explicit out_of_memory( + 693| | std::string const &err, std::string const &Q = "", + 694| | char const sqlstate[] = nullptr, + 695| | std::source_location loc = std::source_location::current()) : + 696| | insufficient_resources{err, Q, sqlstate, loc} + 697| 0| {} + 698| |#else + 699| | explicit out_of_memory( + 700| | std::string const &err, std::string const &Q = "", + 701| | char const sqlstate[] = nullptr) : + 702| | insufficient_resources{err, Q, sqlstate} + 703| | {} + 704| |#endif + 705| |}; + 706| | + 707| |struct PQXX_LIBEXPORT too_many_connections : broken_connection + 708| |{ + 709| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 710| | explicit too_many_connections( + 711| | std::string const &err, + 712| | std::source_location loc = std::source_location::current()) : + 713| | broken_connection{err, loc} + 714| 0| {} + 715| |#else + 716| | explicit too_many_connections(std::string const &err) : + 717| | broken_connection{err} + 718| | {} + 719| |#endif + 720| |}; + 721| | + 722| |/// PL/pgSQL error + 723| |/** Exceptions derived from this class are errors from PL/pgSQL procedures. + 724| | */ + 725| |struct PQXX_LIBEXPORT plpgsql_error : sql_error + 726| |{ + 727| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 728| | explicit plpgsql_error( + 729| | std::string const &err, std::string const &Q = "", + 730| | char const sqlstate[] = nullptr, + 731| | std::source_location loc = std::source_location::current()) : + 732| | sql_error{err, Q, sqlstate, loc} + 733| 0| {} + 734| |#else + 735| | explicit plpgsql_error( + 736| | std::string const &err, std::string const &Q = "", + 737| | char const sqlstate[] = nullptr) : + 738| | sql_error{err, Q, sqlstate} + 739| | {} + 740| |#endif + 741| |}; + 742| | + 743| |/// Exception raised in PL/pgSQL procedure + 744| |struct PQXX_LIBEXPORT plpgsql_raise : plpgsql_error + 745| |{ + 746| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 747| | explicit plpgsql_raise( + 748| | std::string const &err, std::string const &Q = "", + 749| | char const sqlstate[] = nullptr, + 750| | std::source_location loc = std::source_location::current()) : + 751| | plpgsql_error{err, Q, sqlstate, loc} + 752| 0| {} + 753| |#else + 754| | explicit plpgsql_raise( + 755| | std::string const &err, std::string const &Q = "", + 756| | char const sqlstate[] = nullptr) : + 757| | plpgsql_error{err, Q, sqlstate} + 758| | {} + 759| |#endif + 760| |}; + 761| | + 762| |struct PQXX_LIBEXPORT plpgsql_no_data_found : plpgsql_error + 763| |{ + 764| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 765| | explicit plpgsql_no_data_found( + 766| | std::string const &err, std::string const &Q = "", + 767| | char const sqlstate[] = nullptr, + 768| | std::source_location loc = std::source_location::current()) : + 769| | plpgsql_error{err, Q, sqlstate, loc} + 770| 0| {} + 771| |#else + 772| | explicit plpgsql_no_data_found( + 773| | std::string const &err, std::string const &Q = "", + 774| | char const sqlstate[] = nullptr) : + 775| | plpgsql_error{err, Q, sqlstate} + 776| | {} + 777| |#endif + 778| |}; + 779| | + 780| |struct PQXX_LIBEXPORT plpgsql_too_many_rows : plpgsql_error + 781| |{ + 782| |#if defined(PQXX_HAVE_SOURCE_LOCATION) + 783| | explicit plpgsql_too_many_rows( + 784| | std::string const &err, std::string const &Q = "", + 785| | char const sqlstate[] = nullptr, + 786| | std::source_location loc = std::source_location::current()) : + 787| | plpgsql_error{err, Q, sqlstate, loc} + 788| 0| {} + 789| |#else + 790| | explicit plpgsql_too_many_rows( + 791| | std::string const &err, std::string const &Q = "", + 792| | char const sqlstate[] = nullptr) : + 793| | plpgsql_error{err, Q, sqlstate} + 794| | {} + 795| |#endif + 796| |}; + 797| | + 798| |/** + 799| | * @} + 800| | */ + 801| |} // namespace pqxx + 802| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/field.hxx: + 1| |/* Definitions for the pqxx::field class. + 2| | * + 3| | * pqxx::field refers to a field in a query result. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/field instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_FIELD + 14| |#define PQXX_H_FIELD + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include + 21| | + 22| |#include "pqxx/array.hxx" + 23| |#include "pqxx/composite.hxx" + 24| |#include "pqxx/result.hxx" + 25| |#include "pqxx/strconv.hxx" + 26| |#include "pqxx/types.hxx" + 27| | + 28| |namespace pqxx + 29| |{ + 30| |/// Reference to a field in a result set. + 31| |/** A field represents one entry in a row. It represents an actual value + 32| | * in the result set, and can be converted to various types. + 33| | */ + 34| |class PQXX_LIBEXPORT field + 35| |{ + 36| |public: + 37| | using size_type = field_size_type; + 38| | + 39| | /** + 40| | * @name Comparison + 41| | */ + 42| | //@{ + 43| | /// Byte-by-byte comparison of two fields (all nulls are considered equal) + 44| | /** @warning null handling is still open to discussion and change! + 45| | * + 46| | * Handling of null values differs from that in SQL where a comparison + 47| | * involving a null value yields null, so nulls are never considered equal + 48| | * to one another or even to themselves. + 49| | * + 50| | * Null handling also probably differs from the closest equivalent in C++, + 51| | * which is the NaN (Not-a-Number) value, a singularity comparable to + 52| | * SQL's null. This is because the builtin == operator demands that a == a. + 53| | * + 54| | * The usefulness of this operator is questionable. No interpretation + 55| | * whatsoever is imposed on the data; 0 and 0.0 are considered different, + 56| | * as are null vs. the empty string, or even different (but possibly + 57| | * equivalent and equally valid) encodings of the same Unicode character + 58| | * etc. + 59| | */ + 60| | [[nodiscard]] PQXX_PURE bool operator==(field const &) const noexcept; + 61| | + 62| | /// Byte-by-byte comparison (all nulls are considered equal) + 63| | /** @warning See operator==() for important information about this operator + 64| | */ + 65| | [[nodiscard]] PQXX_PURE bool operator!=(field const &rhs) const noexcept + 66| 0| { + 67| 0| return not operator==(rhs); + 68| 0| } + 69| | //@} + 70| | + 71| | /** + 72| | * @name Column information + 73| | */ + 74| | //@{ + 75| | /// Column name. + 76| | [[nodiscard]] PQXX_PURE char const *name() const &; + 77| | + 78| | /// Column type. + 79| | [[nodiscard]] oid PQXX_PURE type() const; + 80| | + 81| | /// What table did this column come from? + 82| | [[nodiscard]] PQXX_PURE oid table() const; + 83| | + 84| | /// Return row number. The first row is row 0, the second is row 1, etc. + 85| 0| PQXX_PURE constexpr row_size_type num() const noexcept { return col(); } + 86| | + 87| | /// What column number in its originating table did this column come from? + 88| | [[nodiscard]] PQXX_PURE row_size_type table_column() const; + 89| | //@} + 90| | + 91| | /** + 92| | * @name Content access + 93| | * + 94| | * You can read a field as any C++ type for which a conversion from + 95| | * PostgreSQL's text format is defined. See @ref datatypes for how this + 96| | * works. This mechanism is _weakly typed:_ the conversions do not care + 97| | * what SQL type a field had in the database, only that its actual contents + 98| | * convert to the target type without problems. So for instance, you can + 99| | * read a `text` field as an `int`, so long as the string in the field spells + 100| | * out a valid `int` number. + 101| | * + 102| | * Many built-in types come with conversions predefined. To find out how to + 103| | * add your own, see @ref datatypes. + 104| | */ + 105| | //@{ + 106| | /// Read as `string_view`, or an empty one if null. + 107| | /** The result only remains usable while the data for the underlying + 108| | * @ref result exists. Once all `result` objects referring to that data have + 109| | * been destroyed, the `string_view` will no longer point to valid memory. + 110| | */ + 111| | [[nodiscard]] PQXX_PURE std::string_view view() const & + 112| 0| { + 113| 0| return std::string_view(c_str(), size()); + 114| 0| } + 115| | + 116| | /// Read as plain C string. + 117| | /** Since the field's data is stored internally in the form of a + 118| | * zero-terminated C string, this is the fastest way to read it. Use the + 119| | * to() or as() functions to convert the string to other types such as + 120| | * `int`, or to C++ strings. + 121| | * + 122| | * Do not use this for BYTEA values, or other binary values. To read those, + 123| | * convert the value to your desired type using `to()` or `as()`. For + 124| | * example: `f.as()`. + 125| | */ + 126| | [[nodiscard]] PQXX_PURE char const *c_str() const &; + 127| | + 128| | /// Is this field's value null? + 129| | [[nodiscard]] PQXX_PURE bool is_null() const noexcept; + 130| | + 131| | /// Return number of bytes taken up by the field's value. + 132| | [[nodiscard]] PQXX_PURE size_type size() const noexcept; + 133| | + 134| | /// Read value into obj; or if null, leave obj untouched and return `false`. + 135| | /** This can be used with optional types (except pointers other than C-style + 136| | * strings). + 137| | */ + 138| | template + 139| | auto to(T &obj) const -> + 140| | typename std::enable_if_t< + 141| | (not std::is_pointer::value or std::is_same::value), + 142| | bool> + 143| | { + 144| | if (is_null()) + 145| | { + 146| | return false; + 147| | } + 148| | else + 149| | { + 150| | auto const data{c_str()}; + 151| | from_string(data, obj); + 152| | return true; + 153| | } + 154| | } + 155| | + 156| | /// Read field as a composite value, write its components into `fields`. + 157| | /** @warning This is still experimental. It may change or be replaced. + 158| | * + 159| | * Returns whether the field was null. If it was, it will not touch the + 160| | * values in `fields`. + 161| | */ + 162| | template bool composite_to(T &...fields) const + 163| | { + 164| | if (is_null()) + 165| | { + 166| | return false; + 167| | } + 168| | else + 169| | { + 170| | parse_composite(m_home.m_encoding, view(), fields...); + 171| | return true; + 172| | } + 173| | } + 174| | + 175| | /// Read value into obj; or leave obj untouched and return `false` if null. + 176| | template bool operator>>(T &obj) const { return to(obj); } + 177| | + 178| | /// Read value into obj; or if null, use default value and return `false`. + 179| | /** This can be used with `std::optional`, as well as with standard smart + 180| | * pointer types, but not with raw pointers. If the conversion from a + 181| | * PostgreSQL string representation allocates a pointer (e.g. using `new`), + 182| | * then the object's later deallocation should be baked in as well, right + 183| | * from the point where the object is created. So if you want a pointer, use + 184| | * a smart pointer, not a raw pointer. + 185| | * + 186| | * There is one exception, of course: C-style strings. Those are just + 187| | * pointers to the field's internal text data. + 188| | */ + 189| | template + 190| | auto to(T &obj, T const &default_value) const -> + 191| | typename std::enable_if_t< + 192| | (not std::is_pointer::value or std::is_same::value), + 193| | bool> + 194| | { + 195| | bool const null{is_null()}; + 196| | if (null) + 197| | obj = default_value; + 198| | else + 199| | obj = from_string(this->view()); + 200| | return not null; + 201| | } + 202| | + 203| | /// Return value as object of given type, or default value if null. + 204| | /** Note that unless the function is instantiated with an explicit template + 205| | * argument, the Default value's type also determines the result type. + 206| | */ + 207| | template T as(T const &default_value) const + 208| | { + 209| | if (is_null()) + 210| | return default_value; + 211| | else + 212| | return from_string(this->view()); + 213| | } + 214| | + 215| | /// Return value as object of given type, or throw exception if null. + 216| | /** Use as `as>()` or `as()` as + 217| | * an alternative to `get()`; this is disabled for use with raw pointers + 218| | * (other than C-strings) because storage for the value can't safely be + 219| | * allocated here + 220| | */ + 221| | template T as() const + 222| 0| { + 223| 0| if (is_null()) + 224| 0| { + 225| 0| if constexpr (not nullness::has_null) + 226| 0| internal::throw_null_conversion(type_name); + 227| 0| else + 228| 0| return nullness::null(); + 229| 0| } + 230| 0| else + 231| 0| { + 232| 0| return from_string(this->view()); + 233| 0| } + 234| 0| } + ------------------ + | Unexecuted instantiation: _ZNK4pqxx5field2asIdEET_v + ------------------ + | Unexecuted instantiation: _ZNK4pqxx5field2asINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEET_v + ------------------ + 235| | + 236| | /// Return value wrapped in some optional type (empty for nulls). + 237| | /** Use as `get()` as before to obtain previous behavior, or specify + 238| | * container type with `get()` + 239| | */ + 240| | template class O = std::optional> + 241| | constexpr O get() const + 242| | { + 243| | return as>(); + 244| | } + 245| | + 246| | /// Read SQL array contents as a @ref pqxx::array. + 247| | template + 248| | array as_sql_array() const + 249| | { + 250| | using array_type = array; + 251| | + 252| | // There's no such thing as a null SQL array. + 253| | if (is_null()) + 254| | internal::throw_null_conversion(type_name); + 255| | else + 256| | return array_type{this->view(), this->m_home.m_encoding}; + 257| | } + 258| | + 259| | /// Parse the field as an SQL array. + 260| | /** Call the parser to retrieve values (and structure) from the array. + 261| | * + 262| | * Make sure the @ref result object stays alive until parsing is finished. If + 263| | * you keep the @ref row of `field` object alive, it will keep the @ref + 264| | * result object alive as well. + 265| | */ + 266| | [[deprecated( + 267| | "Avoid pqxx::array_parser. " + 268| | "Instead, use as_sql_array() to convert to pqxx::array.")]] + 269| | array_parser as_array() const & noexcept + 270| 0| { + 271| 0| return array_parser{c_str(), m_home.m_encoding}; + 272| 0| } + 273| | //@} + 274| | + 275| | /// Constructor. Do not call this yourself; libpqxx will do it for you. + 276| | /** Create field as reference to a field in a result set. + 277| | * @param r Row that this field is part of. + 278| | * @param c Column number of this field. + 279| | */ + 280| | [[deprecated( + 281| | "Do not construct fields yourself. Get them from the row.")]] field(row const &r, row_size_type c) noexcept; + 282| | + 283| | /// Constructor. Do not call this yourself; libpqxx will do it for you. + 284| | [[deprecated( + 285| | "Do not construct fields yourself. Get them from the " + 286| | "row.")]] field() noexcept = default; + 287| | + 288| | + 289| |protected: + 290| 0| constexpr result const &home() const noexcept { return m_home; } + 291| 0| constexpr result::size_type idx() const noexcept { return m_row; } + 292| 0| constexpr row_size_type col() const noexcept { return m_col; } + 293| | + 294| | // TODO: Create gates. + 295| | friend class pqxx::result; + 296| | friend class pqxx::row; + 297| | field( + 298| | result const &r, result_size_type row_num, row_size_type col_num) noexcept + 299| | : + 300| | m_col{col_num}, m_home{r}, m_row{row_num} + 301| 0| {} + 302| | + 303| | /** + 304| | * You'd expect this to be unsigned, but due to the way reverse iterators + 305| | * are related to regular iterators, it must be allowed to underflow to -1. + 306| | */ + 307| | row_size_type m_col; + 308| | + 309| |private: + 310| | result m_home; + 311| | result::size_type m_row; + 312| |}; + 313| | + 314| | + 315| |template<> inline bool field::to(std::string &obj) const + 316| 0|{ + 317| 0| bool const null{is_null()}; + 318| 0| if (not null) + 319| 0| obj = std::string{view()}; + 320| 0| return not null; + 321| 0|} + 322| | + 323| | + 324| |template<> + 325| |inline bool field::to( + 326| | std::string &obj, std::string const &default_value) const + 327| 0|{ + 328| 0| bool const null{is_null()}; + 329| 0| if (null) + 330| 0| obj = default_value; + 331| 0| else + 332| 0| obj = std::string{view()}; + 333| 0| return not null; + 334| 0|} + 335| | + 336| | + 337| |/// Specialization: `to(char const *&)`. + 338| |/** The buffer has the same lifetime as the data in this result (i.e. of this + 339| | * result object, or the last remaining one copied from it etc.), so take care + 340| | * not to use it after the last result object referring to this query result is + 341| | * destroyed. + 342| | */ + 343| |template<> inline bool field::to(char const *&obj) const + 344| 0|{ + 345| 0| bool const null{is_null()}; + 346| 0| if (not null) + 347| 0| obj = c_str(); + 348| 0| return not null; + 349| 0|} + 350| | + 351| | + 352| |template<> inline bool field::to(std::string_view &obj) const + 353| 0|{ + 354| 0| bool const null{is_null()}; + 355| 0| if (not null) + 356| 0| obj = view(); + 357| 0| return not null; + 358| 0|} + 359| | + 360| | + 361| |template<> + 362| |inline bool field::to( + 363| | std::string_view &obj, std::string_view const &default_value) const + 364| 0|{ + 365| 0| bool const null{is_null()}; + 366| 0| if (null) + 367| 0| obj = default_value; + 368| 0| else + 369| 0| obj = view(); + 370| 0| return not null; + 371| 0|} + 372| | + 373| | + 374| |template<> inline std::string_view field::as() const + 375| 0|{ + 376| 0| if (is_null()) + 377| 0| PQXX_UNLIKELY + 378| 0| internal::throw_null_conversion(type_name); + 379| 0| return view(); + 380| 0|} + 381| | + 382| | + 383| |template<> + 384| |inline std::string_view + 385| |field::as(std::string_view const &default_value) const + 386| 0|{ + 387| 0| return is_null() ? default_value : view(); + 388| 0|} + 389| | + 390| | + 391| |template<> inline bool field::to(zview &obj) const + 392| 0|{ + 393| 0| bool const null{is_null()}; + 394| 0| if (not null) + 395| 0| obj = zview{c_str(), size()}; + 396| 0| return not null; + 397| 0|} + 398| | + 399| | + 400| |template<> + 401| |inline bool field::to(zview &obj, zview const &default_value) const + 402| 0|{ + 403| 0| bool const null{is_null()}; + 404| 0| if (null) + 405| 0| obj = default_value; + 406| 0| else + 407| 0| obj = zview{c_str(), size()}; + 408| 0| return not null; + 409| 0|} + 410| | + 411| | + 412| |template<> inline zview field::as() const + 413| 0|{ + 414| 0| if (is_null()) + 415| 0| PQXX_UNLIKELY + 416| 0| internal::throw_null_conversion(type_name); + 417| 0| return zview{c_str(), size()}; + 418| 0|} + 419| | + 420| | + 421| |template<> inline zview field::as(zview const &default_value) const + 422| 0|{ + 423| 0| return is_null() ? default_value : zview{c_str(), size()}; + 424| 0|} + 425| | + 426| | + 427| |template> + 428| |class field_streambuf : public std::basic_streambuf + 429| |{ + 430| |public: + 431| | using char_type = CHAR; + 432| | using traits_type = TRAITS; + 433| | using int_type = typename traits_type::int_type; + 434| | using pos_type = typename traits_type::pos_type; + 435| | using off_type = typename traits_type::off_type; + 436| | using openmode = std::ios::openmode; + 437| | using seekdir = std::ios::seekdir; + 438| | + 439| | explicit field_streambuf(field const &f) : m_field{f} { initialize(); } + 440| | + 441| |protected: + 442| | virtual int sync() override { return traits_type::eof(); } + 443| | + 444| | virtual pos_type seekoff(off_type, seekdir, openmode) override + 445| | { + 446| | return traits_type::eof(); + 447| | } + 448| | virtual pos_type seekpos(pos_type, openmode) override + 449| | { + 450| | return traits_type::eof(); + 451| | } + 452| | virtual int_type overflow(int_type) override { return traits_type::eof(); } + 453| | virtual int_type underflow() override { return traits_type::eof(); } + 454| | + 455| |private: + 456| | field const &m_field; + 457| | + 458| | int_type initialize() + 459| | { + 460| | auto g{static_cast(const_cast(m_field.c_str()))}; + 461| | this->setg(g, g, g + std::size(m_field)); + 462| | return int_type(std::size(m_field)); + 463| | } + 464| |}; + 465| | + 466| | + 467| |/// Input stream that gets its data from a result field + 468| |/** @deprecated To convert a field's value string to some other type, e.g. to + 469| | * an `int`, use the field's `as<...>()` member function. To read a field + 470| | * efficiently just as a string, use its `c_str()` or its + 471| | * `as()`. + 472| | * + 473| | * Works like any other istream to read data from a field. It supports all + 474| | * formatting and streaming operations of `std::istream`. For convenience + 475| | * there is a fieldstream alias, which defines a @ref basic_fieldstream for + 476| | * `char`. This is similar to how e.g. `std::ifstream` relates to + 477| | * `std::basic_ifstream`. + 478| | * + 479| | * This class has only been tested for the char type (and its default traits). + 480| | */ + 481| |template> + 482| |class basic_fieldstream : public std::basic_istream + 483| |{ + 484| | using super = std::basic_istream; + 485| | + 486| |public: + 487| | using char_type = CHAR; + 488| | using traits_type = TRAITS; + 489| | using int_type = typename traits_type::int_type; + 490| | using pos_type = typename traits_type::pos_type; + 491| | using off_type = typename traits_type::off_type; + 492| | + 493| | [[deprecated("Use field::as<...>() or field::c_str().")]] basic_fieldstream( + 494| | field const &f) : + 495| | super{nullptr}, m_buf{f} + 496| | { + 497| | super::init(&m_buf); + 498| | } + 499| | + 500| |private: + 501| | field_streambuf m_buf; + 502| |}; + 503| | + 504| | + 505| |/// @deprecated Read a field using `field::as<...>()` or `field::c_str()`. + 506| |using fieldstream = basic_fieldstream; + 507| | + 508| | + 509| |/// Write a result field to any type of stream. + 510| |/** @deprecated The C++ streams library is not great to work with. In + 511| | * particular, error handling is easy to get wrong. So you're probably better + 512| | * off doing this by hand. + 513| | * + 514| | * This can be convenient when writing a field to an output stream. More + 515| | * importantly, it lets you write a field to e.g. a `stringstream` which you + 516| | * can then use to read, format and convert the field in ways that to() does + 517| | * not support. + 518| | * + 519| | * Example: parse a field into a variable of the nonstandard `long long` type. + 520| | * + 521| | * ```cxx + 522| | * extern result R; + 523| | * long long L; + 524| | * stringstream S; + 525| | * + 526| | * // Write field's string into S + 527| | * S << R[0][0]; + 528| | * + 529| | * // Parse contents of S into L + 530| | * S >> L; + 531| | * ``` + 532| | */ + 533| |template + 534| |[[deprecated( + 535| | "Do this by hand, probably with better error checking.")]] inline std:: + 536| | basic_ostream & + 537| | operator<<(std::basic_ostream &s, field const &value) + 538| |{ + 539| | s.write(value.c_str(), std::streamsize(std::size(value))); + 540| | return s; + 541| |} + 542| | + 543| | + 544| |/// Convert a field's value to type `T`. + 545| |/** Unlike the "regular" `from_string`, this knows how to deal with null + 546| | * values. + 547| | */ + 548| |template inline T from_string(field const &value) + 549| |{ + 550| | if (value.is_null()) + 551| | { + 552| | if constexpr (nullness::has_null) + 553| | return nullness::null(); + 554| | else + 555| | internal::throw_null_conversion(type_name); + 556| | } + 557| | else + 558| | { + 559| | return from_string(value.view()); + 560| | } + 561| |} + 562| | + 563| | + 564| |/// Convert a field's value to `nullptr_t`. + 565| |/** Yes, you read that right. This conversion does nothing useful. It always + 566| | * returns `nullptr`. + 567| | * + 568| | * Except... what if the field is not null? In that case, this throws + 569| | * @ref conversion_error. + 570| | */ + 571| |template<> + 572| |inline std::nullptr_t from_string(field const &value) + 573| 0|{ + 574| 0| if (not value.is_null()) + 575| 0| throw conversion_error{ + 576| 0| "Extracting non-null field into nullptr_t variable."}; + 577| 0| return nullptr; + 578| 0|} + 579| | + 580| | + 581| |/// Convert a field to a string. + 582| |template<> PQXX_LIBEXPORT std::string to_string(field const &value); + 583| |} // namespace pqxx + 584| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/internal/callgate.hxx: + 1| |#ifndef PQXX_H_CALLGATE + 2| |#define PQXX_H_CALLGATE + 3| | + 4| |/* + 5| |Here's what a typical gate class definition looks like: + 6| | + 7| |```cxx + 8| |#include + 9| | + 10| |namespace pqxx::internal::gate + 11| |{ + 12| |class PQXX_PRIVATE @gateclass@ : callgate<@host@> + 13| |{ + 14| | friend class @client@; + 15| | + 16| | @gateclass@(reference x) : super(x) {} + 17| | + 18| | // Methods here. Use home() to access the host-class object. + 19| |}; + 20| |} // namespace pqxx::internal::gate + 21| |``` + 22| |*/ + 23| | + 24| |namespace pqxx::internal + 25| |{ + 26| |/// Base class for call gates. + 27| |/** + 28| | * A call gate defines a limited, private interface on the host class that + 29| | * specified client classes can access. + 30| | * + 31| | * The metaphor works as follows: the gate stands in front of a "home," which + 32| | * is really a class, and only lets specific friends in. + 33| | * + 34| | * To implement a call gate that gives client C access to host H, + 35| | * * derive a gate class from callgate; + 36| | * * make the gate class a friend of H; + 37| | * * make C a friend of the gate class; and + 38| | * * implement "stuff C can do with H" as private members in the gate class. + 39| | * + 40| | * This special kind of "gated" friendship gives C private access to H, but + 41| | * only through an expressly limited interface. The gate class can access its + 42| | * host object as home(). + 43| | * + 44| | * Keep gate classes entirely stateless. They should be ultra-lightweight + 45| | * wrappers for their host classes, and be optimized away as much as possible + 46| | * by the compiler. Once you start adding state, you're on a slippery slope + 47| | * away from the pure, clean, limited interface pattern that gate classes are + 48| | * meant to implement. + 49| | * + 50| | * Ideally, all member functions of the gate class should be one-liners passing + 51| | * calls straight on to the host class. It can be useful however to break this + 52| | * rule temporarily during inter-class refactoring. + 53| | */ + 54| |template class PQXX_PRIVATE callgate + 55| |{ + 56| |protected: + 57| | /// This class, to keep constructors easy. + 58| | using super = callgate; + 59| | /// A reference to the host class. Helps keep constructors easy. + 60| | using reference = HOME &; + 61| | + 62| | callgate(reference x) : m_home(x) {} + 63| | + 64| | /// The home object. The gate class has full "private" access. + 65| 0| reference home() const noexcept { return m_home; } + 66| | + 67| |private: + 68| | reference m_home; + 69| |}; + 70| |} // namespace pqxx::internal + 71| | + 72| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/internal/concat.hxx: + 1| |#if !defined(PQXX_CONCAT_HXX) + 2| |# define PQXX_CONCAT_HXX + 3| | + 4| |# include + 5| |# include + 6| | + 7| |# include "pqxx/strconv.hxx" + 8| | + 9| |namespace pqxx::internal + 10| |{ + 11| |/// Convert item to a string, write it into [here, end). + 12| |template + 13| |void render_item(TYPE const &item, char *&here, char *end) + 14| 0|{ + 15| 0| auto const next = string_traits::into_buf(here, end, item) - 1; + 16| 0| PQXX_ASSUME(next >= here); + 17| 0| here = next; + 18| 0|} + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal11render_itemIPKcEEvRKT_RPcS7_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal11render_itemIiEEvRKT_RPcS5_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal11render_itemINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEEvRKT_RPcSC_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal11render_itemImEEvRKT_RPcS5_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal11render_itemINS0_14encoding_groupEEEvRKT_RPcS6_ + ------------------ + 19| | + 20| | + 21| |// C++20: Support non-random_access_range ranges. + 22| |/// Efficiently combine a bunch of items into one big string. + 23| |/** Use this as an optimised version of string concatentation. It takes just + 24| | * about any type; it will represent each item as a string according to its + 25| | * @ref string_traits. + 26| | * + 27| | * This is a simpler, more specialised version of @ref separated_list for a + 28| | * statically known series of items, possibly of different types. + 29| | */ + 30| |template + 31| |[[nodiscard]] inline std::string concat(TYPE... item) + 32| 0|{ + 33| 0| std::string buf; + 34| 0| // Size to accommodate string representations of all inputs, minus their + 35| 0| // terminating zero bytes. + 36| 0| buf.resize(size_buffer(item...)); + 37| 0| + 38| 0| char *const data{buf.data()}; + 39| 0| char *here = data; + 40| 0| char *end = data + std::size(buf); + 41| 0| (render_item(item, here, end), ...); + 42| 0| + 43| 0| buf.resize(static_cast(here - data)); + 44| 0| return buf; + 45| 0|} + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal6concatIJPKciS3_iS3_EEENSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEDpT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal6concatIJPKciS3_NSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEES3_iS3_EEESA_DpT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal6concatIJPKciS3_EEENSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEDpT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal6concatIJPKcNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEES3_iS3_EEESA_DpT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal6concatIJPKcmS3_mS3_mS3_EEENSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEDpT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal6concatIJPKcNS0_14encoding_groupES3_S4_S3_EEENSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEDpT_ + ------------------ + 46| |} // namespace pqxx::internal + 47| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/internal/conversions.hxx: + 1| |#include + 2| |#include + 3| |#include + 4| |#include + 5| |#include + 6| |#include + 7| | + 8| |#if defined(PQXX_HAVE_SPAN) && __has_include() + 9| |# include + 10| |#endif + 11| | + 12| |#include + 13| |#include + 14| |#include + 15| | + 16| |#include "pqxx/types.hxx" + 17| |#include "pqxx/util.hxx" + 18| | + 19| | + 20| |/* Internal helpers for string conversion, and conversion implementations. + 21| | * + 22| | * Do not include this header directly. The libpqxx headers do it for you. + 23| | */ + 24| |namespace pqxx::internal + 25| |{ + 26| |/// Convert a number in [0, 9] to its ASCII digit. + 27| |inline constexpr char number_to_digit(int i) noexcept + 28| 0|{ + 29| 0| return static_cast(i + '0'); + 30| 0|} + 31| | + 32| | + 33| |/// Compute numeric value of given textual digit (assuming that it is a digit). + 34| |constexpr int digit_to_number(char c) noexcept + 35| 0|{ + 36| 0| return c - '0'; + 37| 0|} + 38| | + 39| | + 40| |/// Summarize buffer overrun. + 41| |/** Don't worry about the exact parameter types: the sizes will be reasonably + 42| | * small, and nonnegative. + 43| | */ + 44| |std::string PQXX_LIBEXPORT + 45| |state_buffer_overrun(int have_bytes, int need_bytes); + 46| | + 47| | + 48| |template + 49| |inline std::string state_buffer_overrun(HAVE have_bytes, NEED need_bytes) + 50| 0|{ + 51| 0| return state_buffer_overrun( + 52| 0| static_cast(have_bytes), static_cast(need_bytes)); + 53| 0|} + 54| | + 55| | + 56| |/// Throw exception for attempt to convert SQL NULL to given type. + 57| |[[noreturn]] PQXX_LIBEXPORT PQXX_COLD void + 58| |throw_null_conversion(std::string const &type); + 59| | + 60| | + 61| |/// Throw exception for attempt to convert SQL NULL to given type. + 62| |[[noreturn]] PQXX_LIBEXPORT PQXX_COLD void + 63| |throw_null_conversion(std::string_view type); + 64| | + 65| | + 66| |/// Deliberately nonfunctional conversion traits for `char` types. + 67| |/** There are no string conversions for `char` and its signed and unsigned + 68| | * variants. Such a conversion would be dangerously ambiguous: should we treat + 69| | * it as text, or as a small integer? It'd be an open invitation for bugs. + 70| | * + 71| | * But the error message when you get this wrong is very cryptic. So, we + 72| | * derive dummy @ref string_traits implementations from this dummy type, and + 73| | * ensure that the compiler disallows their use. The compiler error message + 74| | * will at least contain a hint of the root of the problem. + 75| | */ + 76| |template struct disallowed_ambiguous_char_conversion + 77| |{ + 78| | static constexpr bool converts_to_string{false}; + 79| | static constexpr bool converts_from_string{false}; + 80| | static char *into_buf(char *, char *, CHAR_TYPE) = delete; + 81| | static constexpr zview + 82| | to_buf(char *, char *, CHAR_TYPE const &) noexcept = delete; + 83| | + 84| | static constexpr std::size_t + 85| | size_buffer(CHAR_TYPE const &) noexcept = delete; + 86| | static CHAR_TYPE from_string(std::string_view) = delete; + 87| |}; + 88| | + 89| | + 90| |template PQXX_LIBEXPORT extern std::string to_string_float(T); + 91| | + 92| | + 93| |/// Generic implementation for into_buf, on top of to_buf. + 94| |template + 95| |inline char *generic_into_buf(char *begin, char *end, T const &value) + 96| 0|{ + 97| 0| zview const text{string_traits::to_buf(begin, end, value)}; + 98| 0| auto const space{end - begin}; + 99| 0| // Include the trailing zero. + 100| 0| auto const len = std::size(text) + 1; + 101| 0| if (internal::cmp_greater(len, space)) + 102| 0| throw conversion_overrun{ + 103| 0| "Not enough buffer space to insert " + type_name + ". " + + 104| 0| state_buffer_overrun(space, len)}; + 105| 0| std::memmove(begin, text.data(), len); + 106| 0| return begin + len; + 107| 0|} + 108| | + 109| | + 110| |// C++20: Guard with concept? + 111| |/// String traits for builtin integral types (though not bool). + 112| |template struct integral_traits + 113| |{ + 114| | static constexpr bool converts_to_string{true}; + 115| | static constexpr bool converts_from_string{true}; + 116| | static PQXX_LIBEXPORT T from_string(std::string_view text); + 117| | static PQXX_LIBEXPORT zview to_buf(char *begin, char *end, T const &value); + 118| | static PQXX_LIBEXPORT char *into_buf(char *begin, char *end, T const &value); + 119| | + 120| | static constexpr std::size_t size_buffer(T const &) noexcept + 121| 0| { + 122| 0| /** Includes a sign if needed; the number of base-10 digits which the type + 123| 0| * can reliably represent; the one extra base-10 digit which the type can + 124| 0| * only partially represent; and the terminating zero. + 125| 0| */ + 126| 0| return std::is_signed_v + std::numeric_limits::digits10 + 1 + 1; + 127| 0| } + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal15integral_traitsIiE11size_bufferERKi + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal15integral_traitsImE11size_bufferERKm + ------------------ + 128| |}; + 129| | + 130| | + 131| |// C++20: Guard with concept? + 132| |/// String traits for builtin floating-point types. + 133| |template struct float_traits + 134| |{ + 135| | static constexpr bool converts_to_string{true}; + 136| | static constexpr bool converts_from_string{true}; + 137| | static PQXX_LIBEXPORT T from_string(std::string_view text); + 138| | static PQXX_LIBEXPORT zview to_buf(char *begin, char *end, T const &value); + 139| | static PQXX_LIBEXPORT char *into_buf(char *begin, char *end, T const &value); + 140| | + 141| | // Return a nonnegative integral value's number of decimal digits. + 142| | static constexpr std::size_t digits10(std::size_t value) noexcept + 143| | { + 144| | if (value < 10) + 145| | return 1; + 146| | else + 147| | return 1 + digits10(value / 10); + 148| | } + 149| | + 150| | static constexpr std::size_t size_buffer(T const &) noexcept + 151| | { + 152| | using lims = std::numeric_limits; + 153| | // See #328 for a detailed discussion on the maximum number of digits. + 154| | // + 155| | // In a nutshell: for the big cases, the scientific notation is always + 156| | // the shortest one, and therefore the one that to_chars will pick. + 157| | // + 158| | // So... How long can the scientific notation get? 1 (for sign) + 1 (for + 159| | // decimal point) + 1 (for 'e') + 1 (for exponent sign) + max_digits10 + + 160| | // max number of digits in the exponent + 1 (terminating zero). + 161| | // + 162| | // What's the max number of digits in the exponent? It's the max number of + 163| | // digits out of the most negative exponent and the most positive one. + 164| | // + 165| | // The longest positive exponent is easy: 1 + ceil(log10(max_exponent10)). + 166| | // (The extra 1 is because 10^n takes up 1 + n digits, not n.) + 167| | // + 168| | // The longest negative exponent is a bit harder: min_exponent10 gives us + 169| | // the smallest power of 10 which a normalised version of T can represent. + 170| | // But the smallest denormalised power of 10 that T can represent is + 171| | // another max_digits10 powers of 10 below that. + 172| | // needs a minus sign. + 173| | // + 174| | // All this stuff messes with my head a bit because it's on the order of + 175| | // log10(log10(n)). It's easy to get the number of logs wrong. + 176| | auto const max_pos_exp{digits10(lims::max_exponent10)}; + 177| | // Really want std::abs(lims::min_exponent10), but MSVC 2017 apparently has + 178| | // problems with std::abs. So we use -lims::min_exponent10 instead. + 179| | auto const max_neg_exp{ + 180| | digits10(lims::max_digits10 - lims::min_exponent10)}; + 181| | return 1 + // Sign. + 182| | 1 + // Decimal point. + 183| | std::numeric_limits::max_digits10 + // Mantissa digits. + 184| | 1 + // Exponent "e". + 185| | 1 + // Exponent sign. + 186| | // Spell this weirdly to stop Windows compilers from reading this as + 187| | // a call to their "max" macro when NOMINMAX is not defined. + 188| | (std::max)(max_pos_exp, max_neg_exp) + // Exponent digits. + 189| | 1; // Terminating zero. + 190| | } + 191| |}; + 192| |} // namespace pqxx::internal + 193| | + 194| | + 195| |namespace pqxx + 196| |{ + 197| |/// The built-in arithmetic types do not have inherent null values. + 198| |/** Not-a-Number values (or NaNs for short) behave a lot like an SQL null, but + 199| | * they are not nulls. A non-null SQL float can be NaN. + 200| | */ + 201| |template + 202| |struct nullness>> : no_null + 203| |{}; + 204| | + 205| | + 206| |template<> struct string_traits : internal::integral_traits + 207| |{}; + 208| |template<> inline constexpr bool is_unquoted_safe{true}; + 209| |template<> + 210| |struct string_traits + 211| | : internal::integral_traits + 212| |{}; + 213| |template<> inline constexpr bool is_unquoted_safe{true}; + 214| |template<> struct string_traits : internal::integral_traits + 215| |{}; + 216| |template<> inline constexpr bool is_unquoted_safe{true}; + 217| |template<> struct string_traits : internal::integral_traits + 218| |{}; + 219| |template<> inline constexpr bool is_unquoted_safe{true}; + 220| |template<> struct string_traits : internal::integral_traits + 221| |{}; + 222| |template<> inline constexpr bool is_unquoted_safe{true}; + 223| |template<> + 224| |struct string_traits : internal::integral_traits + 225| |{}; + 226| |template<> inline constexpr bool is_unquoted_safe{true}; + 227| |template<> + 228| |struct string_traits : internal::integral_traits + 229| |{}; + 230| |template<> inline constexpr bool is_unquoted_safe{true}; + 231| |template<> + 232| |struct string_traits + 233| | : internal::integral_traits + 234| |{}; + 235| |template<> inline constexpr bool is_unquoted_safe{true}; + 236| |template<> struct string_traits : internal::float_traits + 237| |{}; + 238| |template<> inline constexpr bool is_unquoted_safe{true}; + 239| |template<> struct string_traits : internal::float_traits + 240| |{}; + 241| |template<> inline constexpr bool is_unquoted_safe{true}; + 242| |template<> + 243| |struct string_traits : internal::float_traits + 244| |{}; + 245| |template<> inline constexpr bool is_unquoted_safe{true}; + 246| | + 247| | + 248| |template<> struct string_traits + 249| |{ + 250| | static constexpr bool converts_to_string{true}; + 251| | static constexpr bool converts_from_string{true}; + 252| | + 253| | static PQXX_LIBEXPORT bool from_string(std::string_view text); + 254| | + 255| | static constexpr zview to_buf(char *, char *, bool const &value) noexcept + 256| 0| { + 257| 0| return value ? "true"_zv : "false"_zv; + 258| 0| } + 259| | + 260| | static char *into_buf(char *begin, char *end, bool const &value) + 261| 0| { + 262| 0| return pqxx::internal::generic_into_buf(begin, end, value); + 263| 0| } + 264| | + 265| 0| static constexpr std::size_t size_buffer(bool const &) noexcept { return 6; } + 266| |}; + 267| | + 268| | + 269| |template<> inline constexpr bool is_unquoted_safe{true}; + 270| | + 271| | + 272| |template struct nullness> + 273| |{ + 274| | static constexpr bool has_null = true; + 275| | /// Technically, you could have an optional of an always-null type. + 276| | static constexpr bool always_null = nullness::always_null; + 277| | static constexpr bool is_null(std::optional const &v) noexcept + 278| | { + 279| | return ((not v.has_value()) or pqxx::is_null(*v)); + 280| | } + 281| | static constexpr std::optional null() { return {}; } + 282| |}; + 283| | + 284| | + 285| |template + 286| |inline constexpr format param_format(std::optional const &value) + 287| |{ + 288| | return param_format(*value); + 289| |} + 290| | + 291| | + 292| |template struct string_traits> + 293| |{ + 294| | static constexpr bool converts_to_string{ + 295| | string_traits::converts_to_string}; + 296| | static constexpr bool converts_from_string{ + 297| | string_traits::converts_from_string}; + 298| | + 299| | static char *into_buf(char *begin, char *end, std::optional const &value) + 300| | { + 301| | return string_traits::into_buf(begin, end, *value); + 302| | } + 303| | + 304| | static zview to_buf(char *begin, char *end, std::optional const &value) + 305| | { + 306| | if (pqxx::is_null(value)) + 307| | return {}; + 308| | else + 309| | return string_traits::to_buf(begin, end, *value); + 310| | } + 311| | + 312| | static std::optional from_string(std::string_view text) + 313| | { + 314| | return std::optional{ + 315| | std::in_place, string_traits::from_string(text)}; + 316| | } + 317| | + 318| | static std::size_t size_buffer(std::optional const &value) noexcept + 319| | { + 320| | if (pqxx::is_null(value)) + 321| | return 0; + 322| | else + 323| | return pqxx::size_buffer(value.value()); + 324| | } + 325| |}; + 326| | + 327| | + 328| |template + 329| |inline constexpr bool is_unquoted_safe>{is_unquoted_safe}; + 330| | + 331| | + 332| |template struct nullness> + 333| |{ + 334| | static constexpr bool has_null = (nullness::has_null or ...); + 335| | static constexpr bool always_null = (nullness::always_null and ...); + 336| | static constexpr bool is_null(std::variant const &value) noexcept + 337| | { + 338| | return value.valueless_by_exception() or + 339| | std::visit( + 340| | [](auto const &i) noexcept { + 341| | return nullness>::is_null(i); + 342| | }, + 343| | value); + 344| | } + 345| | + 346| | // We don't support `null()` for `std::variant`. + 347| | /** It would be technically possible to have a `null` in the case where just + 348| | * one of the types has a null, but it gets complicated and arbitrary. + 349| | */ + 350| | static constexpr std::variant null() = delete; + 351| |}; + 352| | + 353| | + 354| |template struct string_traits> + 355| |{ + 356| | static constexpr bool converts_to_string{ + 357| | (string_traits::converts_to_string and ...)}; + 358| | + 359| | static char * + 360| | into_buf(char *begin, char *end, std::variant const &value) + 361| | { + 362| | return std::visit( + 363| | [begin, end](auto const &i) { + 364| | return string_traits>::into_buf(begin, end, i); + 365| | }, + 366| | value); + 367| | } + 368| | static zview to_buf(char *begin, char *end, std::variant const &value) + 369| | { + 370| | return std::visit( + 371| | [begin, end](auto const &i) { + 372| | return string_traits>::to_buf(begin, end, i); + 373| | }, + 374| | value); + 375| | } + 376| | static std::size_t size_buffer(std::variant const &value) noexcept + 377| | { + 378| | if (pqxx::is_null(value)) + 379| | return 0; + 380| | else + 381| | return std::visit( + 382| | [](auto const &i) noexcept { return pqxx::size_buffer(i); }, value); + 383| | } + 384| | + 385| | /** There's no from_string for std::variant. We could have one with a rule + 386| | * like "pick the first type which fits the value," but we'd have to look + 387| | * into how natural that API feels to users. + 388| | */ + 389| | static std::variant from_string(std::string_view) = delete; + 390| |}; + 391| | + 392| | + 393| |template + 394| |inline constexpr format param_format(std::variant const &value) + 395| |{ + 396| | return std::visit([](auto &v) { return param_format(v); }, value); + 397| |} + 398| | + 399| | + 400| |template + 401| |inline constexpr bool is_unquoted_safe>{ + 402| | (is_unquoted_safe and ...)}; + 403| | + 404| | + 405| |template inline T from_string(std::stringstream const &text) + 406| |{ + 407| | return from_string(text.str()); + 408| |} + 409| | + 410| | + 411| |template<> struct string_traits + 412| |{ + 413| | static constexpr bool converts_to_string{false}; + 414| | static constexpr bool converts_from_string{false}; + 415| | + 416| | static char *into_buf(char *, char *, std::nullptr_t) = delete; + 417| | + 418| | [[deprecated("Do not convert nulls.")]] static constexpr zview + 419| | to_buf(char *, char *, std::nullptr_t const &) noexcept + 420| 0| { + 421| 0| return {}; + 422| 0| } + 423| | + 424| | [[deprecated("Do not convert nulls.")]] static constexpr std::size_t + 425| | size_buffer(std::nullptr_t = nullptr) noexcept + 426| 0| { + 427| 0| return 0; + 428| 0| } + 429| | static std::nullptr_t from_string(std::string_view) = delete; + 430| |}; + 431| | + 432| | + 433| |template<> struct string_traits + 434| |{ + 435| | static constexpr bool converts_to_string{false}; + 436| | static constexpr bool converts_from_string{false}; + 437| | + 438| | static char *into_buf(char *, char *, std::nullopt_t) = delete; + 439| | + 440| | [[deprecated("Do not convert nulls.")]] static constexpr zview + 441| | to_buf(char *, char *, std::nullopt_t const &) noexcept + 442| 0| { + 443| 0| return {}; + 444| 0| } + 445| | + 446| | [[deprecated("Do not convert nulls.")]] static constexpr std::size_t + 447| | size_buffer(std::nullopt_t) noexcept + 448| 0| { + 449| 0| return 0; + 450| 0| } + 451| | static std::nullopt_t from_string(std::string_view) = delete; + 452| |}; + 453| | + 454| | + 455| |template<> struct string_traits + 456| |{ + 457| | static constexpr bool converts_to_string{false}; + 458| | static constexpr bool converts_from_string{false}; + 459| | + 460| | static char *into_buf(char *, char *, std::monostate) = delete; + 461| | + 462| | [[deprecated("Do not convert nulls.")]] static constexpr zview + 463| | to_buf(char *, char *, std::monostate const &) noexcept + 464| 0| { + 465| 0| return {}; + 466| 0| } + 467| | + 468| | [[deprecated("Do not convert nulls.")]] static constexpr std::size_t + 469| | size_buffer(std::monostate) noexcept + 470| 0| { + 471| 0| return 0; + 472| 0| } + 473| | [[deprecated("Do not convert nulls.")]] static std::monostate + 474| | from_string(std::string_view) = delete; + 475| |}; + 476| | + 477| | + 478| |template<> inline constexpr bool is_unquoted_safe{true}; + 479| | + 480| | + 481| |template<> struct nullness + 482| |{ + 483| | static constexpr bool has_null = true; + 484| | static constexpr bool always_null = false; + 485| | static constexpr bool is_null(char const *t) noexcept + 486| 0| { + 487| 0| return t == nullptr; + 488| 0| } + 489| 0| static constexpr char const *null() noexcept { return nullptr; } + 490| |}; + 491| | + 492| | + 493| |/// String traits for C-style string ("pointer to char const"). + 494| |template<> struct string_traits + 495| |{ + 496| | static constexpr bool converts_to_string{true}; + 497| | static constexpr bool converts_from_string{true}; + 498| | + 499| 0| static char const *from_string(std::string_view text) { return text.data(); } + 500| | + 501| | static zview to_buf(char *begin, char *end, char const *const &value) + 502| 0| { + 503| 0| return generic_to_buf(begin, end, value); + 504| 0| } + 505| | + 506| | static char *into_buf(char *begin, char *end, char const *const &value) + 507| 0| { + 508| 0| auto const space{end - begin}; + 509| 0| // Count the trailing zero, even though std::strlen() and friends don't. + 510| 0| auto const len{std::strlen(value) + 1}; + 511| 0| if (space < ptrdiff_t(len)) + 512| 0| throw conversion_overrun{ + 513| 0| "Could not copy string: buffer too small. " + + 514| 0| pqxx::internal::state_buffer_overrun(space, len)}; + 515| 0| std::memmove(begin, value, len); + 516| 0| return begin + len; + 517| 0| } + 518| | + 519| | static std::size_t size_buffer(char const *const &value) noexcept + 520| 0| { + 521| 0| if (pqxx::is_null(value)) + 522| 0| return 0; + 523| 0| else + 524| 0| return std::strlen(value) + 1; + 525| 0| } + 526| |}; + 527| | + 528| | + 529| |template<> struct nullness + 530| |{ + 531| | static constexpr bool has_null = true; + 532| | static constexpr bool always_null = false; + 533| | static constexpr bool is_null(char const *t) noexcept + 534| 0| { + 535| 0| return t == nullptr; + 536| 0| } + 537| 0| static constexpr char const *null() { return nullptr; } + 538| |}; + 539| | + 540| | + 541| |/// String traits for non-const C-style string ("pointer to char"). + 542| |template<> struct string_traits + 543| |{ + 544| | static constexpr bool converts_to_string{true}; + 545| | static constexpr bool converts_from_string{false}; + 546| | + 547| | static char *into_buf(char *begin, char *end, char *const &value) + 548| 0| { + 549| 0| return string_traits::into_buf(begin, end, value); + 550| 0| } + 551| | static zview to_buf(char *begin, char *end, char *const &value) + 552| 0| { + 553| 0| return string_traits::to_buf(begin, end, value); + 554| 0| } + 555| | static std::size_t size_buffer(char *const &value) noexcept + 556| 0| { + 557| 0| if (pqxx::is_null(value)) + 558| 0| return 0; + 559| 0| else + 560| 0| return string_traits::size_buffer(value); + 561| 0| } + 562| | + 563| | /// Don't allow conversion to this type since it breaks const-safety. + 564| | static char *from_string(std::string_view) = delete; + 565| |}; + 566| | + 567| | + 568| |template struct nullness : no_null + 569| |{}; + 570| | + 571| | + 572| |/// String traits for C-style string constant ("pointer to array of char"). + 573| |/** @warning This assumes that every array-of-char is a C-style string literal. + 574| | * So, it must include a trailing zero. and it must have static duration. + 575| | */ + 576| |template struct string_traits + 577| |{ + 578| | static constexpr bool converts_to_string{true}; + 579| | static constexpr bool converts_from_string{false}; + 580| | + 581| | static constexpr zview + 582| | to_buf(char *, char *, char const (&value)[N]) noexcept + 583| | { + 584| | return zview{value, N - 1}; + 585| | } + 586| | + 587| | static char *into_buf(char *begin, char *end, char const (&value)[N]) + 588| | { + 589| | if (internal::cmp_less(end - begin, size_buffer(value))) + 590| | throw conversion_overrun{ + 591| | "Could not convert char[] to string: too long for buffer."}; + 592| | std::memcpy(begin, value, N); + 593| | return begin + N; + 594| | } + 595| | static constexpr std::size_t size_buffer(char const (&)[N]) noexcept + 596| | { + 597| | return N; + 598| | } + 599| | + 600| | /// Don't allow conversion to this type. + 601| | static void from_string(std::string_view) = delete; + 602| |}; + 603| | + 604| | + 605| |template<> struct nullness : no_null + 606| |{}; + 607| | + 608| | + 609| |template<> struct string_traits + 610| |{ + 611| | static constexpr bool converts_to_string{true}; + 612| | static constexpr bool converts_from_string{true}; + 613| | + 614| | static std::string from_string(std::string_view text) + 615| 0| { + 616| 0| return std::string{text}; + 617| 0| } + 618| | + 619| | static char *into_buf(char *begin, char *end, std::string const &value) + 620| 0| { + 621| 0| if (internal::cmp_greater_equal(std::size(value), end - begin)) + 622| 0| throw conversion_overrun{ + 623| 0| "Could not convert string to string: too long for buffer."}; + 624| 0| // Include the trailing zero. + 625| 0| value.copy(begin, std::size(value)); + 626| 0| begin[std::size(value)] = '\0'; + 627| 0| return begin + std::size(value) + 1; + 628| 0| } + 629| | + 630| | static zview to_buf(char *begin, char *end, std::string const &value) + 631| 0| { + 632| 0| return generic_to_buf(begin, end, value); + 633| 0| } + 634| | + 635| | static std::size_t size_buffer(std::string const &value) noexcept + 636| 0| { + 637| 0| return std::size(value) + 1; + 638| 0| } + 639| |}; + 640| | + 641| | + 642| |/// There's no real null for `std::string_view`. + 643| |/** I'm not sure how clear-cut this is: a `string_view` may have a null + 644| | * data pointer, which is analogous to a null `char` pointer. + 645| | */ + 646| |template<> struct nullness : no_null + 647| |{}; + 648| | + 649| | + 650| |/// String traits for `string_view`. + 651| |template<> struct string_traits + 652| |{ + 653| | static constexpr bool converts_to_string{true}; + 654| | static constexpr bool converts_from_string{false}; + 655| | + 656| | static constexpr std::size_t + 657| | size_buffer(std::string_view const &value) noexcept + 658| 0| { + 659| 0| return std::size(value) + 1; + 660| 0| } + 661| | + 662| | static char *into_buf(char *begin, char *end, std::string_view const &value) + 663| 0| { + 664| 0| if (internal::cmp_greater_equal(std::size(value), end - begin)) + 665| 0| throw conversion_overrun{ + 666| 0| "Could not store string_view: too long for buffer."}; + 667| 0| value.copy(begin, std::size(value)); + 668| 0| begin[std::size(value)] = '\0'; + 669| 0| return begin + std::size(value) + 1; + 670| 0| } + 671| | + 672| | static zview to_buf(char *begin, char *end, std::string_view const &value) + 673| 0| { + 674| 0| // You'd think we could just return the same view but alas, there's no + 675| 0| // zero-termination on a string_view. + 676| 0| return generic_to_buf(begin, end, value); + 677| 0| } + 678| | + 679| | /// Don't convert to this type; it has nowhere to store its contents. + 680| | static std::string_view from_string(std::string_view) = delete; + 681| |}; + 682| | + 683| | + 684| |template<> struct nullness : no_null + 685| |{}; + 686| | + 687| | + 688| |/// String traits for `zview`. + 689| |template<> struct string_traits + 690| |{ + 691| | static constexpr bool converts_to_string{true}; + 692| | static constexpr bool converts_from_string{false}; + 693| | + 694| | static constexpr std::size_t + 695| | size_buffer(std::string_view const &value) noexcept + 696| 0| { + 697| 0| return std::size(value) + 1; + 698| 0| } + 699| | + 700| | static char *into_buf(char *begin, char *end, zview const &value) + 701| 0| { + 702| 0| auto const size{std::size(value)}; + 703| 0| if (internal::cmp_less_equal(end - begin, std::size(value))) + 704| 0| throw conversion_overrun{"Not enough buffer space to store this zview."}; + 705| 0| value.copy(begin, size); + 706| 0| begin[size] = '\0'; + 707| 0| return begin + size + 1; + 708| 0| } + 709| | + 710| | static std::string_view to_buf(char *begin, char *end, zview const &value) + 711| 0| { + 712| 0| char *const stop{into_buf(begin, end, value)}; + 713| 0| return {begin, static_cast(stop - begin - 1)}; + 714| 0| } + 715| | + 716| | /// Don't convert to this type; it has nowhere to store its contents. + 717| | static zview from_string(std::string_view) = delete; + 718| |}; + 719| | + 720| | + 721| |template<> struct nullness : no_null + 722| |{}; + 723| | + 724| | + 725| |template<> struct string_traits + 726| |{ + 727| | static constexpr bool converts_to_string{false}; + 728| | static constexpr bool converts_from_string{true}; + 729| | + 730| | static std::size_t size_buffer(std::stringstream const &) = delete; + 731| | + 732| | static std::stringstream from_string(std::string_view text) + 733| 0| { + 734| 0| std::stringstream stream; + 735| 0| stream.write(text.data(), std::streamsize(std::size(text))); + 736| 0| return stream; + 737| 0| } + 738| | + 739| | static char *into_buf(char *, char *, std::stringstream const &) = delete; + 740| | static std::string_view + 741| | to_buf(char *, char *, std::stringstream const &) = delete; + 742| |}; + 743| | + 744| | + 745| |template<> struct nullness + 746| |{ + 747| | static constexpr bool has_null = true; + 748| | static constexpr bool always_null = true; + 749| | static constexpr bool is_null(std::nullptr_t const &) noexcept + 750| 0| { + 751| 0| return true; + 752| 0| } + 753| 0| static constexpr std::nullptr_t null() noexcept { return nullptr; } + 754| |}; + 755| | + 756| | + 757| |template<> struct nullness + 758| |{ + 759| | static constexpr bool has_null = true; + 760| | static constexpr bool always_null = true; + 761| | static constexpr bool is_null(std::nullopt_t const &) noexcept + 762| 0| { + 763| 0| return true; + 764| 0| } + 765| 0| static constexpr std::nullopt_t null() noexcept { return std::nullopt; } + 766| |}; + 767| | + 768| | + 769| |template<> struct nullness + 770| |{ + 771| | static constexpr bool has_null = true; + 772| | static constexpr bool always_null = true; + 773| | static constexpr bool is_null(std::monostate const &) noexcept + 774| 0| { + 775| 0| return true; + 776| 0| } + 777| 0| static constexpr std::monostate null() noexcept { return {}; } + 778| |}; + 779| | + 780| | + 781| |template struct nullness> + 782| |{ + 783| | static constexpr bool has_null = true; + 784| | static constexpr bool always_null = false; + 785| | static constexpr bool is_null(std::unique_ptr const &t) noexcept + 786| | { + 787| | return not t or pqxx::is_null(*t); + 788| | } + 789| | static constexpr std::unique_ptr null() { return {}; } + 790| |}; + 791| | + 792| | + 793| |template + 794| |struct string_traits> + 795| |{ + 796| | static constexpr bool converts_to_string{ + 797| | string_traits::converts_to_string}; + 798| | static constexpr bool converts_from_string{ + 799| | string_traits::converts_from_string}; + 800| | + 801| | static std::unique_ptr from_string(std::string_view text) + 802| | { + 803| | return std::make_unique(string_traits::from_string(text)); + 804| | } + 805| | + 806| | static char * + 807| | into_buf(char *begin, char *end, std::unique_ptr const &value) + 808| | { + 809| | return string_traits::into_buf(begin, end, *value); + 810| | } + 811| | + 812| | static zview + 813| | to_buf(char *begin, char *end, std::unique_ptr const &value) + 814| | { + 815| | if (value) + 816| | return string_traits::to_buf(begin, end, *value); + 817| | else + 818| | return {}; + 819| | } + 820| | + 821| | static std::size_t + 822| | size_buffer(std::unique_ptr const &value) noexcept + 823| | { + 824| | if (pqxx::is_null(value)) + 825| | return 0; + 826| | else + 827| | return pqxx::size_buffer(*value.get()); + 828| | } + 829| |}; + 830| | + 831| | + 832| |template + 833| |inline format param_format(std::unique_ptr const &value) + 834| |{ + 835| | return param_format(*value); + 836| |} + 837| | + 838| | + 839| |template + 840| |inline constexpr bool is_unquoted_safe>{ + 841| | is_unquoted_safe}; + 842| | + 843| | + 844| |template struct nullness> + 845| |{ + 846| | static constexpr bool has_null = true; + 847| | static constexpr bool always_null = false; + 848| | static constexpr bool is_null(std::shared_ptr const &t) noexcept + 849| | { + 850| | return not t or pqxx::is_null(*t); + 851| | } + 852| | static constexpr std::shared_ptr null() { return {}; } + 853| |}; + 854| | + 855| | + 856| |template struct string_traits> + 857| |{ + 858| | static constexpr bool converts_to_string{ + 859| | string_traits::converts_to_string}; + 860| | static constexpr bool converts_from_string{ + 861| | string_traits::converts_from_string}; + 862| | + 863| | static std::shared_ptr from_string(std::string_view text) + 864| | { + 865| | return std::make_shared(string_traits::from_string(text)); + 866| | } + 867| | + 868| | static zview to_buf(char *begin, char *end, std::shared_ptr const &value) + 869| | { + 870| | return string_traits::to_buf(begin, end, *value); + 871| | } + 872| | static char * + 873| | into_buf(char *begin, char *end, std::shared_ptr const &value) + 874| | { + 875| | return string_traits::into_buf(begin, end, *value); + 876| | } + 877| | static std::size_t size_buffer(std::shared_ptr const &value) noexcept + 878| | { + 879| | if (pqxx::is_null(value)) + 880| | return 0; + 881| | else + 882| | return pqxx::size_buffer(*value); + 883| | } + 884| |}; + 885| | + 886| | + 887| |template format param_format(std::shared_ptr const &value) + 888| |{ + 889| | return param_format(*value); + 890| |} + 891| | + 892| | + 893| |template + 894| |inline constexpr bool is_unquoted_safe>{ + 895| | is_unquoted_safe}; + 896| | + 897| | + 898| |template<> struct nullness : no_null + 899| |{}; + 900| | + 901| | + 902| |#if defined(PQXX_HAVE_CONCEPTS) + 903| |template struct nullness : no_null + 904| |{}; + 905| | + 906| | + 907| |template inline constexpr format param_format(DATA const &) + 908| |{ + 909| | return format::binary; + 910| |} + 911| | + 912| | + 913| |template struct string_traits + 914| |{ + 915| | static constexpr bool converts_to_string{true}; + 916| | static constexpr bool converts_from_string{true}; + 917| | + 918| | static std::size_t size_buffer(DATA const &value) noexcept + 919| | { + 920| | return internal::size_esc_bin(std::size(value)); + 921| | } + 922| | + 923| | static zview to_buf(char *begin, char *end, DATA const &value) + 924| | { + 925| | return generic_to_buf(begin, end, value); + 926| | } + 927| | + 928| | static char *into_buf(char *begin, char *end, DATA const &value) + 929| | { + 930| | auto const budget{size_buffer(value)}; + 931| | if (internal::cmp_less(end - begin, budget)) + 932| | throw conversion_overrun{ + 933| | "Not enough buffer space to escape binary data."}; + 934| | internal::esc_bin(value, begin); + 935| | return begin + budget; + 936| | } + 937| | + 938| | static DATA from_string(std::string_view text) + 939| | { + 940| | auto const size{pqxx::internal::size_unesc_bin(std::size(text))}; + 941| | bytes buf; + 942| | buf.resize(size); + 943| | pqxx::internal::unesc_bin(text, reinterpret_cast(buf.data())); + 944| | return buf; + 945| | } + 946| |}; + 947| |#endif // PQXX_HAVE_CONCEPTS + 948| | + 949| | + 950| |template<> struct string_traits + 951| |{ + 952| | static constexpr bool converts_to_string{true}; + 953| | static constexpr bool converts_from_string{true}; + 954| | + 955| | static std::size_t size_buffer(bytes const &value) noexcept + 956| 0| { + 957| 0| return internal::size_esc_bin(std::size(value)); + 958| 0| } + 959| | + 960| | static zview to_buf(char *begin, char *end, bytes const &value) + 961| 0| { + 962| 0| return generic_to_buf(begin, end, value); + 963| 0| } + 964| | + 965| | static char *into_buf(char *begin, char *end, bytes const &value) + 966| 0| { + 967| 0| auto const budget{size_buffer(value)}; + 968| 0| if (internal::cmp_less(end - begin, budget)) + 969| 0| throw conversion_overrun{ + 970| 0| "Not enough buffer space to escape binary data."}; + 971| 0| internal::esc_bin(value, begin); + 972| 0| return begin + budget; + 973| 0| } + 974| | + 975| | static bytes from_string(std::string_view text) + 976| 0| { + 977| 0| auto const size{pqxx::internal::size_unesc_bin(std::size(text))}; + 978| 0| bytes buf; + 979| 0| buf.resize(size); + 980| 0| pqxx::internal::unesc_bin(text, reinterpret_cast(buf.data())); + 981| 0| return buf; + 982| 0| } + 983| |}; + 984| | + 985| | + 986| |template<> inline constexpr format param_format(bytes const &) + 987| 0|{ + 988| 0| return format::binary; + 989| 0|} + 990| | + 991| | + 992| |template<> struct nullness : no_null + 993| |{}; + 994| | + 995| | + 996| |template<> struct string_traits + 997| |{ + 998| | static constexpr bool converts_to_string{true}; + 999| | static constexpr bool converts_from_string{false}; + 1000| | + 1001| | static std::size_t size_buffer(bytes_view const &value) noexcept + 1002| 0| { + 1003| 0| return internal::size_esc_bin(std::size(value)); + 1004| 0| } + 1005| | + 1006| | static zview to_buf(char *begin, char *end, bytes_view const &value) + 1007| 0| { + 1008| 0| return generic_to_buf(begin, end, value); + 1009| 0| } + 1010| | + 1011| | static char *into_buf(char *begin, char *end, bytes_view const &value) + 1012| 0| { + 1013| 0| auto const budget{size_buffer(value)}; + 1014| 0| if (internal::cmp_less(end - begin, budget)) + 1015| 0| throw conversion_overrun{ + 1016| 0| "Not enough buffer space to escape binary data."}; + 1017| 0| internal::esc_bin(value, begin); + 1018| 0| return begin + budget; + 1019| 0| } + 1020| | + 1021| | // There's no from_string, because there's nobody to hold the data. + 1022| |}; + 1023| | + 1024| |template<> inline constexpr format param_format(bytes_view const &) + 1025| 0|{ + 1026| 0| return format::binary; + 1027| 0|} + 1028| |} // namespace pqxx + 1029| | + 1030| | + 1031| |namespace pqxx::internal + 1032| |{ + 1033| |// C++20: Use concepts to identify arrays. + 1034| |/// String traits for SQL arrays. + 1035| |template struct array_string_traits + 1036| |{ + 1037| |private: + 1038| | using elt_type = strip_t>; + 1039| | using elt_traits = string_traits; + 1040| | static constexpr zview s_null{"NULL"}; + 1041| | + 1042| |public: + 1043| | static constexpr bool converts_to_string{true}; + 1044| | static constexpr bool converts_from_string{false}; + 1045| | + 1046| | static zview to_buf(char *begin, char *end, Container const &value) + 1047| | { + 1048| | return generic_to_buf(begin, end, value); + 1049| | } + 1050| | + 1051| | static char *into_buf(char *begin, char *end, Container const &value) + 1052| | { + 1053| | assert(begin <= end); + 1054| | std::size_t const budget{size_buffer(value)}; + 1055| | if (internal::cmp_less(end - begin, budget)) + 1056| | throw conversion_overrun{ + 1057| | "Not enough buffer space to convert array to string."}; + 1058| | + 1059| | char *here = begin; + 1060| | *here++ = '{'; + 1061| | + 1062| | bool nonempty{false}; + 1063| | for (auto const &elt : value) + 1064| | { + 1065| | if (is_null(elt)) + 1066| | { + 1067| | s_null.copy(here, std::size(s_null)); + 1068| | here += std::size(s_null); + 1069| | } + 1070| | else if constexpr (is_sql_array) + 1071| | { + 1072| | // Render nested array in-place. Then erase the trailing zero. + 1073| | here = elt_traits::into_buf(here, end, elt) - 1; + 1074| | } + 1075| | else if constexpr (is_unquoted_safe) + 1076| | { + 1077| | // No need to quote or escape. Just convert the value straight into + 1078| | // its place in the array, and "backspace" the trailing zero. + 1079| | here = elt_traits::into_buf(here, end, elt) - 1; + 1080| | } + 1081| | else + 1082| | { + 1083| | *here++ = '"'; + 1084| | + 1085| | // Use the tail end of the destination buffer as an intermediate + 1086| | // buffer. + 1087| | auto const elt_budget{pqxx::size_buffer(elt)}; + 1088| | assert(elt_budget < static_cast(end - here)); + 1089| | for (char const c : elt_traits::to_buf(end - elt_budget, end, elt)) + 1090| | { + 1091| | // We copy the intermediate buffer into the final buffer, char by + 1092| | // char, with escaping where necessary. + 1093| | // TODO: This will not work for all encodings. UTF8 & ASCII are OK. + 1094| | if (c == '\\' or c == '"') + 1095| | *here++ = '\\'; + 1096| | *here++ = c; + 1097| | } + 1098| | *here++ = '"'; + 1099| | } + 1100| | *here++ = array_separator; + 1101| | nonempty = true; + 1102| | } + 1103| | + 1104| | // Erase that last comma, if present. + 1105| | if (nonempty) + 1106| | here--; + 1107| | + 1108| | *here++ = '}'; + 1109| | *here++ = '\0'; + 1110| | + 1111| | return here; + 1112| | } + 1113| | + 1114| | static std::size_t size_buffer(Container const &value) noexcept + 1115| | { + 1116| | if constexpr (is_unquoted_safe) + 1117| | return 3 + std::accumulate( + 1118| | std::begin(value), std::end(value), std::size_t{}, + 1119| | [](std::size_t acc, elt_type const &elt) { + 1120| | // Budget for each element includes a terminating zero. + 1121| | // We won't actually be wanting those, but don't subtract + 1122| | // that one byte: we want room for a separator instead. + 1123| | return acc + (pqxx::is_null(elt) ? + 1124| | std::size(s_null) : + 1125| | elt_traits::size_buffer(elt)); + 1126| | }); + 1127| | else + 1128| | return 3 + std::accumulate( + 1129| | std::begin(value), std::end(value), std::size_t{}, + 1130| | [](std::size_t acc, elt_type const &elt) { + 1131| | // Opening and closing quotes, plus worst-case escaping, + 1132| | // and the one byte for the trailing zero becomes room + 1133| | // for a separator. + 1134| | std::size_t const elt_size{ + 1135| | pqxx::is_null(elt) ? std::size(s_null) : + 1136| | elt_traits::size_buffer(elt)}; + 1137| | return acc + 2 * elt_size + 2; + 1138| | }); + 1139| | } + 1140| | + 1141| | // We don't yet support parsing of array types using from_string. Doing so + 1142| | // would require a reference to the connection. + 1143| |}; + 1144| |} // namespace pqxx::internal + 1145| | + 1146| | + 1147| |namespace pqxx + 1148| |{ + 1149| |template + 1150| |struct nullness> : no_null> + 1151| |{}; + 1152| | + 1153| | + 1154| |template + 1155| |struct string_traits> + 1156| | : internal::array_string_traits> + 1157| |{}; + 1158| | + 1159| | + 1160| |/// We don't know how to pass array params in binary format, so pass as text. + 1161| |template + 1162| |inline constexpr format param_format(std::vector const &) + 1163| |{ + 1164| | return format::text; + 1165| |} + 1166| | + 1167| | + 1168| |/// A `std::vector` is a binary string. Other vectors are not. + 1169| |template + 1170| |inline constexpr format param_format(std::vector const &) + 1171| |{ + 1172| | return format::binary; + 1173| |} + 1174| | + 1175| | + 1176| |template inline constexpr bool is_sql_array>{true}; + 1177| | + 1178| | + 1179| |#if defined(PQXX_HAVE_SPAN) && __has_include() + 1180| |template + 1181| |struct nullness> : no_null> + 1182| |{}; + 1183| | + 1184| | + 1185| |template + 1186| |struct string_traits> + 1187| | : internal::array_string_traits> + 1188| |{}; + 1189| | + 1190| | + 1191| |template + 1192| |inline constexpr format param_format(std::span const &) + 1193| |{ + 1194| | return format::text; + 1195| |} + 1196| | + 1197| | + 1198| |template + 1199| |inline constexpr format param_format(std::span const &) + 1200| |{ + 1201| | return format::binary; + 1202| |} + 1203| | + 1204| | + 1205| |template + 1206| |inline constexpr bool is_sql_array>{true}; + 1207| |#endif + 1208| | + 1209| | + 1210| |template + 1211| |struct nullness> : no_null> + 1212| |{}; + 1213| | + 1214| | + 1215| |template + 1216| |struct string_traits> + 1217| | : internal::array_string_traits> + 1218| |{}; + 1219| | + 1220| | + 1221| |/// We don't know how to pass array params in binary format, so pass as text. + 1222| |template + 1223| |inline constexpr format param_format(std::array const &) + 1224| |{ + 1225| | return format::text; + 1226| |} + 1227| | + 1228| | + 1229| |/// An array of `std::byte` is a binary string. + 1230| |template + 1231| |inline constexpr format param_format(std::array const &) + 1232| |{ + 1233| | return format::binary; + 1234| |} + 1235| | + 1236| | + 1237| |template + 1238| |inline constexpr bool is_sql_array>{true}; + 1239| |} // namespace pqxx + 1240| | + 1241| | + 1242| |namespace pqxx + 1243| |{ + 1244| |template inline std::string to_string(T const &value) + 1245| 0|{ + 1246| 0| if (is_null(value)) + 1247| 0| throw conversion_error{ + 1248| 0| "Attempt to convert null " + std::string{type_name} + + 1249| 0| " to a string."}; + 1250| 0| + 1251| 0| std::string buf; + 1252| 0| // We can't just reserve() space; modifying the terminating zero leads to + 1253| 0| // undefined behaviour. + 1254| 0| buf.resize(size_buffer(value)); + 1255| 0| auto const data{buf.data()}; + 1256| 0| auto const end{ + 1257| 0| string_traits::into_buf(data, data + std::size(buf), value)}; + 1258| 0| buf.resize(static_cast(end - data - 1)); + 1259| 0| return buf; + 1260| 0|} + 1261| | + 1262| | + 1263| |template<> inline std::string to_string(float const &value) + 1264| 0|{ + 1265| 0| return internal::to_string_float(value); + 1266| 0|} + 1267| |template<> inline std::string to_string(double const &value) + 1268| 0|{ + 1269| 0| return internal::to_string_float(value); + 1270| 0|} + 1271| |template<> inline std::string to_string(long double const &value) + 1272| 0|{ + 1273| 0| return internal::to_string_float(value); + 1274| 0|} + 1275| |template<> inline std::string to_string(std::stringstream const &value) + 1276| 0|{ + 1277| 0| return value.str(); + 1278| 0|} + 1279| | + 1280| | + 1281| |template inline void into_string(T const &value, std::string &out) + 1282| |{ + 1283| | if (is_null(value)) + 1284| | throw conversion_error{ + 1285| | "Attempt to convert null " + type_name + " to a string."}; + 1286| | + 1287| | // We can't just reserve() data; modifying the terminating zero leads to + 1288| | // undefined behaviour. + 1289| | out.resize(size_buffer(value) + 1); + 1290| | auto const data{out.data()}; + 1291| | auto const end{ + 1292| | string_traits::into_buf(data, data + std::size(out), value)}; + 1293| | out.resize(static_cast(end - data - 1)); + 1294| |} + 1295| |} // namespace pqxx + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/internal/encodings.hxx: + 1| |/** Internal string encodings support for libpqxx + 2| | * + 3| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 4| | * + 5| | * See COPYING for copyright license. If you did not receive a file called + 6| | * COPYING with this source code, please notify the distributor of this + 7| | * mistake, or contact the author. + 8| | */ + 9| |#ifndef PQXX_H_ENCODINGS + 10| |#define PQXX_H_ENCODINGS + 11| | + 12| |#include + 13| |#include + 14| |#include + 15| | + 16| |#include "pqxx/internal/concat.hxx" + 17| |#include "pqxx/internal/encoding_group.hxx" + 18| | + 19| | + 20| |namespace pqxx + 21| |{ + 22| |PQXX_DECLARE_ENUM_CONVERSION(pqxx::internal::encoding_group); + 23| |} // namespace pqxx + 24| | + 25| | + 26| |namespace pqxx::internal + 27| |{ + 28| |/// Return PostgreSQL's name for encoding enum value. + 29| |PQXX_PURE char const *name_encoding(int encoding_id); + 30| | + 31| |/// Convert libpq encoding enum value to its libpqxx group. + 32| |PQXX_LIBEXPORT encoding_group enc_group(int /* libpq encoding ID */); + 33| | + 34| | + 35| |/// Look up the glyph scanner function for a given encoding group. + 36| |/** To identify the glyph boundaries in a buffer, call this to obtain the + 37| | * scanner function appropriate for the buffer's encoding. Then, repeatedly + 38| | * call the scanner function to find the glyphs. + 39| | */ + 40| |PQXX_LIBEXPORT glyph_scanner_func *get_glyph_scanner(encoding_group); + 41| | + 42| | + 43| |// TODO: Get rid of this one. Use compile-time-specialised version instead. + 44| |/// Find any of the ASCII characters `NEEDLE` in `haystack`. + 45| |/** Scans through `haystack` until it finds a single-byte character that + 46| | * matches any value in `NEEDLE`. + 47| | * + 48| | * If it finds one, returns its offset. If not, returns the end of the + 49| | * haystack. + 50| | */ + 51| |template + 52| |inline std::size_t find_char( + 53| | glyph_scanner_func *scanner, std::string_view haystack, + 54| | std::size_t here = 0u) + 55| |{ + 56| | auto const sz{std::size(haystack)}; + 57| | auto const data{std::data(haystack)}; + 58| | while (here < sz) + 59| | { + 60| | auto next{scanner(data, sz, here)}; + 61| | PQXX_ASSUME(next > here); + 62| | // (For some reason gcc had a problem with a right-fold here. But clang + 63| | // was fine.) + 64| | if ((... or (data[here] == NEEDLE))) + 65| | { + 66| | // Also check against a multibyte character starting with a bytes which + 67| | // just happens to match one of the ASCII bytes we're looking for. It'd + 68| | // be cleaner to check that first, but either works. So, let's apply the + 69| | // most selective filter first and skip this check in almost all cases. + 70| | if (next == here + 1) + 71| | return here; + 72| | } + 73| | + 74| | // Nope, no hit. Move on. + 75| | here = next; + 76| | } + 77| | return sz; + 78| |} + 79| | + 80| | + 81| |// TODO: Get rid of this one. Use compile-time-specialised loop instead. + 82| |/// Iterate over the glyphs in a buffer. + 83| |/** Scans the glyphs in the buffer, and for each, passes its begin and its + 84| | * one-past-end pointers to `callback`. + 85| | */ + 86| |template + 87| |inline void for_glyphs( + 88| | encoding_group enc, CALLABLE callback, char const buffer[], + 89| | std::size_t buffer_len, std::size_t start = 0) + 90| |{ + 91| | auto const scan{get_glyph_scanner(enc)}; + 92| | for (std::size_t here = start, next; here < buffer_len; here = next) + 93| | { + 94| | next = scan(buffer, buffer_len, here); + 95| | PQXX_ASSUME(next > here); + 96| | callback(buffer + here, buffer + next); + 97| | } + 98| |} + 99| | + 100| | + 101| |namespace + 102| |{ + 103| |/// Extract byte from buffer, return as unsigned char. + 104| |constexpr PQXX_PURE unsigned char + 105| |get_byte(char const buffer[], std::size_t offset) noexcept + 106| 0|{ + 107| 0| return static_cast(buffer[offset]); + 108| 0|} + ------------------ + | Unexecuted instantiation: databaseConnection.cpp:_ZN4pqxx8internal12_GLOBAL__N_18get_byteEPKcm + ------------------ + | Unexecuted instantiation: main.cpp:_ZN4pqxx8internal12_GLOBAL__N_18get_byteEPKcm + ------------------ + | Unexecuted instantiation: db.mm:_ZN4pqxx8internal12_GLOBAL__N_18get_byteEPKcm + ------------------ + 109| | + 110| | + 111| |[[noreturn]] PQXX_COLD void throw_for_encoding_error( + 112| | char const *encoding_name, char const buffer[], std::size_t start, + 113| | std::size_t count) + 114| 0|{ + 115| 0| std::stringstream s; + 116| 0| s << "Invalid byte sequence for encoding " << encoding_name << " at byte " + 117| 0| << start << ": " << std::hex << std::setw(2) << std::setfill('0'); + 118| 0| for (std::size_t i{0}; i < count; ++i) + 119| 0| { + 120| 0| s << "0x" << static_cast(get_byte(buffer, start + i)); + 121| 0| if (i + 1 < count) + 122| 0| s << " "; + 123| 0| } + 124| 0| throw pqxx::argument_error{s.str()}; + 125| 0|} + ------------------ + | Unexecuted instantiation: databaseConnection.cpp:_ZN4pqxx8internal12_GLOBAL__N_124throw_for_encoding_errorEPKcS3_mm + ------------------ + | Unexecuted instantiation: main.cpp:_ZN4pqxx8internal12_GLOBAL__N_124throw_for_encoding_errorEPKcS3_mm + ------------------ + | Unexecuted instantiation: db.mm:_ZN4pqxx8internal12_GLOBAL__N_124throw_for_encoding_errorEPKcS3_mm + ------------------ + 126| | + 127| | + 128| |/// Does value lie between bottom and top, inclusive? + 129| |constexpr PQXX_PURE bool + 130| |between_inc(unsigned char value, unsigned bottom, unsigned top) + 131| 0|{ + 132| 0| return value >= bottom and value <= top; + 133| 0|} + ------------------ + | Unexecuted instantiation: databaseConnection.cpp:_ZN4pqxx8internal12_GLOBAL__N_111between_incEhjj + ------------------ + | Unexecuted instantiation: main.cpp:_ZN4pqxx8internal12_GLOBAL__N_111between_incEhjj + ------------------ + | Unexecuted instantiation: db.mm:_ZN4pqxx8internal12_GLOBAL__N_111between_incEhjj + ------------------ + 134| |} // namespace + 135| | + 136| | + 137| |/// Wrapper struct template for "find next glyph" functions. + 138| |/** When we use this, all we really want is a function pointer. But that + 139| | * won't work, because the template specialisation we use will only work (under + 140| | * current C++ rules) for a struct or class, not for a function. + 141| | */ + 142| |template struct glyph_scanner + 143| |{ + 144| | // TODO: Convert to use string_view? + 145| | /// Find the next glyph in `buffer` after position `start`. + 146| | PQXX_PURE static std::size_t + 147| | call(char const buffer[], std::size_t buffer_len, std::size_t start); + 148| |}; + 149| | + 150| | + 151| |namespace + 152| |{ + 153| |/// Find any of the ASCII characters in `NEEDLE` in `haystack`. + 154| |/** Scans through `haystack` until it finds a single-byte character that + 155| | * matches any of the values in `NEEDLE`. + 156| | * + 157| | * Returns the offset of the character it finds, or the end of the `haystack` + 158| | * otherwise. + 159| | */ + 160| |template + 161| |PQXX_PURE inline std::size_t + 162| |find_ascii_char(std::string_view haystack, std::size_t here) + 163| |{ + 164| | // We only know how to search for ASCII characters. It's an optimisation + 165| | // assumption in the code below. + 166| | static_assert((... and ((NEEDLE & 0x80) == 0))); + 167| | + 168| | auto const sz{std::size(haystack)}; + 169| | auto const data{std::data(haystack)}; + 170| | while (here < sz) + 171| | { + 172| | // Look up the next character boundary. This can be quite costly, so we + 173| | // desperately want the call inlined. + 174| | auto next{glyph_scanner::call(data, sz, here)}; + 175| | PQXX_ASSUME(next > here); + 176| | + 177| | // (For some reason gcc had a problem with a right-fold here. But clang + 178| | // was fine.) + 179| | // + 180| | // In all supported encodings, if a character's first byte is in the ASCII + 181| | // range, that means it's a single-byte character. It follows that when we + 182| | // find a match, we do not need to check that we're in a single-byte + 183| | // character: + 184| | // + 185| | // If this is an "ASCII-unsafe" encoding, e.g. SJIS, we're only checking + 186| | // each character's first byte. That first byte can only match NEEDLE if + 187| | // it's a single-byte character. + 188| | // + 189| | // In an "ASCII-safe" encoding, e.g. UTF-8 or the ISO-8859 ones, we check + 190| | // for a match at each byte in the text, because it's faster than finding + 191| | // character boundaries first. But in these encodings, a multichar byte + 192| | // never contains any bytes in the ASCII range at all. + 193| | if ((... or (data[here] == NEEDLE))) + 194| | return here; + 195| | + 196| | // Nope, no hit. Move on. + 197| | here = next; + 198| | } + 199| | return sz; + 200| |} + 201| |} // namespace + 202| | + 203| | + 204| |/// Find first of `NEEDLE` ASCII chars in `haystack`. + 205| |/** @warning This assumes that one of the `NEEDLE` characters is actually + 206| | * present. It does not check for buffer overruns, so make sure that there's + 207| | * a sentinel. + 208| | */ + 209| |template + 210| |PQXX_PURE std::size_t + 211| |find_s_ascii_char(std::string_view haystack, std::size_t here) + 212| 0|{ + 213| 0| // We only know how to search for ASCII characters. It's an optimisation + 214| 0| // assumption in the code below. + 215| 0| static_assert((... and ((NEEDLE >> 7) == 0))); + 216| 0| + 217| 0| auto const sz{std::size(haystack)}; + 218| 0| auto const data{std::data(haystack)}; + 219| 0| + 220| 0| // No supported encoding has multibyte characters that start with an + 221| 0| // ASCII-range byte. + 222| 0| while ((... and (data[here] != NEEDLE))) + 223| 0| { + 224| 0| auto const next = glyph_scanner::call(data, sz, here); + 225| 0| PQXX_ASSUME(next > here); + 226| 0| here = next; + 227| 0| } + 228| 0| return here; + 229| 0|} + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal17find_s_ascii_charILNS0_14encoding_groupE0EJLc9ELc92EEEEmNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEm + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal17find_s_ascii_charILNS0_14encoding_groupE1EJLc9ELc92EEEEmNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEm + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal17find_s_ascii_charILNS0_14encoding_groupE6EJLc9ELc92EEEEmNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEm + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal17find_s_ascii_charILNS0_14encoding_groupE7EJLc9ELc92EEEEmNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEm + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal17find_s_ascii_charILNS0_14encoding_groupE8EJLc9ELc92EEEEmNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEm + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal17find_s_ascii_charILNS0_14encoding_groupE10EJLc9ELc92EEEEmNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEm + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal17find_s_ascii_charILNS0_14encoding_groupE11EJLc9ELc92EEEEmNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEm + ------------------ + 230| | + 231| | + 232| |template<> struct glyph_scanner + 233| |{ + 234| | static PQXX_PURE constexpr std::size_t + 235| | call(char const /* buffer */[], std::size_t buffer_len, std::size_t start) + 236| 0| { + 237| 0| // TODO: Don't bother with npos. Let the caller check. + 238| 0| if (start >= buffer_len) + 239| 0| PQXX_UNLIKELY return std::string::npos; + 240| 0| else + 241| 0| return start + 1; + 242| 0| } + 243| |}; + 244| | + 245| | + 246| |// https://en.wikipedia.org/wiki/Big5#Organization + 247| |template<> struct glyph_scanner + 248| |{ + 249| | static PQXX_PURE std::size_t + 250| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 251| 0| { + 252| 0| if (start >= buffer_len) + 253| 0| PQXX_UNLIKELY return std::string::npos; + 254| 0| + 255| 0| auto const byte1{get_byte(buffer, start)}; + 256| 0| if (byte1 < 0x80) + 257| 0| return start + 1; + 258| 0| + 259| 0| if (not between_inc(byte1, 0x81, 0xfe) or (start + 2 > buffer_len)) + 260| 0| PQXX_UNLIKELY + 261| 0| throw_for_encoding_error("BIG5", buffer, start, 1); + 262| 0| + 263| 0| auto const byte2{get_byte(buffer, start + 1)}; + 264| 0| if ( + 265| 0| not between_inc(byte2, 0x40, 0x7e) and + 266| 0| not between_inc(byte2, 0xa1, 0xfe)) + 267| 0| PQXX_UNLIKELY + 268| 0| throw_for_encoding_error("BIG5", buffer, start, 2); + 269| 0| + 270| 0| return start + 2; + 271| 0| } + 272| |}; + 273| | + 274| | + 275| |/* + 276| |The PostgreSQL documentation claims that the EUC_* encodings are 1-3 bytes + 277| |each, but other documents explain that the EUC sets can contain 1-(2,3,4) bytes + 278| |depending on the specific extension: + 279| | EUC_CN : 1-2 + 280| | EUC_JP : 1-3 + 281| | EUC_JIS_2004: 1-2 + 282| | EUC_KR : 1-2 + 283| | EUC_TW : 1-4 + 284| |*/ + 285| | + 286| |// https://en.wikipedia.org/wiki/GB_2312#EUC-CN + 287| |template<> struct glyph_scanner + 288| |{ + 289| | static PQXX_PURE std::size_t + 290| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 291| 0| { + 292| 0| if (start >= buffer_len) + 293| 0| return std::string::npos; + 294| 0| + 295| 0| auto const byte1{get_byte(buffer, start)}; + 296| 0| if (byte1 < 0x80) + 297| 0| return start + 1; + 298| 0| + 299| 0| if (not between_inc(byte1, 0xa1, 0xf7) or start + 2 > buffer_len) + 300| 0| PQXX_UNLIKELY + 301| 0| throw_for_encoding_error("EUC_CN", buffer, start, 1); + 302| 0| + 303| 0| auto const byte2{get_byte(buffer, start + 1)}; + 304| 0| if (not between_inc(byte2, 0xa1, 0xfe)) + 305| 0| PQXX_UNLIKELY + 306| 0| throw_for_encoding_error("EUC_CN", buffer, start, 2); + 307| 0| + 308| 0| return start + 2; + 309| 0| } + 310| |}; + 311| | + 312| | + 313| |// EUC-JP and EUC-JIS-2004 represent slightly different code points but iterate + 314| |// the same: + 315| |// + 316| |// https://en.wikipedia.org/wiki/Extended_Unix_Code#EUC-JP + 317| |// http://x0213.org/codetable/index.en.html + 318| |template<> struct glyph_scanner + 319| |{ + 320| | static PQXX_PURE std::size_t + 321| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 322| 0| { + 323| 0| if (start >= buffer_len) + 324| 0| return std::string::npos; + 325| 0| + 326| 0| auto const byte1{get_byte(buffer, start)}; + 327| 0| if (byte1 < 0x80) + 328| 0| return start + 1; + 329| 0| + 330| 0| if (start + 2 > buffer_len) + 331| 0| PQXX_UNLIKELY + 332| 0| throw_for_encoding_error("EUC_JP", buffer, start, 1); + 333| 0| + 334| 0| auto const byte2{get_byte(buffer, start + 1)}; + 335| 0| if (byte1 == 0x8e) + 336| 0| { + 337| 0| if (not between_inc(byte2, 0xa1, 0xfe)) + 338| 0| PQXX_UNLIKELY + 339| 0| throw_for_encoding_error("EUC_JP", buffer, start, 2); + 340| 0| + 341| 0| return start + 2; + 342| 0| } + 343| 0| + 344| 0| if (between_inc(byte1, 0xa1, 0xfe)) + 345| 0| { + 346| 0| if (not between_inc(byte2, 0xa1, 0xfe)) + 347| 0| PQXX_UNLIKELY + 348| 0| throw_for_encoding_error("EUC_JP", buffer, start, 2); + 349| 0| + 350| 0| return start + 2; + 351| 0| } + 352| 0| + 353| 0| if (byte1 == 0x8f and start + 3 <= buffer_len) + 354| 0| { + 355| 0| auto const byte3{get_byte(buffer, start + 2)}; + 356| 0| if ( + 357| 0| not between_inc(byte2, 0xa1, 0xfe) or + 358| 0| not between_inc(byte3, 0xa1, 0xfe)) + 359| 0| PQXX_UNLIKELY + 360| 0| throw_for_encoding_error("EUC_JP", buffer, start, 3); + 361| 0| + 362| 0| return start + 3; + 363| 0| } + 364| 0| + 365| 0| throw_for_encoding_error("EUC_JP", buffer, start, 1); + 366| 0| } + 367| |}; + 368| | + 369| | + 370| |// https://en.wikipedia.org/wiki/Extended_Unix_Code#EUC-KR + 371| |template<> struct glyph_scanner + 372| |{ + 373| | static PQXX_PURE std::size_t + 374| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 375| 0| { + 376| 0| if (start >= buffer_len) + 377| 0| PQXX_UNLIKELY return std::string::npos; + 378| 0| + 379| 0| auto const byte1{get_byte(buffer, start)}; + 380| 0| if (byte1 < 0x80) + 381| 0| return start + 1; + 382| 0| + 383| 0| if (not between_inc(byte1, 0xa1, 0xfe) or start + 2 > buffer_len) + 384| 0| PQXX_UNLIKELY + 385| 0| throw_for_encoding_error("EUC_KR", buffer, start, 1); + 386| 0| + 387| 0| auto const byte2{get_byte(buffer, start + 1)}; + 388| 0| if (not between_inc(byte2, 0xa1, 0xfe)) + 389| 0| PQXX_UNLIKELY + 390| 0| throw_for_encoding_error("EUC_KR", buffer, start, 1); + 391| 0| + 392| 0| return start + 2; + 393| 0| } + 394| |}; + 395| | + 396| | + 397| |// https://en.wikipedia.org/wiki/Extended_Unix_Code#EUC-TW + 398| |template<> struct glyph_scanner + 399| |{ + 400| | static PQXX_PURE std::size_t + 401| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 402| 0| { + 403| 0| if (start >= buffer_len) + 404| 0| PQXX_UNLIKELY + 405| 0| return std::string::npos; + 406| 0| + 407| 0| auto const byte1{get_byte(buffer, start)}; + 408| 0| if (byte1 < 0x80) + 409| 0| return start + 1; + 410| 0| + 411| 0| if (start + 2 > buffer_len) + 412| 0| PQXX_UNLIKELY + 413| 0| throw_for_encoding_error("EUC_KR", buffer, start, 1); + 414| 0| + 415| 0| auto const byte2{get_byte(buffer, start + 1)}; + 416| 0| if (between_inc(byte1, 0xa1, 0xfe)) + 417| 0| { + 418| 0| if (not between_inc(byte2, 0xa1, 0xfe)) + 419| 0| PQXX_UNLIKELY + 420| 0| throw_for_encoding_error("EUC_KR", buffer, start, 2); + 421| 0| + 422| 0| return start + 2; + 423| 0| } + 424| 0| + 425| 0| if (byte1 != 0x8e or start + 4 > buffer_len) + 426| 0| PQXX_UNLIKELY + 427| 0| throw_for_encoding_error("EUC_KR", buffer, start, 1); + 428| 0| + 429| 0| if ( + 430| 0| between_inc(byte2, 0xa1, 0xb0) and + 431| 0| between_inc(get_byte(buffer, start + 2), 0xa1, 0xfe) and + 432| 0| between_inc(get_byte(buffer, start + 3), 0xa1, 0xfe)) + 433| 0| return start + 4; + 434| 0| + 435| 0| PQXX_UNLIKELY + 436| 0| throw_for_encoding_error("EUC_KR", buffer, start, 4); + 437| 0| } + 438| |}; + 439| | + 440| | + 441| |// https://en.wikipedia.org/wiki/GB_18030#Mapping + 442| |template<> struct glyph_scanner + 443| |{ + 444| | static PQXX_PURE std::size_t + 445| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 446| 0| { + 447| 0| if (start >= buffer_len) + 448| 0| PQXX_UNLIKELY return std::string::npos; + 449| 0| + 450| 0| auto const byte1{get_byte(buffer, start)}; + 451| 0| if (byte1 < 0x80) + 452| 0| return start + 1; + 453| 0| if (byte1 == 0x80) + 454| 0| throw_for_encoding_error("GB18030", buffer, start, buffer_len - start); + 455| 0| + 456| 0| if (start + 2 > buffer_len) + 457| 0| PQXX_UNLIKELY + 458| 0| throw_for_encoding_error("GB18030", buffer, start, buffer_len - start); + 459| 0| + 460| 0| auto const byte2{get_byte(buffer, start + 1)}; + 461| 0| if (between_inc(byte2, 0x40, 0xfe)) + 462| 0| { + 463| 0| if (byte2 == 0x7f) + 464| 0| PQXX_UNLIKELY + 465| 0| throw_for_encoding_error("GB18030", buffer, start, 2); + 466| 0| + 467| 0| return start + 2; + 468| 0| } + 469| 0| + 470| 0| if (start + 4 > buffer_len) + 471| 0| PQXX_UNLIKELY + 472| 0| throw_for_encoding_error("GB18030", buffer, start, buffer_len - start); + 473| 0| + 474| 0| if ( + 475| 0| between_inc(byte2, 0x30, 0x39) and + 476| 0| between_inc(get_byte(buffer, start + 2), 0x81, 0xfe) and + 477| 0| between_inc(get_byte(buffer, start + 3), 0x30, 0x39)) + 478| 0| return start + 4; + 479| 0| + 480| 0| PQXX_UNLIKELY + 481| 0| throw_for_encoding_error("GB18030", buffer, start, 4); + 482| 0| } + 483| |}; + 484| | + 485| | + 486| |// https://en.wikipedia.org/wiki/GBK_(character_encoding)#Encoding + 487| |template<> struct glyph_scanner + 488| |{ + 489| | static PQXX_PURE std::size_t + 490| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 491| 0| { + 492| 0| if (start >= buffer_len) + 493| 0| PQXX_UNLIKELY return std::string::npos; + 494| 0| + 495| 0| auto const byte1{get_byte(buffer, start)}; + 496| 0| if (byte1 < 0x80) + 497| 0| return start + 1; + 498| 0| + 499| 0| if (start + 2 > buffer_len) + 500| 0| PQXX_UNLIKELY + 501| 0| throw_for_encoding_error("GBK", buffer, start, 1); + 502| 0| + 503| 0| auto const byte2{get_byte(buffer, start + 1)}; + 504| 0| if ( + 505| 0| (between_inc(byte1, 0xa1, 0xa9) and between_inc(byte2, 0xa1, 0xfe)) or + 506| 0| (between_inc(byte1, 0xb0, 0xf7) and between_inc(byte2, 0xa1, 0xfe)) or + 507| 0| (between_inc(byte1, 0x81, 0xa0) and between_inc(byte2, 0x40, 0xfe) and + 508| 0| byte2 != 0x7f) or + 509| 0| (between_inc(byte1, 0xaa, 0xfe) and between_inc(byte2, 0x40, 0xa0) and + 510| 0| byte2 != 0x7f) or + 511| 0| (between_inc(byte1, 0xa8, 0xa9) and between_inc(byte2, 0x40, 0xa0) and + 512| 0| byte2 != 0x7f) or + 513| 0| (between_inc(byte1, 0xaa, 0xaf) and between_inc(byte2, 0xa1, 0xfe)) or + 514| 0| (between_inc(byte1, 0xf8, 0xfe) and between_inc(byte2, 0xa1, 0xfe)) or + 515| 0| (between_inc(byte1, 0xa1, 0xa7) and between_inc(byte2, 0x40, 0xa0) and + 516| 0| byte2 != 0x7f)) + 517| 0| return start + 2; + 518| 0| + 519| 0| PQXX_UNLIKELY + 520| 0| throw_for_encoding_error("GBK", buffer, start, 2); + 521| 0| } + 522| |}; + 523| | + 524| | + 525| |/* + 526| |The PostgreSQL documentation claims that the JOHAB encoding is 1-3 bytes, but + 527| |"CJKV Information Processing" describes it (actually just the Hangul portion) + 528| |as "three five-bit segments" that reside inside 16 bits (2 bytes). + 529| | + 530| |CJKV Information Processing by Ken Lunde, pg. 269: + 531| | + 532| | https://bit.ly/2BEOu5V + 533| |*/ + 534| |template<> struct glyph_scanner + 535| |{ + 536| | static PQXX_PURE std::size_t + 537| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 538| 0| { + 539| 0| if (start >= buffer_len) + 540| 0| PQXX_UNLIKELY return std::string::npos; + 541| 0| + 542| 0| auto const byte1{get_byte(buffer, start)}; + 543| 0| if (byte1 < 0x80) + 544| 0| return start + 1; + 545| 0| + 546| 0| if (start + 2 > buffer_len) + 547| 0| PQXX_UNLIKELY + 548| 0| throw_for_encoding_error("JOHAB", buffer, start, 1); + 549| 0| + 550| 0| auto const byte2{get_byte(buffer, start)}; + 551| 0| if ( + 552| 0| (between_inc(byte1, 0x84, 0xd3) and + 553| 0| (between_inc(byte2, 0x41, 0x7e) or between_inc(byte2, 0x81, 0xfe))) or + 554| 0| ((between_inc(byte1, 0xd8, 0xde) or between_inc(byte1, 0xe0, 0xf9)) and + 555| 0| (between_inc(byte2, 0x31, 0x7e) or between_inc(byte2, 0x91, 0xfe)))) + 556| 0| return start + 2; + 557| 0| + 558| 0| PQXX_UNLIKELY + 559| 0| throw_for_encoding_error("JOHAB", buffer, start, 2); + 560| 0| } + 561| |}; + 562| | + 563| | + 564| |/* + 565| |PostgreSQL's MULE_INTERNAL is the emacs rather than Xemacs implementation; + 566| |see the server/mb/pg_wchar.h PostgreSQL header file. + 567| |This is implemented according to the description in said header file, but I was + 568| |unable to get it to successfully iterate a MULE-encoded test CSV generated + 569| |using PostgreSQL 9.2.23. Use this at your own risk. + 570| |*/ + 571| |template<> struct glyph_scanner + 572| |{ + 573| | static PQXX_PURE std::size_t + 574| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 575| 0| { + 576| 0| if (start >= buffer_len) + 577| 0| PQXX_UNLIKELY return std::string::npos; + 578| 0| + 579| 0| auto const byte1{get_byte(buffer, start)}; + 580| 0| if (byte1 < 0x80) + 581| 0| return start + 1; + 582| 0| + 583| 0| if (start + 2 > buffer_len) + 584| 0| PQXX_UNLIKELY + 585| 0| throw_for_encoding_error("MULE_INTERNAL", buffer, start, 1); + 586| 0| + 587| 0| auto const byte2{get_byte(buffer, start + 1)}; + 588| 0| if (between_inc(byte1, 0x81, 0x8d) and byte2 >= 0xa0) + 589| 0| return start + 2; + 590| 0| + 591| 0| if (start + 3 > buffer_len) + 592| 0| PQXX_UNLIKELY + 593| 0| throw_for_encoding_error("MULE_INTERNAL", buffer, start, 2); + 594| 0| + 595| 0| if ( + 596| 0| ((byte1 == 0x9a and between_inc(byte2, 0xa0, 0xdf)) or + 597| 0| (byte1 == 0x9b and between_inc(byte2, 0xe0, 0xef)) or + 598| 0| (between_inc(byte1, 0x90, 0x99) and byte2 >= 0xa0)) and + 599| 0| (byte2 >= 0xa0)) + 600| 0| return start + 3; + 601| 0| + 602| 0| if (start + 4 > buffer_len) + 603| 0| PQXX_UNLIKELY + 604| 0| throw_for_encoding_error("MULE_INTERNAL", buffer, start, 3); + 605| 0| + 606| 0| if ( + 607| 0| ((byte1 == 0x9c and between_inc(byte2, 0xf0, 0xf4)) or + 608| 0| (byte1 == 0x9d and between_inc(byte2, 0xf5, 0xfe))) and + 609| 0| get_byte(buffer, start + 2) >= 0xa0 and + 610| 0| get_byte(buffer, start + 4) >= 0xa0) + 611| 0| return start + 4; + 612| 0| + 613| 0| PQXX_UNLIKELY + 614| 0| throw_for_encoding_error("MULE_INTERNAL", buffer, start, 4); + 615| 0| } + 616| |}; + 617| | + 618| | + 619| |// As far as I can tell, for the purposes of iterating the only difference + 620| |// between SJIS and SJIS-2004 is increased range in the first byte of two-byte + 621| |// sequences (0xEF increased to 0xFC). Officially, that is; apparently the + 622| |// version of SJIS used by Postgres has the same range as SJIS-2004. They both + 623| |// have increased range over the documented versions, not having the even/odd + 624| |// restriction for the first byte in 2-byte sequences. + 625| |// + 626| |// https://en.wikipedia.org/wiki/Shift_JIS#Shift_JIS_byte_map + 627| |// http://x0213.org/codetable/index.en.html + 628| |template<> struct glyph_scanner + 629| |{ + 630| | static PQXX_PURE std::size_t + 631| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 632| 0| { + 633| 0| if (start >= buffer_len) + 634| 0| return std::string::npos; + 635| 0| + 636| 0| auto const byte1{get_byte(buffer, start)}; + 637| 0| if (byte1 < 0x80 or between_inc(byte1, 0xa1, 0xdf)) + 638| 0| return start + 1; + 639| 0| + 640| 0| if ( + 641| 0| not between_inc(byte1, 0x81, 0x9f) and + 642| 0| not between_inc(byte1, 0xe0, 0xfc)) + 643| 0| PQXX_UNLIKELY + 644| 0| throw_for_encoding_error("SJIS", buffer, start, 1); + 645| 0| + 646| 0| if (start + 2 > buffer_len) + 647| 0| PQXX_UNLIKELY + 648| 0| throw_for_encoding_error("SJIS", buffer, start, buffer_len - start); + 649| 0| + 650| 0| auto const byte2{get_byte(buffer, start + 1)}; + 651| 0| if (byte2 == 0x7f) + 652| 0| PQXX_UNLIKELY + 653| 0| throw_for_encoding_error("SJIS", buffer, start, 2); + 654| 0| + 655| 0| if (between_inc(byte2, 0x40, 0x9e) or between_inc(byte2, 0x9f, 0xfc)) + 656| 0| return start + 2; + 657| 0| + 658| 0| PQXX_UNLIKELY + 659| 0| throw_for_encoding_error("SJIS", buffer, start, 2); + 660| 0| } + 661| |}; + 662| | + 663| | + 664| |// https://en.wikipedia.org/wiki/Unified_Hangul_Code + 665| |template<> struct glyph_scanner + 666| |{ + 667| | static PQXX_PURE std::size_t + 668| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 669| 0| { + 670| 0| if (start >= buffer_len) + 671| 0| PQXX_UNLIKELY return std::string::npos; + 672| 0| + 673| 0| auto const byte1{get_byte(buffer, start)}; + 674| 0| if (byte1 < 0x80) + 675| 0| return start + 1; + 676| 0| + 677| 0| if (start + 2 > buffer_len) + 678| 0| PQXX_UNLIKELY + 679| 0| throw_for_encoding_error("UHC", buffer, start, buffer_len - start); + 680| 0| + 681| 0| auto const byte2{get_byte(buffer, start + 1)}; + 682| 0| if (between_inc(byte1, 0x80, 0xc6)) + 683| 0| { + 684| 0| if ( + 685| 0| between_inc(byte2, 0x41, 0x5a) or between_inc(byte2, 0x61, 0x7a) or + 686| 0| between_inc(byte2, 0x80, 0xfe)) + 687| 0| return start + 2; + 688| 0| + 689| 0| PQXX_UNLIKELY + 690| 0| throw_for_encoding_error("UHC", buffer, start, 2); + 691| 0| } + 692| 0| + 693| 0| if (between_inc(byte1, 0xa1, 0xfe)) + 694| 0| { + 695| 0| if (not between_inc(byte2, 0xa1, 0xfe)) + 696| 0| PQXX_UNLIKELY + 697| 0| throw_for_encoding_error("UHC", buffer, start, 2); + 698| 0| + 699| 0| return start + 2; + 700| 0| } + 701| 0| + 702| 0| throw_for_encoding_error("UHC", buffer, start, 1); + 703| 0| } + 704| |}; + 705| | + 706| | + 707| |// https://en.wikipedia.org/wiki/UTF-8#Description + 708| |template<> struct glyph_scanner + 709| |{ + 710| | static PQXX_PURE std::size_t + 711| | call(char const buffer[], std::size_t buffer_len, std::size_t start) + 712| 0| { + 713| 0| if (start >= buffer_len) + 714| 0| PQXX_UNLIKELY return std::string::npos; + 715| 0| + 716| 0| auto const byte1{get_byte(buffer, start)}; + 717| 0| if (byte1 < 0x80) + 718| 0| return start + 1; + 719| 0| + 720| 0| if (start + 2 > buffer_len) + 721| 0| PQXX_UNLIKELY + 722| 0| throw_for_encoding_error("UTF8", buffer, start, buffer_len - start); + 723| 0| + 724| 0| auto const byte2{get_byte(buffer, start + 1)}; + 725| 0| if (between_inc(byte1, 0xc0, 0xdf)) + 726| 0| { + 727| 0| if (not between_inc(byte2, 0x80, 0xbf)) + 728| 0| PQXX_UNLIKELY + 729| 0| throw_for_encoding_error("UTF8", buffer, start, 2); + 730| 0| + 731| 0| return start + 2; + 732| 0| } + 733| 0| + 734| 0| if (start + 3 > buffer_len) + 735| 0| PQXX_UNLIKELY + 736| 0| throw_for_encoding_error("UTF8", buffer, start, buffer_len - start); + 737| 0| + 738| 0| auto const byte3{get_byte(buffer, start + 2)}; + 739| 0| if (between_inc(byte1, 0xe0, 0xef)) + 740| 0| { + 741| 0| if (between_inc(byte2, 0x80, 0xbf) and between_inc(byte3, 0x80, 0xbf)) + 742| 0| return start + 3; + 743| 0| + 744| 0| PQXX_UNLIKELY + 745| 0| throw_for_encoding_error("UTF8", buffer, start, 3); + 746| 0| } + 747| 0| + 748| 0| if (start + 4 > buffer_len) + 749| 0| PQXX_UNLIKELY + 750| 0| throw_for_encoding_error("UTF8", buffer, start, buffer_len - start); + 751| 0| + 752| 0| if (between_inc(byte1, 0xf0, 0xf7)) + 753| 0| { + 754| 0| if ( + 755| 0| between_inc(byte2, 0x80, 0xbf) and between_inc(byte3, 0x80, 0xbf) and + 756| 0| between_inc(get_byte(buffer, start + 3), 0x80, 0xbf)) + 757| 0| return start + 4; + 758| 0| + 759| 0| PQXX_UNLIKELY + 760| 0| throw_for_encoding_error("UTF8", buffer, start, 4); + 761| 0| } + 762| 0| + 763| 0| PQXX_UNLIKELY + 764| 0| throw_for_encoding_error("UTF8", buffer, start, 1); + 765| 0| } + 766| |}; + 767| | + 768| | + 769| |/// Just for searching an ASCII character, what encoding can we use here? + 770| |/** Maps an encoding group to an encoding group that we can apply for the + 771| | * specific purpose of looking for a given ASCII character. + 772| | * + 773| | * The "difficult" encoding groups will map to themselves. But the ones that + 774| | * work like "ASCII supersets" have the wonderful property that even a + 775| | * multibyte character cannot contain a byte that happens to be in the ASCII + 776| | * range. This holds for the single-byte encodings, for example, but also for + 777| | * UTF-8. + 778| | * + 779| | * For those encodings, we can just pretend that we're dealing with a + 780| | * single-byte encoding and scan byte-by-byte until we find a byte with the + 781| | * value we're looking for. We don't actually need to know where the + 782| | * boundaries between the characters are. + 783| | */ + 784| |constexpr inline encoding_group + 785| |map_ascii_search_group(encoding_group enc) noexcept + 786| 0|{ + 787| 0| switch (enc) + 788| 0| { + 789| 0| case encoding_group::MONOBYTE: + 790| 0| case encoding_group::EUC_CN: + 791| 0| case encoding_group::EUC_JP: + 792| 0| case encoding_group::EUC_KR: + 793| 0| case encoding_group::EUC_TW: + 794| 0| case encoding_group::MULE_INTERNAL: + 795| 0| case encoding_group::UTF8: + 796| 0| // All these encodings are "ASCII-safe," meaning that if we're looking + 797| 0| // for a particular ASCII character, we can safely just go through the + 798| 0| // string byte for byte. Multibyte characters have the high bit set. + 799| 0| return encoding_group::MONOBYTE; + 800| 0| + 801| 0| default: PQXX_UNLIKELY return enc; + 802| 0| } + 803| 0|} + 804| | + 805| | + 806| |/// Look up a character search function for an encoding group. + 807| |/** We only define a few individual instantiations of this function, as needed. + 808| | * + 809| | * Returns a pointer to a function which looks for the first instance of any of + 810| | * the ASCII characters in `NEEDLE`. Returns its offset, or the end of the + 811| | * `haystack` if it found none. + 812| | */ + 813| |template + 814| |PQXX_PURE constexpr inline char_finder_func * + 815| |get_char_finder(encoding_group enc) + 816| |{ + 817| | auto const as_if{map_ascii_search_group(enc)}; + 818| | switch (as_if) + 819| | { + 820| | case encoding_group::MONOBYTE: + 821| | return pqxx::internal::find_ascii_char< + 822| | encoding_group::MONOBYTE, NEEDLE...>; + 823| | case encoding_group::BIG5: + 824| | return pqxx::internal::find_ascii_char; + 825| | case encoding_group::GB18030: + 826| | return pqxx::internal::find_ascii_char; + 827| | case encoding_group::GBK: + 828| | return pqxx::internal::find_ascii_char; + 829| | case encoding_group::JOHAB: + 830| | return pqxx::internal::find_ascii_char; + 831| | case encoding_group::SJIS: + 832| | return pqxx::internal::find_ascii_char; + 833| | case encoding_group::UHC: + 834| | return pqxx::internal::find_ascii_char; + 835| | + 836| | default: + 837| | throw pqxx::internal_error{concat( + 838| | "Unexpected encoding group: ", as_if, " (mapped from ", enc, ").")}; + 839| | } + 840| |} + 841| | + 842| | + 843| |/// Look up a "sentry" character search function for an encoding group. + 844| |/** This version returns a finder function that does not check buffer bounds. + 845| | * It just assumes that one of the `NEEDLE` characters will be there. + 846| | */ + 847| |template + 848| |PQXX_PURE constexpr inline char_finder_func * + 849| |get_s_char_finder(encoding_group enc) + 850| 0|{ + 851| 0| auto const as_if{map_ascii_search_group(enc)}; + 852| 0| switch (as_if) + 853| 0| { + 854| 0| case encoding_group::MONOBYTE: + 855| 0| return pqxx::internal::find_s_ascii_char< + 856| 0| encoding_group::MONOBYTE, NEEDLE...>; + 857| 0| case encoding_group::BIG5: + 858| 0| return pqxx::internal::find_s_ascii_char; + 859| 0| case encoding_group::GB18030: + 860| 0| return pqxx::internal::find_s_ascii_char< + 861| 0| encoding_group::GB18030, NEEDLE...>; + 862| 0| case encoding_group::GBK: + 863| 0| return pqxx::internal::find_s_ascii_char; + 864| 0| case encoding_group::JOHAB: + 865| 0| return pqxx::internal::find_s_ascii_char; + 866| 0| case encoding_group::SJIS: + 867| 0| return pqxx::internal::find_s_ascii_char; + 868| 0| case encoding_group::UHC: + 869| 0| return pqxx::internal::find_s_ascii_char; + 870| 0| + 871| 0| default: + 872| 0| throw pqxx::internal_error{concat( + 873| 0| "Unexpected encoding group: ", as_if, " (mapped from ", enc, ").")}; + 874| 0| } + 875| 0|} + 876| |} // namespace pqxx::internal + 877| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/internal/gates/connection-stream_from.hxx: + 1| |#if !defined(PQXX_H_CONNECTION_STREAM_FROM) + 2| |# define PQXX_H_CONNECTION_STREAM_FROM + 3| | + 4| |# include + 5| | + 6| |# include "pqxx/connection.hxx" + 7| | + 8| |namespace pqxx::internal::gate + 9| |{ + 10| |// Not publicising this call gate to specific classes. We also use it in + 11| |// stream_query, which is a template. + 12| |struct PQXX_PRIVATE connection_stream_from : callgate + 13| |{ + 14| 0| connection_stream_from(reference x) : super{x} {} + 15| | + 16| 0| auto read_copy_line() { return home().read_copy_line(); } + 17| |}; + 18| |} // namespace pqxx::internal::gate + 19| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/internal/result_iterator.hxx: + 1| |/* Definitions for the pqxx::result class and support classes. + 2| | * + 3| | * pqxx::result represents the set of result rows from a database query. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/result instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_RESULT_ITERATOR + 14| |#define PQXX_H_RESULT_ITERATOR + 15| | + 16| |#include "pqxx/row.hxx" + 17| | + 18| | + 19| |/* Result iterator. + 20| | * + 21| | * Don't include this header from your own application; it is included for you + 22| | * by other libpqxx headers. + 23| | */ + 24| | + 25| |namespace pqxx + 26| |{ + 27| |/// Iterator for rows in a result. Use as result::const_iterator. + 28| |/** A result, once obtained, cannot be modified. Therefore there is no + 29| | * plain iterator type for result. However its const_iterator type can be + 30| | * used to inspect its rows without changing them. + 31| | */ + 32| |class PQXX_LIBEXPORT const_result_iterator : public row + 33| |{ + 34| |public: + 35| | // TODO: Change operator[] so this becomes a proper random_access_iterator. + 36| | using iterator_category = std::bidirectional_iterator_tag; + 37| | using value_type = row const; + 38| | using pointer = row const *; + 39| | using reference = row; + 40| | using size_type = result_size_type; + 41| | using difference_type = result_difference_type; + 42| | + 43| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 44| | /// Create an iterator, but in an unusable state. + 45| | const_result_iterator() noexcept = default; + 46| | /// Copy an iterator. + 47| | const_result_iterator(const_result_iterator const &) noexcept = default; + 48| | /// Move an iterator. + 49| | const_result_iterator(const_result_iterator &&) noexcept = default; + 50| | + 51| | /// Begin iterating a @ref row. + 52| 0| const_result_iterator(row const &t) noexcept : row{t} {} + 53| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 54| | + 55| | /** + 56| | * @name Dereferencing operators + 57| | * + 58| | * An iterator "points to" its own row, which is also itself. This makes it + 59| | * easy to address a @ref pqxx::result as a two-dimensional container, + 60| | * without going through the intermediate step of dereferencing the iterator. + 61| | * It makes the interface similar to C pointer/array semantics. + 62| | * + 63| | * IIRC Alex Stepanov, the inventor of the STL, once remarked that having + 64| | * this as standard behaviour for pointers would be useful in some + 65| | * algorithms. So even if this makes me look foolish, I would seem to be in + 66| | * distinguished company. + 67| | */ + 68| | //@{ + 69| | /// Dereference the iterator. + 70| 0| [[nodiscard]] pointer operator->() const { return this; } + 71| | + 72| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 73| | /// Dereference the iterator. + 74| 0| [[nodiscard]] reference operator*() const { return *this; } + 75| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 76| | //@} + 77| | + 78| | /** + 79| | * @name Field access + 80| | */ + 81| | //@{ + 82| | using row::back; + 83| | using row::front; + 84| | // TODO: Replace with standard operator[]: i[n] == *(i + n). + 85| | using row::operator[]; + 86| | using row::at; + 87| | using row::rownumber; + 88| | //@} + 89| | + 90| | /** + 91| | * @name Manipulations + 92| | */ + 93| | //@{ + 94| | const_result_iterator &operator=(const_result_iterator const &rhs) + 95| 0| { + 96| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 97| 0| row::operator=(rhs); + 98| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 99| 0| return *this; + 100| 0| } + 101| | + 102| | const_result_iterator &operator=(const_result_iterator &&rhs) + 103| 0| { + 104| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 105| 0| row::operator=(std::move(rhs)); + 106| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 107| 0| return *this; + 108| 0| } + 109| | + 110| | const_result_iterator operator++(int) &; + 111| | const_result_iterator &operator++() + 112| 0| { + 113| 0| ++m_index; + 114| 0| return *this; + 115| 0| } + 116| | const_result_iterator operator--(int) &; + 117| | const_result_iterator &operator--() + 118| 0| { + 119| 0| --m_index; + 120| 0| return *this; + 121| 0| } + 122| | + 123| | const_result_iterator &operator+=(difference_type i) + 124| 0| { + 125| 0| m_index += i; + 126| 0| return *this; + 127| 0| } + 128| | const_result_iterator &operator-=(difference_type i) + 129| 0| { + 130| 0| m_index -= i; + 131| 0| return *this; + 132| 0| } + 133| | + 134| | /// Interchange two iterators in an exception-safe manner. + 135| | void swap(const_result_iterator &other) noexcept + 136| 0| { + 137| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 138| 0| row::swap(other); + 139| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 140| 0| } + 141| | //@} + 142| | + 143| | /** + 144| | * @name Comparisons + 145| | */ + 146| | //@{ + 147| | [[nodiscard]] bool operator==(const_result_iterator const &i) const + 148| 0| { + 149| 0| return m_index == i.m_index; + 150| 0| } + 151| | [[nodiscard]] bool operator!=(const_result_iterator const &i) const + 152| 0| { + 153| 0| return m_index != i.m_index; + 154| 0| } + 155| | [[nodiscard]] bool operator<(const_result_iterator const &i) const + 156| 0| { + 157| 0| return m_index < i.m_index; + 158| 0| } + 159| | [[nodiscard]] bool operator<=(const_result_iterator const &i) const + 160| 0| { + 161| 0| return m_index <= i.m_index; + 162| 0| } + 163| | [[nodiscard]] bool operator>(const_result_iterator const &i) const + 164| 0| { + 165| 0| return m_index > i.m_index; + 166| 0| } + 167| | [[nodiscard]] bool operator>=(const_result_iterator const &i) const + 168| 0| { + 169| 0| return m_index >= i.m_index; + 170| 0| } + 171| | //@} + 172| | + 173| | /** + 174| | * @name Arithmetic operators + 175| | */ + 176| | //@{ + 177| | [[nodiscard]] inline const_result_iterator operator+(difference_type) const; + 178| | friend const_result_iterator + 179| | operator+(difference_type, const_result_iterator const &); + 180| | [[nodiscard]] inline const_result_iterator operator-(difference_type) const; + 181| | [[nodiscard]] inline difference_type + 182| | operator-(const_result_iterator const &) const; + 183| | //@} + 184| | + 185| |private: + 186| | friend class pqxx::result; + 187| | const_result_iterator(pqxx::result const *r, result_size_type i) noexcept : + 188| | row{*r, i, r->columns()} + 189| 0| {} + 190| |}; + 191| | + 192| | + 193| |/// Reverse iterator for result. Use as result::const_reverse_iterator. + 194| |class PQXX_LIBEXPORT const_reverse_result_iterator + 195| | : private const_result_iterator + 196| |{ + 197| |public: + 198| | using super = const_result_iterator; + 199| | using iterator_type = const_result_iterator; + 200| | using iterator_type::difference_type; + 201| | using iterator_type::iterator_category; + 202| | using iterator_type::pointer; + 203| | using value_type = iterator_type::value_type; + 204| | using reference = iterator_type::reference; + 205| | + 206| | /// Create an iterator, but in an unusable state. + 207| | const_reverse_result_iterator() = default; + 208| | /// Copy an iterator. + 209| | const_reverse_result_iterator(const_reverse_result_iterator const &rhs) = + 210| | default; + 211| | /// Copy a reverse iterator from a regular iterator. + 212| | explicit const_reverse_result_iterator(const_result_iterator const &rhs) : + 213| | const_result_iterator{rhs} + 214| 0| { + 215| 0| super::operator--(); + 216| 0| } + 217| | + 218| | /// Move a regular iterator into a reverse iterator. + 219| | explicit const_reverse_result_iterator(const_result_iterator const &&rhs) : + 220| | const_result_iterator{std::move(rhs)} + 221| 0| { + 222| 0| super::operator--(); + 223| 0| } + 224| | + 225| | /// Return the underlying "regular" iterator (as per standard library). + 226| | [[nodiscard]] PQXX_PURE const_result_iterator base() const noexcept; + 227| | + 228| | /** + 229| | * @name Dereferencing operators + 230| | */ + 231| | //@{ + 232| | /// Dereference iterator. + 233| | using const_result_iterator::operator->; + 234| | /// Dereference iterator. + 235| | using const_result_iterator::operator*; + 236| | //@} + 237| | + 238| | /** + 239| | * @name Field access + 240| | */ + 241| | //@{ + 242| | using const_result_iterator::back; + 243| | using const_result_iterator::front; + 244| | // TODO: Replace with standard operator[]: i[n] == *(i + n). + 245| | using const_result_iterator::operator[]; + 246| | using const_result_iterator::at; + 247| | using const_result_iterator::rownumber; + 248| | //@} + 249| | + 250| | /** + 251| | * @name Manipulations + 252| | */ + 253| | //@{ + 254| | const_reverse_result_iterator & + 255| | operator=(const_reverse_result_iterator const &r) + 256| 0| { + 257| 0| iterator_type::operator=(r); + 258| 0| return *this; + 259| 0| } + 260| | const_reverse_result_iterator &operator=(const_reverse_result_iterator &&r) + 261| 0| { + 262| 0| iterator_type::operator=(std::move(r)); + 263| 0| return *this; + 264| 0| } + 265| | const_reverse_result_iterator &operator++() + 266| 0| { + 267| 0| iterator_type::operator--(); + 268| 0| return *this; + 269| 0| } + 270| | const_reverse_result_iterator operator++(int) &; + 271| | const_reverse_result_iterator &operator--() + 272| 0| { + 273| 0| iterator_type::operator++(); + 274| 0| return *this; + 275| 0| } + 276| | const_reverse_result_iterator operator--(int) &; + 277| | const_reverse_result_iterator &operator+=(difference_type i) + 278| 0| { + 279| 0| iterator_type::operator-=(i); + 280| 0| return *this; + 281| 0| } + 282| | const_reverse_result_iterator &operator-=(difference_type i) + 283| 0| { + 284| 0| iterator_type::operator+=(i); + 285| 0| return *this; + 286| 0| } + 287| | + 288| | void swap(const_reverse_result_iterator &other) noexcept + 289| 0| { + 290| 0| const_result_iterator::swap(other); + 291| 0| } + 292| | //@} + 293| | + 294| | /** + 295| | * @name Arithmetic operators + 296| | */ + 297| | //@{ + 298| | [[nodiscard]] const_reverse_result_iterator + 299| | operator+(difference_type i) const + 300| 0| { + 301| 0| return const_reverse_result_iterator(base() - i); + 302| 0| } + 303| | [[nodiscard]] const_reverse_result_iterator operator-(difference_type i) + 304| 0| { + 305| 0| return const_reverse_result_iterator(base() + i); + 306| 0| } + 307| | [[nodiscard]] difference_type + 308| | operator-(const_reverse_result_iterator const &rhs) const + 309| 0| { + 310| 0| return rhs.const_result_iterator::operator-(*this); + 311| 0| } + 312| | //@} + 313| | + 314| | /** + 315| | * @name Comparisons + 316| | */ + 317| | //@{ + 318| | [[nodiscard]] bool + 319| | operator==(const_reverse_result_iterator const &rhs) const noexcept + 320| 0| { + 321| 0| return iterator_type::operator==(rhs); + 322| 0| } + 323| | [[nodiscard]] bool + 324| | operator!=(const_reverse_result_iterator const &rhs) const noexcept + 325| 0| { + 326| 0| return not operator==(rhs); + 327| 0| } + 328| | + 329| | [[nodiscard]] bool operator<(const_reverse_result_iterator const &rhs) const + 330| 0| { + 331| 0| return iterator_type::operator>(rhs); + 332| 0| } + 333| | [[nodiscard]] bool operator<=(const_reverse_result_iterator const &rhs) const + 334| 0| { + 335| 0| return iterator_type::operator>=(rhs); + 336| 0| } + 337| | [[nodiscard]] bool operator>(const_reverse_result_iterator const &rhs) const + 338| 0| { + 339| 0| return iterator_type::operator<(rhs); + 340| 0| } + 341| | [[nodiscard]] bool operator>=(const_reverse_result_iterator const &rhs) const + 342| 0| { + 343| 0| return iterator_type::operator<=(rhs); + 344| 0| } + 345| | //@} + 346| |}; + 347| | + 348| | + 349| |inline const_result_iterator + 350| |const_result_iterator::operator+(result::difference_type o) const + 351| 0|{ + 352| 0| return {&m_result, size_type(result::difference_type(m_index) + o)}; + 353| 0|} + 354| | + 355| |inline const_result_iterator + 356| |operator+(result::difference_type o, const_result_iterator const &i) + 357| 0|{ + 358| 0| return i + o; + 359| 0|} + 360| | + 361| |inline const_result_iterator + 362| |const_result_iterator::operator-(result::difference_type o) const + 363| 0|{ + 364| 0| return {&m_result, result_size_type(result::difference_type(m_index) - o)}; + 365| 0|} + 366| | + 367| |inline result::difference_type + 368| |const_result_iterator::operator-(const const_result_iterator &i) const + 369| 0|{ + 370| 0| return result::difference_type(num() - i.num()); + 371| 0|} + 372| | + 373| |inline const_result_iterator result::end() const noexcept + 374| 0|{ + 375| 0| return {this, size()}; + 376| 0|} + 377| | + 378| | + 379| |inline const_result_iterator result::cend() const noexcept + 380| 0|{ + 381| 0| return end(); + 382| 0|} + 383| | + 384| | + 385| |inline const_reverse_result_iterator + 386| |operator+(result::difference_type n, const_reverse_result_iterator const &i) + 387| 0|{ + 388| 0| return const_reverse_result_iterator{i.base() - n}; + 389| 0|} + 390| | + 391| |} // namespace pqxx + 392| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/internal/sql_cursor.hxx: + 1| |/** Internal wrapper for SQL cursors. Supports higher-level cursor classes. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY. Other headers include it for you. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_SQL_CURSOR + 12| |#define PQXX_H_SQL_CURSOR + 13| | + 14| |namespace pqxx::internal + 15| |{ + 16| |/// Cursor with SQL positioning semantics. + 17| |/** Thin wrapper around an SQL cursor, with SQL's ideas of positioning. + 18| | * + 19| | * SQL cursors have pre-increment/pre-decrement semantics, with on either end + 20| | * of the result set a special position that does not repesent a row. This + 21| | * class models SQL cursors for the purpose of implementing more C++-like + 22| | * semantics on top. + 23| | * + 24| | * Positions of actual rows are numbered starting at 1. Position 0 exists but + 25| | * does not refer to a row. There is a similar non-row position at the end of + 26| | * the result set. + 27| | * + 28| | * Don't use this at home. You deserve better. Use the stateless_cursor + 29| | * instead. + 30| | */ + 31| |class PQXX_LIBEXPORT sql_cursor : public cursor_base + 32| |{ + 33| |public: + 34| | sql_cursor( + 35| | transaction_base &t, std::string_view query, std::string_view cname, + 36| | cursor_base::access_policy ap, cursor_base::update_policy up, + 37| | cursor_base::ownership_policy op, bool hold); + 38| | + 39| | sql_cursor( + 40| | transaction_base &t, std::string_view cname, + 41| | cursor_base::ownership_policy op); + 42| | + 43| 0| ~sql_cursor() noexcept { close(); } + 44| | + 45| | result fetch(difference_type rows, difference_type &displacement); + 46| | result fetch(difference_type rows) + 47| 0| { + 48| 0| difference_type d = 0; + 49| 0| return fetch(rows, d); + 50| 0| } + 51| | difference_type move(difference_type rows, difference_type &displacement); + 52| | difference_type move(difference_type rows) + 53| 0| { + 54| 0| difference_type d = 0; + 55| 0| return move(rows, d); + 56| 0| } + 57| | + 58| | /// Current position, or -1 for unknown + 59| | /** + 60| | * The starting position, just before the first row, counts as position zero. + 61| | * + 62| | * Position may be unknown if (and only if) this cursor was adopted, and has + 63| | * never hit its starting position (position zero). + 64| | */ + 65| 0| difference_type pos() const noexcept { return m_pos; } + 66| | + 67| | /// End position, or -1 for unknown + 68| | /** + 69| | * Returns the final position, just after the last row in the result set. The + 70| | * starting position, just before the first row, counts as position zero. + 71| | * + 72| | * End position is unknown until it is encountered during use. + 73| | */ + 74| 0| difference_type endpos() const noexcept { return m_endpos; } + 75| | + 76| | /// Return zero-row result for this cursor. + 77| 0| result const &empty_result() const noexcept { return m_empty_result; } + 78| | + 79| | void close() noexcept; + 80| | + 81| |private: + 82| | difference_type adjust(difference_type hoped, difference_type actual); + 83| | static std::string stridestring(difference_type); + 84| | /// Initialize cached empty result. Call only at beginning or end! + 85| | void init_empty_result(transaction_base &); + 86| | + 87| | /// Connection in which this cursor lives. + 88| | connection &m_home; + 89| | + 90| | /// Zero-row result from this cursor (or plain empty one if cursor is + 91| | /// adopted) + 92| | result m_empty_result; + 93| | + 94| | result m_cached_current_row; + 95| | + 96| | /// Will this cursor object destroy its SQL cursor when it dies? + 97| | cursor_base::ownership_policy m_ownership; + 98| | + 99| | /// At starting position (-1), somewhere in the middle (0), or past end (1) + 100| | int m_at_end; + 101| | + 102| | /// Position, or -1 for unknown + 103| | difference_type m_pos; + 104| | + 105| | /// End position, or -1 for unknown + 106| | difference_type m_endpos = -1; + 107| |}; + 108| | + 109| | + 110| |PQXX_LIBEXPORT result_size_type obtain_stateless_cursor_size(sql_cursor &); + 111| |PQXX_LIBEXPORT result stateless_cursor_retrieve( + 112| | sql_cursor &, result::difference_type size, + 113| | result::difference_type begin_pos, result::difference_type end_pos); + 114| |} // namespace pqxx::internal + 115| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/largeobject.hxx: + 1| |/* Large Objects interface. Deprecated; use blob instead. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/largeobject instead. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_LARGEOBJECT + 12| |#define PQXX_H_LARGEOBJECT + 13| | + 14| |#if !defined(PQXX_HEADER_PRE) + 15| |# error "Include libpqxx headers as , not ." + 16| |#endif + 17| | + 18| |#include + 19| | + 20| |#include "pqxx/dbtransaction.hxx" + 21| | + 22| | + 23| |namespace pqxx + 24| |{ + 25| |/// Identity of a large object. + 26| |/** @deprecated Use the @ref blob class instead. + 27| | * + 28| | * Encapsulates the identity of a large object. + 29| | * + 30| | * A largeobject must be accessed only from within a backend transaction, but + 31| | * the object's identity remains valid as long as the object exists. + 32| | */ + 33| |class PQXX_LIBEXPORT largeobject + 34| |{ + 35| |public: + 36| | using size_type = large_object_size_type; + 37| | + 38| | /// Refer to a nonexistent large object (similar to what a null pointer + 39| | /// does). + 40| | [[deprecated("Use blob instead.")]] largeobject() noexcept = default; + 41| | + 42| | /// Create new large object. + 43| | /** @param t Backend transaction in which the object is to be created. + 44| | */ + 45| | [[deprecated("Use blob instead.")]] explicit largeobject(dbtransaction &t); + 46| | + 47| | /// Wrap object with given oid. + 48| | /** Convert combination of a transaction and object identifier into a + 49| | * large object identity. Does not affect the database. + 50| | * @param o Object identifier for the given object. + 51| | */ + 52| | [[deprecated("Use blob instead.")]] explicit largeobject(oid o) noexcept : + 53| | m_id{o} + 54| 0| {} + 55| | + 56| | /// Import large object from a local file. + 57| | /** Creates a large object containing the data found in the given file. + 58| | * @param t Backend transaction in which the large object is to be created. + 59| | * @param file A filename on the client program's filesystem. + 60| | */ + 61| | [[deprecated("Use blob instead.")]] largeobject( + 62| | dbtransaction &t, std::string_view file); + 63| | + 64| | /// Take identity of an opened large object. + 65| | /** Copy identity of already opened large object. Note that this may be done + 66| | * as an implicit conversion. + 67| | * @param o Already opened large object to copy identity from. + 68| | */ + 69| | [[deprecated("Use blob instead.")]] largeobject( + 70| | largeobjectaccess const &o) noexcept; + 71| | + 72| | /// Object identifier. + 73| | /** The number returned by this function identifies the large object in the + 74| | * database we're connected to (or oid_none is returned if we refer to the + 75| | * null object). + 76| | */ + 77| 0| [[nodiscard]] oid id() const noexcept { return m_id; } + 78| | + 79| | /** + 80| | * @name Identity comparisons + 81| | * + 82| | * These operators compare the object identifiers of large objects. This has + 83| | * nothing to do with the objects' actual contents; use them only for keeping + 84| | * track of containers of references to large objects and such. + 85| | */ + 86| | //@{ + 87| | /// Compare object identities + 88| | /** @warning Only valid between large objects in the same database. */ + 89| | [[nodiscard]] bool operator==(largeobject const &other) const + 90| 0| { + 91| 0| return m_id == other.m_id; + 92| 0| } + 93| | /// Compare object identities + 94| | /** @warning Only valid between large objects in the same database. */ + 95| | [[nodiscard]] bool operator!=(largeobject const &other) const + 96| 0| { + 97| 0| return m_id != other.m_id; + 98| 0| } + 99| | /// Compare object identities + 100| | /** @warning Only valid between large objects in the same database. */ + 101| | [[nodiscard]] bool operator<=(largeobject const &other) const + 102| 0| { + 103| 0| return m_id <= other.m_id; + 104| 0| } + 105| | /// Compare object identities + 106| | /** @warning Only valid between large objects in the same database. */ + 107| | [[nodiscard]] bool operator>=(largeobject const &other) const + 108| 0| { + 109| 0| return m_id >= other.m_id; + 110| 0| } + 111| | /// Compare object identities + 112| | /** @warning Only valid between large objects in the same database. */ + 113| | [[nodiscard]] bool operator<(largeobject const &other) const + 114| 0| { + 115| 0| return m_id < other.m_id; + 116| 0| } + 117| | /// Compare object identities + 118| | /** @warning Only valid between large objects in the same database. */ + 119| | [[nodiscard]] bool operator>(largeobject const &other) const + 120| 0| { + 121| 0| return m_id > other.m_id; + 122| 0| } + 123| | //@} + 124| | + 125| | /// Export large object's contents to a local file + 126| | /** Writes the data stored in the large object to the given file. + 127| | * @param t Transaction in which the object is to be accessed + 128| | * @param file A filename on the client's filesystem + 129| | */ + 130| | void to_file(dbtransaction &t, std::string_view file) const; + 131| | + 132| | /// Delete large object from database + 133| | /** Unlike its low-level equivalent cunlink, this will throw an exception if + 134| | * deletion fails. + 135| | * @param t Transaction in which the object is to be deleted + 136| | */ + 137| | void remove(dbtransaction &t) const; + 138| | + 139| |protected: + 140| | PQXX_PURE static internal::pq::PGconn * + 141| | raw_connection(dbtransaction const &T); + 142| | + 143| | PQXX_PRIVATE std::string reason(connection const &, int err) const; + 144| | + 145| |private: + 146| | oid m_id = oid_none; + 147| |}; + 148| | + 149| | + 150| |/// Accessor for large object's contents. + 151| |/** @deprecated Use the `blob` class instead. + 152| | */ + 153| |class PQXX_LIBEXPORT largeobjectaccess : private largeobject + 154| |{ + 155| |public: + 156| | using largeobject::size_type; + 157| | using off_type = size_type; + 158| | using pos_type = size_type; + 159| | + 160| | /// Open mode: `in`, `out` (can be combined using "bitwise or"). + 161| | /** According to the C++ standard, these should be in `std::ios_base`. We + 162| | * take them from derived class `std::ios` instead, which is easier on the + 163| | * eyes. + 164| | * + 165| | * Historical note: taking it from std::ios was originally a workaround for a + 166| | * problem with gcc 2.95. + 167| | */ + 168| | using openmode = std::ios::openmode; + 169| | + 170| | /// Default open mode: in, out, binary. + 171| | static constexpr auto default_mode{ + 172| | std::ios::in | std::ios::out | std::ios::binary}; + 173| | + 174| | /// Seek direction: `beg`, `cur`, `end`. + 175| | using seekdir = std::ios::seekdir; + 176| | + 177| | /// Create new large object and open it. + 178| | /** + 179| | * @param t Backend transaction in which the object is to be created. + 180| | * @param mode Access mode, defaults to ios_base::in | ios_base::out | + 181| | * ios_base::binary. + 182| | */ + 183| | [[deprecated("Use blob instead.")]] explicit largeobjectaccess( + 184| | dbtransaction &t, openmode mode = default_mode); + 185| | + 186| | /// Open large object with given oid. + 187| | /** Convert combination of a transaction and object identifier into a + 188| | * large object identity. Does not affect the database. + 189| | * @param t Transaction in which the object is to be accessed. + 190| | * @param o Object identifier for the given object. + 191| | * @param mode Access mode, defaults to ios_base::in | ios_base::out | + 192| | * ios_base::binary. + 193| | */ + 194| | [[deprecated("Use blob instead.")]] largeobjectaccess( + 195| | dbtransaction &t, oid o, openmode mode = default_mode); + 196| | + 197| | /// Open given large object. + 198| | /** Open a large object with the given identity for reading and/or writing. + 199| | * @param t Transaction in which the object is to be accessed. + 200| | * @param o Identity for the large object to be accessed. + 201| | * @param mode Access mode, defaults to ios_base::in | ios_base::out | + 202| | * ios_base::binary. + 203| | */ + 204| | [[deprecated("Use blob instead.")]] largeobjectaccess( + 205| | dbtransaction &t, largeobject o, openmode mode = default_mode); + 206| | + 207| | /// Import large object from a local file and open it. + 208| | /** Creates a large object containing the data found in the given file. + 209| | * @param t Backend transaction in which the large object is to be created. + 210| | * @param file A filename on the client program's filesystem. + 211| | * @param mode Access mode, defaults to ios_base::in | ios_base::out. + 212| | */ + 213| | [[deprecated("Use blob instead.")]] largeobjectaccess( + 214| | dbtransaction &t, std::string_view file, openmode mode = default_mode); + 215| | + 216| 0| ~largeobjectaccess() noexcept { close(); } + 217| | + 218| | /// Object identifier. + 219| | /** The number returned by this function uniquely identifies the large object + 220| | * in the context of the database we're connected to. + 221| | */ + 222| | using largeobject::id; + 223| | + 224| | /// Export large object's contents to a local file. + 225| | /** Writes the data stored in the large object to the given file. + 226| | * @param file A filename on the client's filesystem. + 227| | */ + 228| | void to_file(std::string_view file) const + 229| 0| { + 230| 0| largeobject::to_file(m_trans, file); + 231| 0| } + 232| | + 233| | using largeobject::to_file; + 234| | + 235| | /** + 236| | * @name High-level access to object contents. + 237| | */ + 238| | //@{ + 239| | /// Write data to large object. + 240| | /** @warning The size of a write is currently limited to 2GB. + 241| | * + 242| | * @param buf Data to write. + 243| | * @param len Number of bytes from Buf to write. + 244| | */ + 245| | void write(char const buf[], std::size_t len); + 246| | + 247| | /// Write string to large object. + 248| | /** If not all bytes could be written, an exception is thrown. + 249| | * @param buf Data to write; no terminating zero is written. + 250| | */ + 251| 0| void write(std::string_view buf) { write(std::data(buf), std::size(buf)); } + 252| | + 253| | /// Read data from large object. + 254| | /** Throws an exception if an error occurs while reading. + 255| | * @param buf Location to store the read data in. + 256| | * @param len Number of bytes to try and read. + 257| | * @return Number of bytes read, which may be less than the number requested + 258| | * if the end of the large object is reached. + 259| | */ + 260| | size_type read(char buf[], std::size_t len); + 261| | + 262| | /// Seek in large object's data stream. + 263| | /** Throws an exception if an error occurs. + 264| | * @return The new position in the large object + 265| | */ + 266| | size_type seek(size_type dest, seekdir dir); + 267| | + 268| | /// Report current position in large object's data stream. + 269| | /** Throws an exception if an error occurs. + 270| | * @return The current position in the large object. + 271| | */ + 272| | [[nodiscard]] size_type tell() const; + 273| | //@} + 274| | + 275| | /** + 276| | * @name Low-level access to object contents. + 277| | * + 278| | * These functions provide a more "C-like" access interface, returning + 279| | * special values instead of throwing exceptions on error. These functions + 280| | * are generally best avoided in favour of the high-level access functions, + 281| | * which behave more like C++ functions should. + 282| | * + 283| | * Due to libpq's underlying API, some operations are limited to "int" + 284| | * sizes, typically 2 GB, even though a large object can grow much larger. + 285| | */ + 286| | //@{ + 287| | /// Seek in large object's data stream. + 288| | /** Does not throw exception in case of error; inspect return value and + 289| | * `errno` instead. + 290| | * @param dest Offset to go to. + 291| | * @param dir Origin to which dest is relative: ios_base::beg (from beginning + 292| | * of the object), ios_base::cur (from current access position), or + 293| | * ios_base;:end (from end of object). + 294| | * @return New position in large object, or -1 if an error occurred. + 295| | */ + 296| | pos_type cseek(off_type dest, seekdir dir) noexcept; + 297| | + 298| | /// Write to large object's data stream. + 299| | /** Does not throw exception in case of error; inspect return value and + 300| | * `errno` instead. + 301| | * @param buf Data to write. + 302| | * @param len Number of bytes to write. + 303| | * @return Number of bytes actually written, or -1 if an error occurred. + 304| | */ + 305| | off_type cwrite(char const buf[], std::size_t len) noexcept; + 306| | + 307| | /// Read from large object's data stream. + 308| | /** Does not throw exception in case of error; inspect return value and + 309| | * `errno` instead. + 310| | * @param buf Area where incoming bytes should be stored. + 311| | * @param len Number of bytes to read. + 312| | * @return Number of bytes actually read, or -1 if an error occurred.. + 313| | */ + 314| | off_type cread(char buf[], std::size_t len) noexcept; + 315| | + 316| | /// Report current position in large object's data stream. + 317| | /** Does not throw exception in case of error; inspect return value and + 318| | * `errno` instead. + 319| | * @return Current position in large object, of -1 if an error occurred. + 320| | */ + 321| | [[nodiscard]] pos_type ctell() const noexcept; + 322| | //@} + 323| | + 324| | /** + 325| | * @name Error/warning output + 326| | */ + 327| | //@{ + 328| | /// Issue message to transaction's notice processor. + 329| | void process_notice(zview) noexcept; + 330| | //@} + 331| | + 332| | using largeobject::remove; + 333| | + 334| | using largeobject::operator==; + 335| | using largeobject::operator!=; + 336| | using largeobject::operator<; + 337| | using largeobject::operator<=; + 338| | using largeobject::operator>; + 339| | using largeobject::operator>=; + 340| | + 341| | largeobjectaccess() = delete; + 342| | largeobjectaccess(largeobjectaccess const &) = delete; + 343| | largeobjectaccess operator=(largeobjectaccess const &) = delete; + 344| | + 345| |private: + 346| | PQXX_PRIVATE std::string reason(int err) const; + 347| | internal::pq::PGconn *raw_connection() const + 348| 0| { + 349| 0| return largeobject::raw_connection(m_trans); + 350| 0| } + 351| | + 352| | PQXX_PRIVATE void open(openmode mode); + 353| | void close() noexcept; + 354| | + 355| | dbtransaction &m_trans; + 356| | int m_fd = -1; + 357| |}; + 358| | + 359| | + 360| |/// Streambuf to use large objects in standard I/O streams. + 361| |/** @deprecated Access large objects directly using the @ref blob class. + 362| | * + 363| | * The standard streambuf classes provide uniform access to data storage such + 364| | * as files or string buffers, so they can be accessed using standard input or + 365| | * output streams. This streambuf implementation provided similar access to + 366| | * large objects, so they could be read and written using the same stream + 367| | * classes. + 368| | * + 369| | * This functionality was considered too fragile and complex, so it has been + 370| | * replaced with a single, much simpler class. + 371| | */ + 372| |template> + 373| |class largeobject_streambuf : public std::basic_streambuf + 374| |{ + 375| | using size_type = largeobject::size_type; + 376| | + 377| |public: + 378| | using char_type = CHAR; + 379| | using traits_type = TRAITS; + 380| | using int_type = typename traits_type::int_type; + 381| | using pos_type = typename traits_type::pos_type; + 382| | using off_type = typename traits_type::off_type; + 383| | using openmode = largeobjectaccess::openmode; + 384| | using seekdir = largeobjectaccess::seekdir; + 385| | + 386| | /// Default open mode: in, out, binary. + 387| | static constexpr auto default_mode{ + 388| | std::ios::in | std::ios::out | std::ios::binary}; + 389| | + 390| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 391| | [[deprecated("Use blob instead.")]] largeobject_streambuf( + 392| | dbtransaction &t, largeobject o, openmode mode = default_mode, + 393| | size_type buf_size = 512) : + 394| | m_bufsize{buf_size}, m_obj{t, o, mode}, m_g{nullptr}, m_p{nullptr} + 395| | { + 396| | initialize(mode); + 397| | } + 398| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 399| | + 400| | [[deprecated("Use blob instead.")]] largeobject_streambuf( + 401| | dbtransaction &t, oid o, openmode mode = default_mode, + 402| | size_type buf_size = 512) : + 403| | m_bufsize{buf_size}, m_obj{t, o, mode}, m_g{nullptr}, m_p{nullptr} + 404| | { + 405| | initialize(mode); + 406| | } + 407| | + 408| | virtual ~largeobject_streambuf() noexcept + 409| | { + 410| | delete[] m_p; + 411| | delete[] m_g; + 412| | } + 413| | + 414| | /// For use by large object stream classes. + 415| | void process_notice(zview const &s) { m_obj.process_notice(s); } + 416| | + 417| |protected: + 418| | virtual int sync() override + 419| | { + 420| | // setg() sets eback, gptr, egptr. + 421| | this->setg(this->eback(), this->eback(), this->egptr()); + 422| | return overflow(eof()); + 423| | } + 424| | + 425| | virtual pos_type seekoff(off_type offset, seekdir dir, openmode) override + 426| | { + 427| | return adjust_eof(m_obj.cseek(largeobjectaccess::off_type(offset), dir)); + 428| | } + 429| | + 430| | virtual pos_type seekpos(pos_type pos, openmode) override + 431| | { + 432| | largeobjectaccess::pos_type const newpos{ + 433| | m_obj.cseek(largeobjectaccess::off_type(pos), std::ios::beg)}; + 434| | return adjust_eof(newpos); + 435| | } + 436| | + 437| | virtual int_type overflow(int_type ch) override + 438| | { + 439| | auto *const pp{this->pptr()}; + 440| | if (pp == nullptr) + 441| | return eof(); + 442| | auto *const pb{this->pbase()}; + 443| | int_type res{0}; + 444| | + 445| | if (pp > pb) + 446| | { + 447| | auto const write_sz{pp - pb}; + 448| | auto const written_sz{ + 449| | m_obj.cwrite(pb, static_cast(pp - pb))}; + 450| | if (internal::cmp_less_equal(written_sz, 0)) + 451| | throw internal_error{ + 452| | "pqxx::largeobject: write failed " + 453| | "(is transaction still valid on write or flush?), " + 454| | "libpq reports error"}; + 455| | else if (write_sz != written_sz) + 456| | throw internal_error{ + 457| | "pqxx::largeobject: write failed " + 458| | "(is transaction still valid on write or flush?), " + + 459| | std::to_string(written_sz) + "/" + std::to_string(write_sz) + + 460| | " bytes written"}; + 461| | auto const out{adjust_eof(written_sz)}; + 462| | + 463| | if constexpr (std::is_arithmetic_v) + 464| | res = check_cast(out, "largeobject position"sv); + 465| | else + 466| | res = int_type(out); + 467| | } + 468| | this->setp(m_p, m_p + m_bufsize); + 469| | + 470| | // Write that one more character, if it's there. + 471| | if (ch != eof()) + 472| | { + 473| | *this->pptr() = static_cast(ch); + 474| | this->pbump(1); + 475| | } + 476| | return res; + 477| | } + 478| | + 479| | virtual int_type overflow() { return overflow(eof()); } + 480| | + 481| | virtual int_type underflow() override + 482| | { + 483| | if (this->gptr() == nullptr) + 484| | return eof(); + 485| | auto *const eb{this->eback()}; + 486| | auto const res{adjust_eof( + 487| | m_obj.cread(this->eback(), static_cast(m_bufsize)))}; + 488| | this->setg( + 489| | eb, eb, eb + (res == eof() ? 0 : static_cast(res))); + 490| | return (res == eof() or res == 0) ? eof() : traits_type::to_int_type(*eb); + 491| | } + 492| | + 493| |private: + 494| | /// Shortcut for traits_type::eof(). + 495| | static int_type eof() { return traits_type::eof(); } + 496| | + 497| | /// Helper: change error position of -1 to EOF (probably a no-op). + 498| | template static std::streampos adjust_eof(INTYPE pos) + 499| | { + 500| | bool const at_eof{pos == -1}; + 501| | if constexpr (std::is_arithmetic_v) + 502| | { + 503| | return check_cast( + 504| | (at_eof ? eof() : pos), "large object seek"sv); + 505| | } + 506| | else + 507| | { + 508| | return std::streampos(at_eof ? eof() : pos); + 509| | } + 510| | } + 511| | + 512| | void initialize(openmode mode) + 513| | { + 514| | if ((mode & std::ios::in) != 0) + 515| | { + 516| | m_g = new char_type[unsigned(m_bufsize)]; + 517| | this->setg(m_g, m_g, m_g); + 518| | } + 519| | if ((mode & std::ios::out) != 0) + 520| | { + 521| | m_p = new char_type[unsigned(m_bufsize)]; + 522| | this->setp(m_p, m_p + m_bufsize); + 523| | } + 524| | } + 525| | + 526| | size_type const m_bufsize; + 527| | largeobjectaccess m_obj; + 528| | + 529| | /// Get & put buffers. + 530| | char_type *m_g, *m_p; + 531| |}; + 532| | + 533| | + 534| |/// Input stream that gets its data from a large object. + 535| |/** @deprecated Access large objects directly using the @ref blob class. + 536| | * + 537| | * This class worked like any other istream, but to read data from a large + 538| | * object. It supported all formatting and streaming operations of + 539| | * `std::istream`. + 540| | * + 541| | * This functionality was considered too fragile and complex, so it has been + 542| | * replaced with a single, much simpler class. + 543| | */ + 544| |template> + 545| |class basic_ilostream : public std::basic_istream + 546| |{ + 547| | using super = std::basic_istream; + 548| | + 549| |public: + 550| | using char_type = CHAR; + 551| | using traits_type = TRAITS; + 552| | using int_type = typename traits_type::int_type; + 553| | using pos_type = typename traits_type::pos_type; + 554| | using off_type = typename traits_type::off_type; + 555| | + 556| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 557| | /// Create a basic_ilostream. + 558| | /** + 559| | * @param t Transaction in which this stream is to exist. + 560| | * @param o Large object to access. + 561| | * @param buf_size Size of buffer to use internally (optional). + 562| | */ + 563| | [[deprecated("Use blob instead.")]] basic_ilostream( + 564| | dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) : + 565| | super{nullptr}, + 566| | m_buf{t, o, std::ios::in | std::ios::binary, buf_size} + 567| | { + 568| | super::init(&m_buf); + 569| | } + 570| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 571| | + 572| | /// Create a basic_ilostream. + 573| | /** + 574| | * @param t Transaction in which this stream is to exist. + 575| | * @param o Identifier of a large object to access. + 576| | * @param buf_size Size of buffer to use internally (optional). + 577| | */ + 578| | [[deprecated("Use blob instead.")]] basic_ilostream( + 579| | dbtransaction &t, oid o, largeobject::size_type buf_size = 512) : + 580| | super{nullptr}, + 581| | m_buf{t, o, std::ios::in | std::ios::binary, buf_size} + 582| | { + 583| | super::init(&m_buf); + 584| | } + 585| | + 586| |private: + 587| | largeobject_streambuf m_buf; + 588| |}; + 589| | + 590| |using ilostream = basic_ilostream; + 591| | + 592| | + 593| |/// Output stream that writes data back to a large object. + 594| |/** @deprecated Access large objects directly using the @ref blob class. + 595| | * + 596| | * This worked like any other ostream, but to write data to a large object. + 597| | * It supported all formatting and streaming operations of `std::ostream`. + 598| | * + 599| | * This functionality was considered too fragile and complex, so it has been + 600| | * replaced with a single, much simpler class. + 601| | */ + 602| |template> + 603| |class basic_olostream : public std::basic_ostream + 604| |{ + 605| | using super = std::basic_ostream; + 606| | + 607| |public: + 608| | using char_type = CHAR; + 609| | using traits_type = TRAITS; + 610| | using int_type = typename traits_type::int_type; + 611| | using pos_type = typename traits_type::pos_type; + 612| | using off_type = typename traits_type::off_type; + 613| | + 614| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 615| | /// Create a basic_olostream. + 616| | /** + 617| | * @param t transaction in which this stream is to exist. + 618| | * @param o a large object to access. + 619| | * @param buf_size size of buffer to use internally (optional). + 620| | */ + 621| | [[deprecated("Use blob instead.")]] basic_olostream( + 622| | dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) : + 623| | super{nullptr}, + 624| | m_buf{t, o, std::ios::out | std::ios::binary, buf_size} + 625| | { + 626| | super::init(&m_buf); + 627| | } + 628| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 629| | + 630| | /// Create a basic_olostream. + 631| | /** + 632| | * @param t transaction in which this stream is to exist. + 633| | * @param o a large object to access. + 634| | * @param buf_size size of buffer to use internally (optional). + 635| | */ + 636| | [[deprecated("Use blob instead.")]] basic_olostream( + 637| | dbtransaction &t, oid o, largeobject::size_type buf_size = 512) : + 638| | super{nullptr}, + 639| | m_buf{t, o, std::ios::out | std::ios::binary, buf_size} + 640| | { + 641| | super::init(&m_buf); + 642| | } + 643| | + 644| | ~basic_olostream() + 645| | { + 646| | try + 647| | { + 648| | m_buf.pubsync(); + 649| | m_buf.pubsync(); + 650| | } + 651| | catch (std::exception const &e) + 652| | { + 653| | m_buf.process_notice(e.what()); + 654| | } + 655| | } + 656| | + 657| |private: + 658| | largeobject_streambuf m_buf; + 659| |}; + 660| | + 661| |using olostream = basic_olostream; + 662| | + 663| | + 664| |/// Stream that reads and writes a large object. + 665| |/** @deprecated Access large objects directly using the @ref blob class. + 666| | * + 667| | * This worked like a std::iostream, but to read data from, or write data to, a + 668| | * large object. It supported all formatting and streaming operations of + 669| | * `std::iostream`. + 670| | * + 671| | * This functionality was considered too fragile and complex, so it has been + 672| | * replaced with a single, much simpler class. + 673| | */ + 674| |template> + 675| |class basic_lostream : public std::basic_iostream + 676| |{ + 677| | using super = std::basic_iostream; + 678| | + 679| |public: + 680| | using char_type = CHAR; + 681| | using traits_type = TRAITS; + 682| | using int_type = typename traits_type::int_type; + 683| | using pos_type = typename traits_type::pos_type; + 684| | using off_type = typename traits_type::off_type; + 685| | + 686| | /// Create a basic_lostream. + 687| | /** + 688| | * @param t Transaction in which this stream is to exist. + 689| | * @param o Large object to access. + 690| | * @param buf_size Size of buffer to use internally (optional). + 691| | */ + 692| | [[deprecated("Use blob instead.")]] basic_lostream( + 693| | dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) : + 694| | super{nullptr}, + 695| | m_buf{ + 696| | t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size} + 697| | { + 698| | super::init(&m_buf); + 699| | } + 700| | + 701| | /// Create a basic_lostream. + 702| | /** + 703| | * @param t Transaction in which this stream is to exist. + 704| | * @param o Large object to access. + 705| | * @param buf_size Size of buffer to use internally (optional). + 706| | */ + 707| | [[deprecated("Use blob instead.")]] basic_lostream( + 708| | dbtransaction &t, oid o, largeobject::size_type buf_size = 512) : + 709| | super{nullptr}, + 710| | m_buf{ + 711| | t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size} + 712| | { + 713| | super::init(&m_buf); + 714| | } + 715| | + 716| | ~basic_lostream() + 717| | { + 718| | try + 719| | { + 720| | m_buf.pubsync(); + 721| | m_buf.pubsync(); + 722| | } + 723| | catch (std::exception const &e) + 724| | { + 725| | m_buf.process_notice(e.what()); + 726| | } + 727| | } + 728| | + 729| |private: + 730| | largeobject_streambuf m_buf; + 731| |}; + 732| | + 733| |using lostream = basic_lostream; + 734| |} // namespace pqxx + 735| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/nontransaction.hxx: + 1| |/* Definition of the pqxx::nontransaction class. + 2| | * + 3| | * pqxx::nontransaction provides nontransactional database access + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/nontransaction instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_NONTRANSACTION + 14| |#define PQXX_H_NONTRANSACTION + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include "pqxx/connection.hxx" + 21| |#include "pqxx/result.hxx" + 22| |#include "pqxx/transaction.hxx" + 23| | + 24| |namespace pqxx + 25| |{ + 26| |using namespace std::literals; + 27| | + 28| |/// Simple "transaction" class offering no transactional integrity. + 29| |/** + 30| | * @ingroup transactions + 31| | * + 32| | * nontransaction, like transaction or any other transaction_base-derived + 33| | * class, provides access to a database through a connection. Unlike its + 34| | * siblings, however, nontransaction does not maintain any kind of + 35| | * transactional integrity. This may be useful eg. for read-only access to the + 36| | * database that does not require a consistent, atomic view on its data; or for + 37| | * operations that are not allowed within a backend transaction, such as + 38| | * creating tables. + 39| | * + 40| | * For queries that update the database, however, a real transaction is likely + 41| | * to be faster unless the transaction consists of only a single record update. + 42| | * + 43| | * Also, you can keep a nontransaction open for as long as you like. Actual + 44| | * back-end transactions are limited in lifespan, and will sometimes fail just + 45| | * because they took too long to execute or were left idle for too long. This + 46| | * will not happen with a nontransaction (although the connection may still + 47| | * time out, e.g. when the network is unavailable for a very long time). + 48| | * + 49| | * Any query executed in a nontransaction is committed immediately, and neither + 50| | * commit() nor abort() has any effect as far as the database is concerned. + 51| | * Just like other transaction types, however, the nontransaction remains + 52| | * attached to the @ref pqxx::connection until you commit, abort, or destroy + 53| | * it. Just like a regular transaction, it is a @ref transaction_focus, of + 54| | * which no more than one can be active for any given connection at any given + 55| | * time. + 56| | * + 57| | * Database features that require a backend transaction, such as cursors or + 58| | * large objects, will not work in a nontransaction. + 59| | */ + 60| |class PQXX_LIBEXPORT nontransaction final : public transaction_base + 61| |{ + 62| |public: + 63| | /// Constructor. + 64| | /** Create a "dummy" transaction. + 65| | * @param cx Connection in which this "transaction" will operate. + 66| | * @param tname Optional tname for the transaction, beginning with a letter + 67| | * and containing only letters and digits. + 68| | */ + 69| | nontransaction(connection &cx, std::string_view tname = ""sv) : + 70| | transaction_base{cx, tname, std::shared_ptr{}} + 71| 0| { + 72| 0| register_transaction(); + 73| 0| } + 74| | + 75| 0| virtual ~nontransaction() override { close(); } + 76| | + 77| |private: + 78| 0| virtual void do_commit() override {} + 79| |}; + 80| |} // namespace pqxx + 81| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/notification.hxx: + 1| |/* Definition of the pqxx::notification_receiver functor interface. + 2| | * + 3| | * pqxx::notification_receiver handles incoming notifications. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/notification instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_NOTIFICATION + 14| |#define PQXX_H_NOTIFICATION + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include + 21| | + 22| |#include "pqxx/types.hxx" + 23| | + 24| | + 25| |namespace pqxx + 26| |{ + 27| |/// "Observer" base class for notifications. + 28| |/** @addtogroup notification Notifications and Receivers + 29| | * + 30| | * To listen on a notification issued using the NOTIFY command, derive your own + 31| | * class from notification_receiver and define its function-call operator to + 32| | * perform whatever action you wish to take when the given notification + 33| | * arrives. Then create an object of that class and pass it to your connection. + 34| | * DO NOT use raw SQL to listen for notifications, or your attempts to listen + 35| | * won't be resumed when a connection fails--and you'll have no way to notice. + 36| | * + 37| | * Notifications never arrive inside a transaction, not even in a + 38| | * nontransaction. Therefore, you are free to open a transaction of your own + 39| | * inside your receiver's function invocation operator. + 40| | * + 41| | * Notifications you are listening for may arrive anywhere within libpqxx code, + 42| | * but be aware that **PostgreSQL defers notifications occurring inside + 43| | * transactions.** (This was done for excellent reasons; just think about what + 44| | * happens if the transaction where you happen to handle an incoming + 45| | * notification is later rolled back for other reasons). So if you're keeping + 46| | * a transaction open, don't expect any of your receivers on the same + 47| | * connection to be notified. + 48| | * + 49| | * (For very similar reasons, outgoing notifications are also not sent until + 50| | * the transaction that sends them commits.) + 51| | * + 52| | * Multiple receivers on the same connection may listen on a notification of + 53| | * the same name. An incoming notification is processed by invoking all + 54| | * receivers (zero or more) of the same name. + 55| | */ + 56| |class PQXX_LIBEXPORT PQXX_NOVTABLE notification_receiver + 57| |{ + 58| |public: + 59| | /// Register the receiver with a connection. + 60| | /** + 61| | * @param cx Connnection to operate on. + 62| | * @param channel Name of the notification to listen for. + 63| | */ + 64| | [[deprecated("Use pqxx::connection::listen() instead.")]] + 65| | notification_receiver(connection &cx, std::string_view channel); + 66| | /// Register the receiver with a connection. + 67| | [[deprecated("Use pqxx::connection::listen() instead.")]] + 68| | notification_receiver(notification_receiver const &) = delete; + 69| | /// Register the receiver with a connection. + 70| | [[deprecated("Use pqxx::connection::listen() instead.")]] + 71| | notification_receiver &operator=(notification_receiver const &) = delete; + 72| | /// Deregister the receiver. + 73| | virtual ~notification_receiver(); + 74| | + 75| | /// The channel that this receiver listens on. + 76| 0| [[nodiscard]] std::string const &channel() const & { return m_channel; } + 77| | + 78| | /// Overridable: action to invoke when notification arrives. + 79| | /** + 80| | * @param payload An optional string that may have been passed to the NOTIFY + 81| | * command. + 82| | * @param backend_pid Process ID of the database backend process that served + 83| | * our connection when the notification arrived. The actual process ID + 84| | * behind the connection may have changed by the time this method is called. + 85| | */ + 86| | virtual void operator()(std::string const &payload, int backend_pid) = 0; + 87| | + 88| |protected: + 89| 0| connection &conn() const noexcept { return m_conn; } + 90| | + 91| |private: + 92| | connection &m_conn; + 93| | std::string m_channel; + 94| |}; + 95| |} // namespace pqxx + 96| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/params.hxx: + 1| |/* Helpers for prepared statements and parameterised statements. + 2| | * + 3| | * See @ref connection and @ref transaction_base for more. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_PARAMS + 12| |#define PQXX_H_PARAMS + 13| | + 14| |#if !defined(PQXX_HEADER_PRE) + 15| |# error "Include libpqxx headers as , not ." + 16| |#endif + 17| | + 18| |#include + 19| | + 20| |#include "pqxx/internal/concat.hxx" + 21| |#include "pqxx/internal/statement_parameters.hxx" + 22| |#include "pqxx/types.hxx" + 23| | + 24| | + 25| |namespace pqxx + 26| |{ + 27| |/// Build a parameter list for a parameterised or prepared statement. + 28| |/** When calling a parameterised statement or a prepared statement, in many + 29| | * cases you can pass parameters into the statement in the form of a + 30| | * `pqxx::params` object. + 31| | */ + 32| |class PQXX_LIBEXPORT params + 33| |{ + 34| |public: + 35| | params() = default; + 36| | + 37| | /// Pre-populate a `params` with `args`. Feel free to add more later. + 38| | template constexpr params(Args &&...args) + 39| | { + 40| | reserve(sizeof...(args)); + 41| | append_pack(std::forward(args)...); + 42| | } + 43| | + 44| | /// Pre-allocate room for at least `n` parameters. + 45| | /** This is not needed, but it may improve efficiency. + 46| | * + 47| | * Reserve space if you're going to add parameters individually, and you've + 48| | * got some idea of how many there are going to be. It may save some + 49| | * memory re-allocations. + 50| | */ + 51| | void reserve(std::size_t n) &; + 52| | + 53| | // C++20: constexpr. + 54| | /// Get the number of parameters currently in this `params`. + 55| 0| [[nodiscard]] auto size() const noexcept { return m_params.size(); } + 56| | + 57| | // C++20: Use the vector's ssize() directly and go noexcept+constexpr. + 58| | /// Get the number of parameters (signed). + 59| | /** Unlike `size()`, this is not yet `noexcept`. That's because C++17's + 60| | * `std::vector` does not have a `ssize()` member function. These member + 61| | * functions are `noexcept`, but `std::size()` and `std::ssize()` are + 62| | * not. + 63| | */ + 64| 0| [[nodiscard]] auto ssize() const { return pqxx::internal::ssize(m_params); } + 65| | + 66| | /// Append a null value. + 67| | void append() &; + 68| | + 69| | /// Append a non-null zview parameter. + 70| | /** The underlying data must stay valid for as long as the `params` + 71| | * remains active. + 72| | */ + 73| | void append(zview) &; + 74| | + 75| | /// Append a non-null string parameter. + 76| | /** Copies the underlying data into internal storage. For best efficiency, + 77| | * use the @ref zview variant if you can, or `std::move()` + 78| | */ + 79| | void append(std::string const &) &; + 80| | + 81| | /// Append a non-null string parameter. + 82| | void append(std::string &&) &; + 83| | + 84| | /// Append a non-null binary parameter. + 85| | /** The underlying data must stay valid for as long as the `params` + 86| | * remains active. + 87| | */ + 88| | void append(bytes_view) &; + 89| | + 90| | /// Append a non-null binary parameter. + 91| | /** Copies the underlying data into internal storage. For best efficiency, + 92| | * use the `pqxx::bytes_view` variant if you can, or `std::move()`. + 93| | */ + 94| | void append(bytes const &) &; + 95| | + 96| |#if defined(PQXX_HAVE_CONCEPTS) + 97| | /// Append a non-null binary parameter. + 98| | /** The `data` object must stay in place and unchanged, for as long as the + 99| | * `params` remains active. + 100| | */ + 101| | template void append(DATA const &data) & + 102| | { + 103| | append(bytes_view{std::data(data), std::size(data)}); + 104| | } + 105| |#endif // PQXX_HAVE_CONCEPTS + 106| | + 107| | /// Append a non-null binary parameter. + 108| | void append(bytes &&) &; + 109| | + 110| | /// @deprecated Append binarystring parameter. + 111| | /** The binarystring must stay valid for as long as the `params` remains + 112| | * active. + 113| | */ + 114| | void append(binarystring const &value) &; + 115| | + 116| | /// Append all parameters from value. + 117| | template + 118| | void append(pqxx::internal::dynamic_params const &value) & + 119| | { + 120| | for (auto ¶m : value) append(value.access(param)); + 121| | } + 122| | + 123| | void append(params const &value) &; + 124| | + 125| | void append(params &&value) &; + 126| | + 127| | /// Append a non-null parameter, converting it to its string + 128| | /// representation. + 129| | template void append(TYPE const &value) & + 130| | { + 131| | // TODO: Pool storage for multiple string conversions in one buffer? + 132| | if constexpr (nullness>::always_null) + 133| | { + 134| | ignore_unused(value); + 135| | m_params.emplace_back(); + 136| | } + 137| | else if (is_null(value)) + 138| | { + 139| | m_params.emplace_back(); + 140| | } + 141| | else + 142| | { + 143| | m_params.emplace_back(entry{to_string(value)}); + 144| | } + 145| | } + 146| | + 147| | /// Append all elements of `range` as parameters. + 148| | template void append_multi(RANGE const &range) & + 149| | { + 150| |#if defined(PQXX_HAVE_CONCEPTS) + 151| | if constexpr (std::ranges::sized_range) + 152| | reserve(std::size(*this) + std::size(range)); + 153| |#endif + 154| | for (auto &value : range) append(value); + 155| | } + 156| | + 157| | /// For internal use: Generate a `params` object for use in calls. + 158| | /** The params object encapsulates the pointers which we will need to pass + 159| | * to libpq when calling a parameterised or prepared statement. + 160| | * + 161| | * The pointers in the params will refer to storage owned by either the + 162| | * params object, or the caller. This is not a problem because a + 163| | * `c_params` object is guaranteed to live only while the call is going on. + 164| | * As soon as we climb back out of that call tree, we're done with that + 165| | * data. + 166| | */ + 167| | pqxx::internal::c_params make_c_params() const; + 168| | + 169| |private: + 170| | /// Recursively append a pack of params. + 171| | template + 172| | void append_pack(Arg &&arg, More &&...args) + 173| | { + 174| | this->append(std::forward(arg)); + 175| | // Recurse for remaining args. + 176| | append_pack(std::forward(args)...); + 177| | } + 178| | + 179| | /// Terminating case: append an empty parameter pack. It's not hard BTW. + 180| 0| constexpr void append_pack() noexcept {} + 181| | + 182| | // The way we store a parameter depends on whether it's binary or text + 183| | // (most types are text), and whether we're responsible for storing the + 184| | // contents. + 185| | using entry = + 186| | std::variant; + 187| | std::vector m_params; + 188| | + 189| | static constexpr std::string_view s_overflow{ + 190| | "Statement parameter length overflow."sv}; + 191| |}; + 192| | + 193| | + 194| |/// Generate parameter placeholders for use in an SQL statement. + 195| |/** When you want to pass parameters to a prepared statement or a parameterised + 196| | * statement, you insert placeholders into the SQL. During invocation, the + 197| | * database replaces those with the respective parameter values you passed. + 198| | * + 199| | * The placeholders look like `$1` (for the first parameter value), `$2` (for + 200| | * the second), and so on. You can just write those directly in your + 201| | * statement. But for those rare cases where it becomes difficult to track + 202| | * which number a placeholder should have, you can use a `placeholders` object + 203| | * to count and generate them in order. + 204| | */ + 205| |template class placeholders + 206| |{ + 207| |public: + 208| | /// Maximum number of parameters we support. + 209| | static inline constexpr unsigned int max_params{ + 210| | (std::numeric_limits::max)()}; + 211| | + 212| | placeholders() + 213| | { + 214| | static constexpr auto initial{"$1\0"sv}; + 215| | initial.copy(std::data(m_buf), std::size(initial)); + 216| | } + 217| | + 218| | /// Read an ephemeral version of the current placeholder text. + 219| | /** @warning Changing the current placeholder number will overwrite this. + 220| | * Use the view immediately, or lose it. + 221| | */ + 222| | constexpr zview view() const & noexcept + 223| | { + 224| | return zview{std::data(m_buf), m_len}; + 225| | } + 226| | + 227| | /// Read the current placeholder text, as a `std::string`. + 228| | /** This will be slightly slower than converting to a `zview`. With most + 229| | * C++ implementations however, until you get into ridiculous numbers of + 230| | * parameters, the string will benefit from the Short String Optimization, or + 231| | * SSO. + 232| | */ + 233| | std::string get() const { return std::string(std::data(m_buf), m_len); } + 234| | + 235| | /// Move on to the next parameter. + 236| | void next() & + 237| | { + 238| | if (m_current >= max_params) + 239| | throw range_error{pqxx::internal::concat( + 240| | "Too many parameters in one statement: limit is ", max_params, ".")}; + 241| | PQXX_ASSUME(m_current > 0); + 242| | ++m_current; + 243| | if (m_current % 10 == 0) + 244| | { + 245| | // Carry the 1. Don't get too clever for this relatively rare + 246| | // case, just rewrite the entire number. Leave the $ in place + 247| | // though. + 248| | char *const data{std::data(m_buf)}; + 249| | char *const end{string_traits::into_buf( + 250| | data + 1, data + std::size(m_buf), m_current)}; + 251| | // (Subtract because we don't include the trailing zero.) + 252| | m_len = check_cast(end - data, "placeholders counter") - 1; + 253| | } + 254| | else + 255| | { + 256| | PQXX_LIKELY + 257| | // Shortcut for the common case: just increment that last digit. + 258| | ++m_buf[m_len - 1]; + 259| | } + 260| | } + 261| | + 262| | /// Return the current placeholder number. The initial placeholder is 1. + 263| | COUNTER count() const noexcept { return m_current; } + 264| | + 265| |private: + 266| | /// Current placeholder number. Starts at 1. + 267| | COUNTER m_current = 1; + 268| | + 269| | /// Length of the current placeholder string, not including trailing zero. + 270| | COUNTER m_len = 2; + 271| | + 272| | /// Text buffer where we render the placeholders, with a trailing zero. + 273| | /** We keep reusing this for every subsequent placeholder, just because we + 274| | * don't like string allocations. + 275| | * + 276| | * Maximum length is the maximum base-10 digits that COUNTER can fully + 277| | * represent, plus 1 more for the extra digit that it can only partially + 278| | * fill up, plus room for the dollar sign and the trailing zero. + 279| | */ + 280| | std::array::digits10 + 3> m_buf; + 281| |}; + 282| |} // namespace pqxx + 283| | + 284| | + 285| |/// @deprecated The new @ref params class replaces all of this. + 286| |namespace pqxx::prepare + 287| |{ + 288| |/// @deprecated Use @ref params instead. + 289| |template + 290| |[[deprecated("Use the params class instead.")]] constexpr inline auto + 291| |make_dynamic_params(IT begin, IT end) + 292| |{ + 293| | return pqxx::internal::dynamic_params(begin, end); + 294| |} + 295| | + 296| | + 297| |/// @deprecated Use @ref params instead. + 298| |template + 299| |[[deprecated("Use the params class instead.")]] constexpr inline auto + 300| |make_dynamic_params(C const &container) + 301| |{ + 302| | using IT = typename C::const_iterator; + 303| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 304| | return pqxx::internal::dynamic_params{container}; + 305| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 306| |} + 307| | + 308| | + 309| |/// @deprecated Use @ref params instead. + 310| |template + 311| |[[deprecated("Use the params class instead.")]] constexpr inline auto + 312| |make_dynamic_params(C &container, ACCESSOR accessor) + 313| |{ + 314| | using IT = decltype(std::begin(container)); + 315| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 316| | return pqxx::internal::dynamic_params{container, accessor}; + 317| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 318| |} + 319| |} // namespace pqxx::prepare + 320| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/pipeline.hxx: + 1| |/* Definition of the pqxx::pipeline class. + 2| | * + 3| | * Throughput-optimized mechanism for executing queries. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/pipeline instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_PIPELINE + 14| |#define PQXX_H_PIPELINE + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include + 21| |#include + 22| |#include + 23| | + 24| |#include "pqxx/transaction_base.hxx" + 25| | + 26| | + 27| |namespace pqxx + 28| |{ + 29| |// TODO: libpq 14 introduced a similar "pipeline mode." Can we use that? + 30| | + 31| |/// Processes several queries in FIFO manner, optimized for high throughput. + 32| |/** Use a pipeline if you want to keep doing useful work while your queries are + 33| | * executing. Result retrieval is decoupled from execution request; queries + 34| | * "go in at the front" and results "come out the back." + 35| | * + 36| | * Actually, you can retrieve the results in any order if you want, but it may + 37| | * lead to surprising "time travel" effects if any of the queries fails. In + 38| | * particular, syntax errors in the queries can confuse things and show up too + 39| | * early in the stream of results. + 40| | * + 41| | * Generally, if any of the queries fails, it will throw an exception at the + 42| | * point where you request its result. But it may happen earlier, especially + 43| | * if you request results out of chronological order. + 44| | * + 45| | * @warning While a pipeline is active, you cannot execute queries, open + 46| | * streams, etc. on the same transaction. A transaction can have at most one + 47| | * object of a type derived from @ref pqxx::transaction_focus active on it at a + 48| | * time. + 49| | */ + 50| |class PQXX_LIBEXPORT pipeline : public transaction_focus + 51| |{ + 52| |public: + 53| | /// Identifying numbers for queries. + 54| | using query_id = long; + 55| | + 56| | pipeline(pipeline const &) = delete; + 57| | pipeline &operator=(pipeline const &) = delete; + 58| | pipeline(pipeline &&) = delete; + 59| | pipeline &operator=(pipeline &&) = delete; + 60| | + 61| | + 62| | /// Start a pipeline. + 63| | explicit pipeline(transaction_base &t) : transaction_focus{t, s_classname} + 64| 0| { + 65| 0| init(); + 66| 0| } + 67| | /// Start a pipeline. Assign it a name, for more helpful error messages. + 68| | pipeline(transaction_base &t, std::string_view tname) : + 69| | transaction_focus{t, s_classname, tname} + 70| 0| { + 71| 0| init(); + 72| 0| } + 73| | + 74| | /// Close the pipeline. + 75| | ~pipeline() noexcept; + 76| | + 77| | /// Add query to the pipeline. + 78| | /** Queries accumulate in the pipeline, which sends them to the backend in a + 79| | * batch separated by semicolons. The queries you insert must not use this + 80| | * trick themselves, or the pipeline will get hopelessly confused! + 81| | * + 82| | * @return Identifier for this query, unique only within this pipeline. + 83| | */ + 84| | query_id insert(std::string_view) &; + 85| | + 86| | /// Wait for all ongoing or pending operations to complete, and detach. + 87| | /** Detaches from the transaction when done. + 88| | * + 89| | * This does not produce the queries' results, so it may not report any + 90| | * errors which may have occurred in their execution. To be sure that your + 91| | * statements succeeded, call @ref retrieve until the pipeline is empty. + 92| | */ + 93| | void complete(); + 94| | + 95| | /// Forget all ongoing or pending operations and retrieved results. + 96| | /** Queries already sent to the backend may still be completed, depending + 97| | * on implementation and timing. + 98| | * + 99| | * Any error state (unless caused by an internal error) will also be cleared. + 100| | * This is mostly useful in a nontransaction, since a backend transaction is + 101| | * aborted automatically when an error occurs. + 102| | * + 103| | * Detaches from the transaction when done. + 104| | */ + 105| | void flush(); + 106| | + 107| | /// Cancel ongoing query, if any. + 108| | /** May cancel any or all of the queries that have been inserted at this + 109| | * point whose results have not yet been retrieved. If the pipeline lives in + 110| | * a backend transaction, that transaction may be left in a nonfunctional + 111| | * state in which it can only be aborted. + 112| | * + 113| | * Therefore, either use this function in a nontransaction, or abort the + 114| | * transaction after calling it. + 115| | */ + 116| | void cancel(); + 117| | + 118| | /// Is result for given query available? + 119| | [[nodiscard]] bool is_finished(query_id) const; + 120| | + 121| | /// Retrieve result for given query. + 122| | /** If the query failed for whatever reason, this will throw an exception. + 123| | * The function will block if the query has not finished yet. + 124| | * @warning If results are retrieved out-of-order, i.e. in a different order + 125| | * than the one in which their queries were inserted, errors may "propagate" + 126| | * to subsequent queries. + 127| | */ + 128| | result retrieve(query_id qid) + 129| 0| { + 130| 0| return retrieve(m_queries.find(qid)).second; + 131| 0| } + 132| | + 133| | /// Retrieve oldest unretrieved result (possibly wait for one). + 134| | /** @return The query's identifier and its result set. */ + 135| | std::pair retrieve(); + 136| | + 137| 0| [[nodiscard]] bool empty() const noexcept { return std::empty(m_queries); } + 138| | + 139| | /// Set maximum number of queries to retain before issuing them to the + 140| | /// backend. + 141| | /** The pipeline will perform better if multiple queries are issued at once, + 142| | * but retaining queries until the results are needed (as opposed to issuing + 143| | * them to the backend immediately) may negate any performance benefits the + 144| | * pipeline can offer. + 145| | * + 146| | * Recommended practice is to set this value no higher than the number of + 147| | * queries you intend to insert at a time. + 148| | * @param retain_max A nonnegative "retention capacity;" passing zero will + 149| | * cause queries to be issued immediately + 150| | * @return Old retention capacity + 151| | */ + 152| | int retain(int retain_max = 2) &; + 153| | + 154| | + 155| | /// Resume retained query emission. Harmless when not needed. + 156| | void resume() &; + 157| | + 158| |private: + 159| | struct PQXX_PRIVATE Query + 160| | { + 161| | explicit Query(std::string_view q) : + 162| | query{std::make_shared(q)} + 163| 0| {} + 164| | + 165| | std::shared_ptr query; + 166| | result res; + 167| | }; + 168| | + 169| | using QueryMap = std::map; + 170| | + 171| | void init(); + 172| | void attach(); + 173| | void detach(); + 174| | + 175| | /// Upper bound to query id's. + 176| | static constexpr query_id qid_limit() noexcept + 177| 0| { + 178| 0| // Parenthesise this to work around an eternal Visual C++ problem: + 179| 0| // Without the extra parentheses, unless NOMINMAX is defined, the + 180| 0| // preprocessor will mistake this "max" for its annoying built-in macro + 181| 0| // of the same name. + 182| 0| return (std::numeric_limits::max)(); + 183| 0| } + 184| | + 185| | /// Create new query_id. + 186| | PQXX_PRIVATE query_id generate_id(); + 187| | + 188| | bool have_pending() const noexcept + 189| 0| { + 190| 0| return m_issuedrange.second != m_issuedrange.first; + 191| 0| } + 192| | + 193| | PQXX_PRIVATE void issue(); + 194| | + 195| | /// The given query failed; never issue anything beyond that. + 196| | void set_error_at(query_id qid) noexcept + 197| 0| { + 198| 0| PQXX_UNLIKELY + 199| 0| if (qid < m_error) + 200| 0| m_error = qid; + 201| 0| } + 202| | + 203| | /// Throw pqxx::internal_error. + 204| | [[noreturn]] PQXX_PRIVATE void internal_error(std::string const &err); + 205| | + 206| | PQXX_PRIVATE bool obtain_result(bool expect_none = false); + 207| | + 208| | PQXX_PRIVATE void obtain_dummy(); + 209| | PQXX_PRIVATE void get_further_available_results(); + 210| | PQXX_PRIVATE void check_end_results(); + 211| | + 212| | /// Receive any results that happen to be available; it's not urgent. + 213| | PQXX_PRIVATE void receive_if_available(); + 214| | + 215| | /// Receive results, up to stop if possible. + 216| | PQXX_PRIVATE void receive(pipeline::QueryMap::const_iterator stop); + 217| | std::pair retrieve(pipeline::QueryMap::iterator); + 218| | + 219| | QueryMap m_queries; + 220| | std::pair m_issuedrange; + 221| | int m_retain = 0; + 222| | int m_num_waiting = 0; + 223| | query_id m_q_id = 0; + 224| | + 225| | /// Is there a "dummy query" pending? + 226| | bool m_dummy_pending = false; + 227| | + 228| | /// Point at which an error occurred; no results beyond it will be available + 229| | query_id m_error = qid_limit(); + 230| | + 231| | /// Encoding. + 232| | /** We store this in the object to avoid the risk of exceptions at awkward + 233| | * moments. + 234| | */ + 235| | internal::encoding_group m_encoding; + 236| | + 237| | static constexpr std::string_view s_classname{"pipeline"}; + 238| |}; + 239| |} // namespace pqxx + 240| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/prepared_statement.hxx: + 1| |/* Definition of the pqxx::prepped. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/prepared_statement instead. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_PREPARED_STATEMENT + 12| |#define PQXX_H_PREPARED_STATEMENT + 13| | + 14| |namespace pqxx + 15| |{ + 16| |/** + 17| | * @name Prepared statements + 18| | * + 19| | * These are very similar to parameterised statements. The difference is + 20| | * that you prepare a statement in advance, before you execute it, giving it an + 21| | * identifying name. You can then call it by this name, as many times as you + 22| | * like, passing in separate sets of argument values appropriate for each call. + 23| | * + 24| | * You prepare a statement on the connection, using + 25| | * @ref pqxx::connection::prepare(). But you then call the statement in a + 26| | * transaction, by calling + 27| | * @ref pqxx::transaction_base::exec(pqxx::prepped, pqxx::params). + 28| | * + 29| | * The @ref pqxx::prepped type is really just a zero-terminated string, but + 30| | * wrapped in its own type. This type only exists for one reason: it indicates + 31| | * that the string is not an SQL statement itself, but the _name_ of a prepared + 32| | * statement. + 33| | * + 34| | * See \ref prepared for a full discussion. + 35| | * + 36| | * @warning Beware of "nul" bytes. Any string you pass as a parameter will + 37| | * end at the first char with value zero. If you pass a string that contains + 38| | * a zero byte, the last byte in the value will be the one just before the + 39| | * zero. If you need a zero byte, you're dealing with binary strings, not + 40| | * regular strings. Represent binary strings on the SQL side as `BYTEA` + 41| | * (or as large objects). On the C++ side, use types like `pqxx::bytes` or + 42| | * `pqxx::bytes_view` or (in C++20) `std::vector`. Also, consider + 43| | * large objects on the SQL side and @ref blob on the C++ side. + 44| | * + 45| | * @warning Passing the wrong number of parameters to a prepared or + 46| | * parameterised statement will _break the connection._ The usual exception + 47| | * that occurs in this situation is @ref pqxx::protocol_violation. It's a + 48| | * subclass of @ref pqxx::broken_connection, but where `broken_connection` + 49| | * usually indicates a networking problem, `protocol_violation` indicates + 50| | * that the communication with the server has deviated from protocol. Once + 51| | * something like that happens, communication is broken and there is nothing + 52| | * for it but to discard the connection. A networking problem is usually + 53| | * worth retrying, but a protocol violation is not. Once the two ends of the + 54| | * connection disagree about where they are in their conversation, they can't + 55| | * get back on track. This is beyond libpqxx's control. + 56| | */ + 57| |//@{ + 58| | + 59| |/// A string that is the name of a prepared statement. + 60| |/** + 61| | * When calling on libpqxx to execute a prepared statement, wrap its name in + 62| | * a `prepped` object to indicate to libpqxx that it is a statement name, not + 63| | * SQL. + 64| | * + 65| | * The string must be like a C-style string: it should contain no bytes with + 66| | * value zero, but it must have a single byte with value zero directly behind + 67| | * it in memory. + 68| | */ + 69| |class PQXX_LIBEXPORT prepped : public zview + 70| |{ + 71| |public: + 72| | // TODO: May not have to be a zview! Because exec() draws a copy anyway. + 73| 0| prepped(zview name) : zview{name} {} + 74| |}; + 75| |} // namespace pqxx + 76| | + 77| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/result.hxx: + 1| |/* Definitions for the pqxx::result class and support classes. + 2| | * + 3| | * pqxx::result represents the set of result rows from a database query. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/result instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_RESULT + 14| |#define PQXX_H_RESULT + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include + 21| |#include + 22| |#include + 23| |#include + 24| |#include + 25| | + 26| |#include "pqxx/except.hxx" + 27| |#include "pqxx/types.hxx" + 28| |#include "pqxx/util.hxx" + 29| |#include "pqxx/zview.hxx" + 30| | + 31| |#include "pqxx/internal/encodings.hxx" + 32| | + 33| | + 34| |namespace pqxx::internal + 35| |{ + 36| |PQXX_LIBEXPORT void clear_result(pq::PGresult const *) noexcept; + 37| |} // namespace pqxx::internal + 38| | + 39| | + 40| |namespace pqxx::internal::gate + 41| |{ + 42| |class result_connection; + 43| |class result_creation; + 44| |class result_pipeline; + 45| |class result_row; + 46| |class result_sql_cursor; + 47| |} // namespace pqxx::internal::gate + 48| | + 49| | + 50| |namespace pqxx::internal + 51| |{ + 52| |// 9.0: Remove this, just use the notice handler in connection/result. + 53| |/// Various callbacks waiting for a notice to come in. + 54| |struct notice_waiters + 55| |{ + 56| | std::function notice_handler; + 57| | std::list errorhandlers; + 58| | + 59| | notice_waiters() = default; + 60| | notice_waiters(notice_waiters const &) = delete; + 61| | notice_waiters(notice_waiters &&) = delete; + 62| | notice_waiters &operator=(notice_waiters const &) = delete; + 63| | notice_waiters &operator=(notice_waiters &&) = delete; + 64| |}; + 65| |} // namespace pqxx::internal + 66| | + 67| | + 68| |namespace pqxx + 69| |{ + 70| |/// Result set containing data returned by a query or command. + 71| |/** This behaves as a container (as defined by the C++ standard library) and + 72| | * provides random access const iterators to iterate over its rows. You can + 73| | * also access a row by indexing a `result R` by the row's zero-based + 74| | * number: + 75| | * + 76| | * ```cxx + 77| | * for (result::size_type i=0; i < std::size(R); ++i) Process(R[i]); + 78| | * ``` + 79| | * + 80| | * Result sets in libpqxx are lightweight, reference-counted wrapper objects + 81| | * which are relatively small and cheap to copy. Think of a result object as + 82| | * a "smart pointer" to an underlying result set. + 83| | * + 84| | * @warning The result set that a result object points to is not thread-safe. + 85| | * If you copy a result object, it still refers to the same underlying result + 86| | * set. So never copy, destroy, query, or otherwise access a result while + 87| | * another thread may be copying, destroying, querying, or otherwise accessing + 88| | * the same result set--even if it is doing so through a different result + 89| | * object! + 90| | */ + 91| |class PQXX_LIBEXPORT result + 92| |{ + 93| |public: + 94| | using size_type = result_size_type; + 95| | using difference_type = result_difference_type; + 96| | using reference = row; + 97| | using const_iterator = const_result_iterator; + 98| | using pointer = const_iterator; + 99| | using iterator = const_iterator; + 100| | using const_reverse_iterator = const_reverse_result_iterator; + 101| | using reverse_iterator = const_reverse_iterator; + 102| | + 103| | result() noexcept : + 104| | m_data{}, m_query{}, m_encoding{internal::encoding_group::MONOBYTE} + 105| 0| {} + 106| | + 107| 0| result(result const &rhs) noexcept = default; + 108| | result(result &&rhs) noexcept = default; + 109| | + 110| | /// Assign one result to another. + 111| | /** Copying results is cheap: it copies only smart pointers, but the actual + 112| | * data stays in the same place. + 113| | */ + 114| | result &operator=(result const &rhs) noexcept = default; + 115| | + 116| | /// Assign one result to another, invaliding the old one. + 117| | result &operator=(result &&rhs) noexcept = default; + 118| | + 119| | /** + 120| | * @name Comparisons + 121| | * + 122| | * You can compare results for equality. Beware: this is a very strict, + 123| | * dumb comparison. The smallest difference between two results (such as a + 124| | * string "Foo" versus a string "foo") will make them unequal. + 125| | */ + 126| | //@{ + 127| | /// Compare two results for equality. + 128| | [[nodiscard]] bool operator==(result const &) const noexcept; + 129| | /// Compare two results for inequality. + 130| | [[nodiscard]] bool operator!=(result const &rhs) const noexcept + 131| 0| { + 132| 0| return not operator==(rhs); + 133| 0| } + 134| | //@} + 135| | + 136| | /// Iterate rows, reading them directly into a tuple of "TYPE...". + 137| | /** Converts the fields to values of the given respective types. + 138| | * + 139| | * Use this only with a ranged "for" loop. The iteration produces + 140| | * std::tuple which you can "unpack" to a series of `auto` + 141| | * variables. + 142| | */ + 143| | template auto iter() const; + 144| | + 145| | [[nodiscard]] const_reverse_iterator rbegin() const; + 146| | [[nodiscard]] const_reverse_iterator crbegin() const; + 147| | [[nodiscard]] const_reverse_iterator rend() const; + 148| | [[nodiscard]] const_reverse_iterator crend() const; + 149| | + 150| | [[nodiscard]] const_iterator begin() const noexcept; + 151| | [[nodiscard]] const_iterator cbegin() const noexcept; + 152| | [[nodiscard]] inline const_iterator end() const noexcept; + 153| | [[nodiscard]] inline const_iterator cend() const noexcept; + 154| | + 155| | [[nodiscard]] reference front() const noexcept; + 156| | [[nodiscard]] reference back() const noexcept; + 157| | + 158| | [[nodiscard]] PQXX_PURE size_type size() const noexcept; + 159| | [[nodiscard]] PQXX_PURE bool empty() const noexcept; + 160| 0| [[nodiscard]] size_type capacity() const noexcept { return size(); } + 161| | + 162| | /// Exchange two `result` values in an exception-safe manner. + 163| | /** If the swap fails, the two values will be exactly as they were before. + 164| | * + 165| | * The swap is not necessarily thread-safe. + 166| | */ + 167| | void swap(result &) noexcept; + 168| | + 169| | /// Index a row by number. + 170| | /** This returns a @ref row object. Generally you should not keep the row + 171| | * around as a variable, but if you do, make sure that your variable is a + 172| | * `row`, not a `row&`. + 173| | */ + 174| | [[nodiscard]] row operator[](size_type i) const noexcept; + 175| | + 176| |#if defined(PQXX_HAVE_MULTIDIM) + 177| | [[nodiscard]] field + 178| | operator[](size_type row_num, row_size_type col_num) const noexcept; + 179| |#endif // PQXX_HAVE_MULTIDIM + 180| | + 181| | /// Index a row by number, but check that the row number is valid. + 182| | row at(size_type) const; + 183| | + 184| | /// Index a field by row number and column number. + 185| | field at(size_type, row_size_type) const; + 186| | + 187| | /// Let go of the result's data. + 188| | /** Use this if you need to deallocate the result data earlier than you can + 189| | * destroy the `result` object itself. + 190| | * + 191| | * Multiple `result` objects can refer to the same set of underlying data. + 192| | * The underlying data will be deallocated once all `result` objects that + 193| | * refer to it are cleared or destroyed. + 194| | */ + 195| | void clear() noexcept + 196| 0| { + 197| 0| m_data.reset(); + 198| 0| m_query = nullptr; + 199| 0| } + 200| | + 201| | /** + 202| | * @name Column information + 203| | */ + 204| | //@{ + 205| | /// Number of columns in result. + 206| | [[nodiscard]] PQXX_PURE row_size_type columns() const noexcept; + 207| | + 208| | /// Number of given column (throws exception if it doesn't exist). + 209| | [[nodiscard]] row_size_type column_number(zview name) const; + 210| | + 211| | /// Name of column with this number (throws exception if it doesn't exist) + 212| | [[nodiscard]] char const *column_name(row_size_type number) const &; + 213| | + 214| | /// Server-side storage size for field of column's type, in bytes. + 215| | /** Returns the size of the server's internal representation of the column's + 216| | * data type. A negative value indicates the data type is variable-length. + 217| | */ + 218| | [[nodiscard]] int column_storage(row_size_type number) const; + 219| | + 220| | /// Type modifier of the column with this number. + 221| | /** The meaning of modifier values is type-specific; they typically indicate + 222| | * precision or size limits. + 223| | * + 224| | * _Use this only if you know what you're doing._ Most applications do not + 225| | * need it, and most types do not use modifiers. + 226| | * + 227| | * The value -1 indicates "no information available." + 228| | * + 229| | * @warning There is no check for errors, such as an invalid column number. + 230| | */ + 231| | [[nodiscard]] int column_type_modifier(row_size_type number) const noexcept; + 232| | + 233| | /// Return column's type, as an OID from the system catalogue. + 234| | [[nodiscard]] oid column_type(row_size_type col_num) const; + 235| | + 236| | /// Return column's type, as an OID from the system catalogue. + 237| | [[nodiscard]] oid column_type(zview col_name) const + 238| 0| { + 239| 0| return column_type(column_number(col_name)); + 240| 0| } + 241| | + 242| | /// What table did this column come from? + 243| | [[nodiscard]] oid column_table(row_size_type col_num) const; + 244| | + 245| | /// What table did this column come from? + 246| | [[nodiscard]] oid column_table(zview col_name) const + 247| 0| { + 248| 0| return column_table(column_number(col_name)); + 249| 0| } + 250| | + 251| | /// What column in its table did this column come from? + 252| | [[nodiscard]] row_size_type table_column(row_size_type col_num) const; + 253| | + 254| | /// What column in its table did this column come from? + 255| | [[nodiscard]] row_size_type table_column(zview col_name) const + 256| 0| { + 257| 0| return table_column(column_number(col_name)); + 258| 0| } + 259| | //@} + 260| | + 261| | /// Query that produced this result, if available (empty string otherwise) + 262| | [[nodiscard]] PQXX_PURE std::string const &query() const & noexcept; + 263| | + 264| | /// If command was an `INSERT` of 1 row, return oid of the inserted row. + 265| | /** @return Identifier of inserted row if exactly one row was inserted, or + 266| | * @ref oid_none otherwise. + 267| | */ + 268| | [[nodiscard]] PQXX_PURE oid inserted_oid() const; + 269| | + 270| | /// If command was `INSERT`, `UPDATE`, or `DELETE`: number of affected rows. + 271| | /** @return Number of affected rows if last command was `INSERT`, `UPDATE`, + 272| | * or `DELETE`; zero for all other commands. + 273| | */ + 274| | [[nodiscard]] PQXX_PURE size_type affected_rows() const; + 275| | + 276| | // C++20: Concept like std::invocable, but without specifying param types. + 277| | /// Run `func` on each row, passing the row's fields as parameters. + 278| | /** Goes through the rows from first to last. You provide a callable `func`. + 279| | * + 280| | * For each row in the `result`, `for_each` will call `func`. It converts + 281| | * the row's fields to the types of `func`'s parameters, and pass them to + 282| | * `func`. + 283| | * + 284| | * (Therefore `func` must have a _single_ signature. It can't be a generic + 285| | * lambda, or an object of a class with multiple overloaded function call + 286| | * operators. Otherwise, `for_each` will have no way to detect a parameter + 287| | * list without ambiguity.) + 288| | * + 289| | * If any of your parameter types is `std::string_view`, it refers to the + 290| | * underlying storage of this `result`. + 291| | * + 292| | * If any of your parameter types is a reference type, its argument will + 293| | * refer to a temporary value which only lives for the duration of that + 294| | * single invocation to `func`. If the reference is an lvalue reference, it + 295| | * must be `const`. + 296| | * + 297| | * For example, this queries employee names and salaries from the database + 298| | * and prints how much each would like to earn instead: + 299| | * ```cxx + 300| | * tx.exec("SELECT name, salary FROM employee").for_each( + 301| | * [](std::string_view name, float salary){ + 302| | * std::cout << name << " would like " << salary * 2 << ".\n"; + 303| | * }) + 304| | * ``` + 305| | * + 306| | * If `func` throws an exception, processing stops at that point and + 307| | * propagates the exception. + 308| | * + 309| | * @throws pqxx::usage_error if `func`'s number of parameters does not match + 310| | * the number of columns in this result. + 311| | * + 312| | * The parameter types must have conversions from PostgreSQL's string format + 313| | * defined; see @ref datatypes. + 314| | */ + 315| | template inline void for_each(CALLABLE &&func) const; + 316| | + 317| | /// Check that result contains exactly `n` rows. + 318| | /** @return The result itself, for convenience. + 319| | * @throw @ref unexpected_rows if the actual count is not equal to `n`. + 320| | */ + 321| | result expect_rows(size_type n) const + 322| 0| { + 323| 0| auto const sz{size()}; + 324| 0| if (sz != n) + 325| 0| { + 326| 0| // TODO: See whether result contains a generated statement. + 327| 0| if (not m_query or m_query->empty()) + 328| 0| throw unexpected_rows{pqxx::internal::concat( + 329| 0| "Expected ", n, " row(s) from query, got ", sz, ".")}; + 330| 0| else + 331| 0| throw unexpected_rows{pqxx::internal::concat( + 332| 0| "Expected ", n, " row(s) from query '", *m_query, "', got ", sz, + 333| 0| ".")}; + 334| 0| } + 335| 0| return *this; + 336| 0| } + 337| | + 338| | /// Check that result contains exactly 1 row, and return that row. + 339| | /** @return @ref pqxx::row + 340| | * @throw @ref unexpected_rows if the actual count is not equal to `n`. + 341| | */ + 342| | row one_row() const; + 343| | + 344| | /// Expect that result contains at moost one row, and return as optional. + 345| | /** Returns an empty `std::optional` if the result is empty, or if it has + 346| | * exactly one row, a `std::optional` containing the row. + 347| | * + 348| | * @throw @ref unexpected_rows is the row count is not 0 or 1. + 349| | */ + 350| | std::optional opt_row() const; + 351| | + 352| | /// Expect that result contains no rows. Return result for convenience. + 353| | result no_rows() const + 354| 0| { + 355| 0| expect_rows(0); + 356| 0| return *this; + 357| 0| } + 358| | + 359| | /// Expect that result consists of exactly `cols` columns. + 360| | /** @return The result itself, for convenience. + 361| | * @throw @ref usage_error otherwise. + 362| | */ + 363| | result expect_columns(row_size_type cols) const + 364| 0| { + 365| 0| auto const actual{columns()}; + 366| 0| if (actual != cols) + 367| 0| { + 368| 0| // TODO: See whether result contains a generated statement. + 369| 0| if (not m_query or m_query->empty()) + 370| 0| throw usage_error{pqxx::internal::concat( + 371| 0| "Expected 1 column from query, got ", actual, ".")}; + 372| 0| else + 373| 0| throw usage_error{pqxx::internal::concat( + 374| 0| "Expected 1 column from query '", *m_query, "', got ", actual, ".")}; + 375| 0| } + 376| 0| return *this; + 377| 0| } + 378| | + 379| | /// Expect that result consists of exactly 1 row and 1 column. + 380| | /** @return The one @ref pqxx::field in the result. + 381| | * @throw @ref usage_error otherwise. + 382| | */ + 383| | field one_field() const; + 384| | + 385| |private: + 386| | using data_pointer = std::shared_ptr; + 387| | + 388| | /// Underlying libpq result set. + 389| | data_pointer m_data; + 390| | + 391| | friend class pqxx::internal::gate::result_pipeline; + 392| | PQXX_PURE std::shared_ptr query_ptr() const noexcept + 393| 0| { + 394| 0| return m_query; + 395| 0| } + 396| | + 397| | /// Query string. + 398| | std::shared_ptr m_query; + 399| | + 400| | /// The connection's notice handler. + 401| | /** We're not actually using this, but we need a copy here so that the + 402| | * actual function does not get deallocated if the connection is destroyed + 403| | * while this result still exists. + 404| | */ + 405| | std::shared_ptr m_notice_waiters; + 406| | + 407| | internal::encoding_group m_encoding; + 408| | + 409| | static std::string const s_empty_string; + 410| | + 411| | friend class pqxx::field; + 412| | PQXX_PURE char const * + 413| | get_value(size_type row, row_size_type col) const noexcept; + 414| | PQXX_PURE bool get_is_null(size_type row, row_size_type col) const noexcept; + 415| | PQXX_PURE + 416| | field_size_type get_length(size_type, row_size_type) const noexcept; + 417| | + 418| | friend class pqxx::internal::gate::result_creation; + 419| | result( + 420| | std::shared_ptr const &rhs, + 421| | std::shared_ptr const &query, + 422| | std::shared_ptr const &waiters, + 423| | internal::encoding_group enc); + 424| | + 425| | PQXX_PRIVATE void check_status(std::string_view desc = ""sv) const; + 426| | + 427| | friend class pqxx::internal::gate::result_connection; + 428| | friend class pqxx::internal::gate::result_row; + 429| 0| bool operator!() const noexcept { return m_data.get() == nullptr; } + 430| 0| operator bool() const noexcept { return m_data.get() != nullptr; } + 431| | + 432| | [[noreturn]] PQXX_PRIVATE PQXX_COLD void + 433| | throw_sql_error(std::string const &Err, std::string const &Query) const; + 434| | PQXX_PRIVATE PQXX_PURE int errorposition() const; + 435| | PQXX_PRIVATE std::string status_error() const; + 436| | + 437| | friend class pqxx::internal::gate::result_sql_cursor; + 438| | PQXX_PURE char const *cmd_status() const noexcept; + 439| |}; + 440| |} // namespace pqxx + 441| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/row.hxx: + 1| |/* Definitions for the pqxx::result class and support classes. + 2| | * + 3| | * pqxx::result represents the set of result rows from a database query. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/result instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_ROW + 14| |#define PQXX_H_ROW + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include "pqxx/except.hxx" + 21| |#include "pqxx/field.hxx" + 22| |#include "pqxx/result.hxx" + 23| | + 24| |#include "pqxx/internal/concat.hxx" + 25| | + 26| |namespace pqxx::internal + 27| |{ + 28| |template class result_iter; + 29| |} // namespace pqxx::internal + 30| | + 31| | + 32| |namespace pqxx + 33| |{ + 34| |/// Reference to one row in a result. + 35| |/** A row represents one row (also called a row) in a query result set. + 36| | * It also acts as a container mapping column numbers or names to field + 37| | * values (see below): + 38| | * + 39| | * ```cxx + 40| | * cout << row["date"].c_str() << ": " << row["name"].c_str() << endl; + 41| | * ``` + 42| | * + 43| | * The row itself acts like a (non-modifyable) container, complete with its + 44| | * own const_iterator and const_reverse_iterator. + 45| | */ + 46| |class PQXX_LIBEXPORT row + 47| |{ + 48| |public: + 49| | // TODO: Some of these types conflict: class is both iterator and container. + 50| | // TODO: Set iterator nested types using std::iterator_traits. + 51| | using size_type = row_size_type; + 52| | using difference_type = row_difference_type; + 53| | using const_iterator = const_row_iterator; + 54| | using iterator = const_iterator; + 55| | using reference = field; + 56| | using pointer = const_row_iterator; + 57| | using const_reverse_iterator = const_reverse_row_iterator; + 58| | using reverse_iterator = const_reverse_iterator; + 59| | + 60| | row() noexcept = default; + 61| | row(row &&) noexcept = default; + 62| 0| row(row const &) noexcept = default; + 63| | row &operator=(row const &) noexcept = default; + 64| | row &operator=(row &&) noexcept = default; + 65| | + 66| | /** + 67| | * @name Comparison + 68| | */ + 69| | //@{ + 70| | [[nodiscard]] PQXX_PURE bool operator==(row const &) const noexcept; + 71| | [[nodiscard]] bool operator!=(row const &rhs) const noexcept + 72| 0| { + 73| 0| return not operator==(rhs); + 74| 0| } + 75| | //@} + 76| | + 77| | [[nodiscard]] const_iterator begin() const noexcept; + 78| | [[nodiscard]] const_iterator cbegin() const noexcept; + 79| | [[nodiscard]] const_iterator end() const noexcept; + 80| | [[nodiscard]] const_iterator cend() const noexcept; + 81| | + 82| | /** + 83| | * @name Field access + 84| | */ + 85| | //@{ + 86| | [[nodiscard]] reference front() const noexcept; + 87| | [[nodiscard]] reference back() const noexcept; + 88| | + 89| | [[nodiscard]] const_reverse_row_iterator rbegin() const noexcept; + 90| | [[nodiscard]] const_reverse_row_iterator crbegin() const noexcept; + 91| | [[nodiscard]] const_reverse_row_iterator rend() const noexcept; + 92| | [[nodiscard]] const_reverse_row_iterator crend() const noexcept; + 93| | + 94| | [[nodiscard]] reference operator[](size_type) const noexcept; + 95| | /** Address field by name. + 96| | * @warning This is much slower than indexing by number, or iterating. + 97| | */ + 98| | [[nodiscard]] reference operator[](zview col_name) const; + 99| | + 100| | reference at(size_type) const; + 101| | /** Address field by name. + 102| | * @warning This is much slower than indexing by number, or iterating. + 103| | */ + 104| | reference at(zview col_name) const; + 105| | + 106| | [[nodiscard]] constexpr size_type size() const noexcept + 107| 0| { + 108| 0| return m_end - m_begin; + 109| 0| } + 110| | + 111| | /// Row number, assuming this is a real row and not end()/rend(). + 112| | [[nodiscard]] constexpr result::size_type rownumber() const noexcept + 113| 0| { + 114| 0| return m_index; + 115| 0| } + 116| | + 117| | /** + 118| | * @name Column information + 119| | */ + 120| | //@{ + 121| | /// Number of given column (throws exception if it doesn't exist). + 122| | [[nodiscard]] size_type column_number(zview col_name) const; + 123| | + 124| | /// Return a column's type. + 125| | [[nodiscard]] oid column_type(size_type) const; + 126| | + 127| | /// Return a column's type. + 128| | [[nodiscard]] oid column_type(zview col_name) const + 129| 0| { + 130| 0| return column_type(column_number(col_name)); + 131| 0| } + 132| | + 133| | /// What table did this column come from? + 134| | [[nodiscard]] oid column_table(size_type col_num) const; + 135| | + 136| | /// What table did this column come from? + 137| | [[nodiscard]] oid column_table(zview col_name) const + 138| 0| { + 139| 0| return column_table(column_number(col_name)); + 140| 0| } + 141| | + 142| | /// What column number in its table did this result column come from? + 143| | /** A meaningful answer can be given only if the column in question comes + 144| | * directly from a column in a table. If the column is computed in any + 145| | * other way, a logic_error will be thrown. + 146| | * + 147| | * @param col_num a zero-based column number in this result set + 148| | * @return a zero-based column number in originating table + 149| | */ + 150| | [[nodiscard]] size_type table_column(size_type) const; + 151| | + 152| | /// What column number in its table did this result column come from? + 153| | [[nodiscard]] size_type table_column(zview col_name) const + 154| 0| { + 155| 0| return table_column(column_number(col_name)); + 156| 0| } + 157| | //@} + 158| | + 159| | [[nodiscard]] constexpr result::size_type num() const noexcept + 160| 0| { + 161| 0| return rownumber(); + 162| 0| } + 163| | + 164| | /// Extract entire row's values into a tuple. + 165| | /** Converts to the types of the tuple's respective fields. + 166| | * + 167| | * The types in the tuple must have conversions from PostgreSQL's text format + 168| | * defined; see @ref datatypes. + 169| | * + 170| | * @throw usage_error If the number of columns in the `row` does not match + 171| | * the number of fields in `t`. + 172| | */ + 173| | template void to(Tuple &t) const + 174| | { + 175| | check_size(std::tuple_size_v); + 176| | convert(t); + 177| | } + 178| | + 179| | /// Extract entire row's values into a tuple. + 180| | /** Converts to the types of the tuple's respective fields. + 181| | * + 182| | * The types must have conversions from PostgreSQL's text format defined; + 183| | * see @ref datatypes. + 184| | * + 185| | * @throw usage_error If the number of columns in the `row` does not match + 186| | * the number of fields in `t`. + 187| | */ + 188| | template std::tuple as() const + 189| | { + 190| | check_size(sizeof...(TYPE)); + 191| | using seq = std::make_index_sequence; + 192| | return get_tuple>(seq{}); + 193| | } + 194| | + 195| | [[deprecated("Swap iterators, not rows.")]] void swap(row &) noexcept; + 196| | + 197| | /** Produce a slice of this row, containing the given range of columns. + 198| | * + 199| | * @deprecated I haven't heard of anyone caring about row slicing at all in + 200| | * at least the last 15 years. Yet it adds complexity, so unless anyone + 201| | * files a bug explaining why they really need this feature, I'm going to + 202| | * remove it. Even if they do, the feature may need an update. + 203| | * + 204| | * The slice runs from the range's starting column to the range's end + 205| | * column, exclusive. It looks just like a normal result row, except + 206| | * slices can be empty. + 207| | */ + 208| | [[deprecated("Row slicing is going away. File a bug if you need it.")]] row + 209| | slice(size_type sbegin, size_type send) const; + 210| | + 211| | /// Is this a row without fields? Can only happen to a slice. + 212| | [[nodiscard, deprecated("Row slicing is going away.")]] PQXX_PURE bool + 213| | empty() const noexcept; + 214| | + 215| |protected: + 216| | friend class const_row_iterator; + 217| | friend class result; + 218| | row(result r, result_size_type index, size_type cols) noexcept; + 219| | + 220| | /// Throw @ref usage_error if row size is not `expected`. + 221| | void check_size(size_type expected) const + 222| 0| { + 223| 0| if (size() != expected) + 224| 0| throw usage_error{internal::concat( + 225| 0| "Tried to extract ", expected, " field(s) from a row of ", size(), + 226| 0| ".")}; + 227| 0| } + 228| | + 229| | /// Convert to a given tuple of values, don't check sizes. + 230| | /** We need this for cases where we have a full tuple of field types, but + 231| | * not a parameter pack. + 232| | */ + 233| | template TUPLE as_tuple() const + 234| | { + 235| | using seq = std::make_index_sequence>; + 236| | return get_tuple(seq{}); + 237| | } + 238| | + 239| | template friend class pqxx::internal::result_iter; + 240| | /// Convert entire row to tuple fields, without checking row size. + 241| | template void convert(Tuple &t) const + 242| | { + 243| | extract_fields(t, std::make_index_sequence>{}); + 244| | } + 245| | + 246| | friend class field; + 247| | + 248| | /// Result set of which this is one row. + 249| | result m_result; + 250| | + 251| | /// Row number. + 252| | /** + 253| | * You'd expect this to be unsigned, but due to the way reverse iterators + 254| | * are related to regular iterators, it must be allowed to underflow to -1. + 255| | */ + 256| | result::size_type m_index = 0; + 257| | + 258| | // TODO: Remove m_begin and (if possible) m_end when we remove slice(). + 259| | /// First column in slice. This row ignores lower-numbered columns. + 260| | size_type m_begin = 0; + 261| | /// End column in slice. This row only sees lower-numbered columns. + 262| | size_type m_end = 0; + 263| | + 264| |private: + 265| | template + 266| | void extract_fields(Tuple &t, std::index_sequence) const + 267| | { + 268| | (extract_value(t), ...); + 269| | } + 270| | + 271| | template + 272| | void extract_value(Tuple &t) const; + 273| | + 274| | /// Convert row's values as a new tuple. + 275| | template + 276| | auto get_tuple(std::index_sequence) const + 277| | { + 278| | return std::make_tuple(get_field()...); + 279| | } + 280| | + 281| | /// Extract and convert a field. + 282| | template auto get_field() const + 283| | { + 284| | return (*this)[index].as>(); + 285| | } + 286| |}; + 287| | + 288| | + 289| |/// Iterator for fields in a row. Use as row::const_iterator. + 290| |class PQXX_LIBEXPORT const_row_iterator : public field + 291| |{ + 292| |public: + 293| | using iterator_category = std::random_access_iterator_tag; + 294| | using value_type = field const; + 295| | using pointer = field const *; + 296| | using size_type = row_size_type; + 297| | using difference_type = row_difference_type; + 298| | using reference = field; + 299| | + 300| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 301| | const_row_iterator() noexcept = default; + 302| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 303| | const_row_iterator(row const &t, row_size_type c) noexcept : + 304| | field{t.m_result, t.m_index, c} + 305| 0| {} + 306| 0| const_row_iterator(field const &F) noexcept : field{F} {} + 307| | const_row_iterator(const_row_iterator const &) noexcept = default; + 308| | const_row_iterator(const_row_iterator &&) noexcept = default; + 309| | + 310| | /** + 311| | * @name Dereferencing operators + 312| | */ + 313| | //@{ + 314| 0| [[nodiscard]] constexpr pointer operator->() const noexcept { return this; } + 315| 0| [[nodiscard]] reference operator*() const noexcept { return {*this}; } + 316| | //@} + 317| | + 318| | /** + 319| | * @name Manipulations + 320| | */ + 321| | //@{ + 322| | const_row_iterator &operator=(const_row_iterator const &) noexcept = default; + 323| | const_row_iterator &operator=(const_row_iterator &&) noexcept = default; + 324| | + 325| | const_row_iterator operator++(int) & noexcept; + 326| | const_row_iterator &operator++() noexcept + 327| 0| { + 328| 0| ++m_col; + 329| 0| return *this; + 330| 0| } + 331| | const_row_iterator operator--(int) & noexcept; + 332| | const_row_iterator &operator--() noexcept + 333| 0| { + 334| 0| --m_col; + 335| 0| return *this; + 336| 0| } + 337| | + 338| | const_row_iterator &operator+=(difference_type i) noexcept + 339| 0| { + 340| 0| m_col = size_type(difference_type(m_col) + i); + 341| 0| return *this; + 342| 0| } + 343| | const_row_iterator &operator-=(difference_type i) noexcept + 344| 0| { + 345| 0| m_col = size_type(difference_type(m_col) - i); + 346| 0| return *this; + 347| 0| } + 348| | //@} + 349| | + 350| | /** + 351| | * @name Comparisons + 352| | */ + 353| | //@{ + 354| | [[nodiscard]] constexpr bool + 355| | operator==(const_row_iterator const &i) const noexcept + 356| 0| { + 357| 0| return col() == i.col(); + 358| 0| } + 359| | [[nodiscard]] constexpr bool + 360| | operator!=(const_row_iterator const &i) const noexcept + 361| 0| { + 362| 0| return col() != i.col(); + 363| 0| } + 364| | [[nodiscard]] constexpr bool + 365| | operator<(const_row_iterator const &i) const noexcept + 366| 0| { + 367| 0| return col() < i.col(); + 368| 0| } + 369| | [[nodiscard]] constexpr bool + 370| | operator<=(const_row_iterator const &i) const noexcept + 371| 0| { + 372| 0| return col() <= i.col(); + 373| 0| } + 374| | [[nodiscard]] constexpr bool + 375| | operator>(const_row_iterator const &i) const noexcept + 376| 0| { + 377| 0| return col() > i.col(); + 378| 0| } + 379| | [[nodiscard]] constexpr bool + 380| | operator>=(const_row_iterator const &i) const noexcept + 381| 0| { + 382| 0| return col() >= i.col(); + 383| 0| } + 384| | //@} + 385| | + 386| | /** + 387| | * @name Arithmetic operators + 388| | */ + 389| | //@{ + 390| | [[nodiscard]] inline const_row_iterator + 391| | operator+(difference_type) const noexcept; + 392| | + 393| | friend const_row_iterator + 394| | operator+(difference_type, const_row_iterator const &) noexcept; + 395| | + 396| | [[nodiscard]] inline const_row_iterator + 397| | operator-(difference_type) const noexcept; + 398| | [[nodiscard]] inline difference_type + 399| | operator-(const_row_iterator const &) const noexcept; + 400| | + 401| | [[nodiscard]] inline field operator[](difference_type offset) const noexcept + 402| 0| { + 403| 0| return *(*this + offset); + 404| 0| } + 405| | //@} + 406| |}; + 407| | + 408| | + 409| |/// Reverse iterator for a row. Use as row::const_reverse_iterator. + 410| |class PQXX_LIBEXPORT const_reverse_row_iterator : private const_row_iterator + 411| |{ + 412| |public: + 413| | using super = const_row_iterator; + 414| | using iterator_type = const_row_iterator; + 415| | using iterator_type::difference_type; + 416| | using iterator_type::iterator_category; + 417| | using iterator_type::pointer; + 418| | using value_type = iterator_type::value_type; + 419| | using reference = iterator_type::reference; + 420| | + 421| | const_reverse_row_iterator() noexcept = default; + 422| | const_reverse_row_iterator(const_reverse_row_iterator const &) noexcept = + 423| | default; + 424| | const_reverse_row_iterator(const_reverse_row_iterator &&) noexcept = default; + 425| | + 426| | explicit const_reverse_row_iterator(super const &rhs) noexcept : + 427| | const_row_iterator{rhs} + 428| 0| { + 429| 0| super::operator--(); + 430| 0| } + 431| | + 432| | [[nodiscard]] PQXX_PURE iterator_type base() const noexcept; + 433| | + 434| | /** + 435| | * @name Dereferencing operators + 436| | */ + 437| | //@{ + 438| | using iterator_type::operator->; + 439| | using iterator_type::operator*; + 440| | //@} + 441| | + 442| | /** + 443| | * @name Manipulations + 444| | */ + 445| | //@{ + 446| | const_reverse_row_iterator & + 447| | operator=(const_reverse_row_iterator const &r) noexcept + 448| 0| { + 449| 0| iterator_type::operator=(r); + 450| 0| return *this; + 451| 0| } + 452| | const_reverse_row_iterator operator++() noexcept + 453| 0| { + 454| 0| iterator_type::operator--(); + 455| 0| return *this; + 456| 0| } + 457| | const_reverse_row_iterator operator++(int) & noexcept; + 458| | const_reverse_row_iterator &operator--() noexcept + 459| 0| { + 460| 0| iterator_type::operator++(); + 461| 0| return *this; + 462| 0| } + 463| | const_reverse_row_iterator operator--(int) &; + 464| | const_reverse_row_iterator &operator+=(difference_type i) noexcept + 465| 0| { + 466| 0| iterator_type::operator-=(i); + 467| 0| return *this; + 468| 0| } + 469| | const_reverse_row_iterator &operator-=(difference_type i) noexcept + 470| 0| { + 471| 0| iterator_type::operator+=(i); + 472| 0| return *this; + 473| 0| } + 474| | //@} + 475| | + 476| | /** + 477| | * @name Arithmetic operators + 478| | */ + 479| | //@{ + 480| | [[nodiscard]] const_reverse_row_iterator + 481| | operator+(difference_type i) const noexcept + 482| 0| { + 483| 0| return const_reverse_row_iterator{base() - i}; + 484| 0| } + 485| | [[nodiscard]] const_reverse_row_iterator + 486| | operator-(difference_type i) noexcept + 487| 0| { + 488| 0| return const_reverse_row_iterator{base() + i}; + 489| 0| } + 490| | [[nodiscard]] difference_type + 491| | operator-(const_reverse_row_iterator const &rhs) const noexcept + 492| 0| { + 493| 0| return rhs.const_row_iterator::operator-(*this); + 494| 0| } + 495| | [[nodiscard]] inline field operator[](difference_type offset) const noexcept + 496| 0| { + 497| 0| return *(*this + offset); + 498| 0| } + 499| | //@} + 500| | + 501| | /** + 502| | * @name Comparisons + 503| | */ + 504| | //@{ + 505| | [[nodiscard]] bool + 506| | operator==(const_reverse_row_iterator const &rhs) const noexcept + 507| 0| { + 508| 0| return iterator_type::operator==(rhs); + 509| 0| } + 510| | [[nodiscard]] bool + 511| | operator!=(const_reverse_row_iterator const &rhs) const noexcept + 512| 0| { + 513| 0| return !operator==(rhs); + 514| 0| } + 515| | + 516| | [[nodiscard]] constexpr bool + 517| | operator<(const_reverse_row_iterator const &rhs) const noexcept + 518| 0| { + 519| 0| return iterator_type::operator>(rhs); + 520| 0| } + 521| | [[nodiscard]] constexpr bool + 522| | operator<=(const_reverse_row_iterator const &rhs) const noexcept + 523| 0| { + 524| 0| return iterator_type::operator>=(rhs); + 525| 0| } + 526| | [[nodiscard]] constexpr bool + 527| | operator>(const_reverse_row_iterator const &rhs) const noexcept + 528| 0| { + 529| 0| return iterator_type::operator<(rhs); + 530| 0| } + 531| | [[nodiscard]] constexpr bool + 532| | operator>=(const_reverse_row_iterator const &rhs) const noexcept + 533| 0| { + 534| 0| return iterator_type::operator<=(rhs); + 535| 0| } + 536| | //@} + 537| |}; + 538| | + 539| | + 540| |const_row_iterator + 541| |const_row_iterator::operator+(difference_type o) const noexcept + 542| 0|{ + 543| 0| // TODO:: More direct route to home().columns()? + 544| 0| return { + 545| 0| row{home(), idx(), home().columns()}, + 546| 0| size_type(difference_type(col()) + o)}; + 547| 0|} + 548| | + 549| |inline const_row_iterator operator+( + 550| | const_row_iterator::difference_type o, const_row_iterator const &i) noexcept + 551| 0|{ + 552| 0| return i + o; + 553| 0|} + 554| | + 555| |inline const_row_iterator + 556| |const_row_iterator::operator-(difference_type o) const noexcept + 557| 0|{ + 558| 0| // TODO:: More direct route to home().columns()? + 559| 0| return { + 560| 0| row{home(), idx(), home().columns()}, + 561| 0| size_type(difference_type(col()) - o)}; + 562| 0|} + 563| | + 564| |inline const_row_iterator::difference_type + 565| |const_row_iterator::operator-(const_row_iterator const &i) const noexcept + 566| 0|{ + 567| 0| return difference_type(num() - i.num()); + 568| 0|} + 569| | + 570| | + 571| |template + 572| |inline void row::extract_value(Tuple &t) const + 573| |{ + 574| | using field_type = strip_t(t))>; + 575| | field const f{m_result, m_index, index}; + 576| | std::get(t) = from_string(f); + 577| |} + 578| |} // namespace pqxx + 579| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/separated_list.hxx: + 1| |/* Helper similar to Python's `str.join()`. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/separated_list instead. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_SEPARATED_LIST + 12| |#define PQXX_H_SEPARATED_LIST + 13| | + 14| |#if !defined(PQXX_HEADER_PRE) + 15| |# error "Include libpqxx headers as , not ." + 16| |#endif + 17| | + 18| |#include + 19| |#include + 20| | + 21| |#include "pqxx/strconv.hxx" + 22| | + 23| |// C++20: Simplify using std::ranges::range. + 24| |// C++20: Optimise buffer allocation using random_access_range/iterator. + 25| |// C++23: Use std::join_with(). + 26| |// TODO: Or just use std formatting? + 27| |// TODO: Can we pass separators at compile time? + 28| |namespace pqxx + 29| |{ + 30| |/** + 31| | * @defgroup utility Utility functions + 32| | */ + 33| |//@{ + 34| | + 35| |/// Represent sequence of values as a string, joined by a given separator. + 36| |/** + 37| | * Use this to turn e.g. the numbers 1, 2, and 3 into a string "1, 2, 3". + 38| | * + 39| | * @param sep separator string (to be placed between items) + 40| | * @param begin beginning of items sequence + 41| | * @param end end of items sequence + 42| | * @param access functor defining how to dereference sequence elements + 43| | */ + 44| |template + 45| |[[nodiscard]] inline std::string + 46| |separated_list(std::string_view sep, ITER begin, ITER end, ACCESS access) + 47| 0|{ + 48| 0| if (end == begin) + 49| 0| return {}; + 50| 0| auto next{begin}; + 51| 0| ++next; + 52| 0| if (next == end) + 53| 0| return to_string(access(begin)); + 54| 0| + 55| 0| // From here on, we've got at least 2 elements -- meaning that we need sep. + 56| 0| using elt_type = strip_t; + 57| 0| using traits = string_traits; + 58| 0| + 59| 0| std::size_t budget{0}; + 60| 0| for (ITER cnt{begin}; cnt != end; ++cnt) + 61| 0| budget += traits::size_buffer(access(cnt)); + 62| 0| budget += + 63| 0| static_cast(std::distance(begin, end)) * std::size(sep); + 64| 0| + 65| 0| std::string result; + 66| 0| result.resize(budget); + 67| 0| + 68| 0| char *const data{result.data()}; + 69| 0| char *here{data}; + 70| 0| char *stop{data + budget}; + 71| 0| here = traits::into_buf(here, stop, access(begin)) - 1; + 72| 0| for (++begin; begin != end; ++begin) + 73| 0| { + 74| 0| here += sep.copy(here, std::size(sep)); + 75| 0| here = traits::into_buf(here, stop, access(begin)) - 1; + 76| 0| } + 77| 0| result.resize(static_cast(here - data)); + 78| 0| return result; + 79| 0|} + 80| | + 81| | + 82| |/// Render sequence as a string, using given separator between items. + 83| |template + 84| |[[nodiscard]] inline std::string + 85| |separated_list(std::string_view sep, ITER begin, ITER end) + 86| |{ + 87| | return separated_list(sep, begin, end, [](ITER i) { return *i; }); + 88| |} + 89| | + 90| | + 91| |// C++20: Use a concept. + 92| |/// Render items in a container as a string, using given separator. + 93| |template + 94| |[[nodiscard]] inline auto + 95| |separated_list(std::string_view sep, CONTAINER const &c) + 96| | /* + 97| | Always std::string; necessary because SFINAE doesn't work with the + 98| | contents of function bodies, so the check for iterability has to be in + 99| | the signature. + 100| | */ + 101| | -> typename std::enable_if< + 102| | (not std::is_void::value and + 103| | not std::is_void::value), + 104| | std::string>::type + 105| |{ + 106| | return separated_list(sep, std::begin(c), std::end(c)); + 107| |} + 108| | + 109| | + 110| |/// Render items in a tuple as a string, using given separator. + 111| |template< + 112| | typename TUPLE, std::size_t INDEX = 0, typename ACCESS, + 113| | typename std::enable_if< + 114| | (INDEX == std::tuple_size::value - 1), int>::type = 0> + 115| |[[nodiscard]] inline std::string separated_list( + 116| | std::string_view /* sep */, TUPLE const &t, ACCESS const &access) + 117| |{ + 118| | return to_string(access(&std::get(t))); + 119| |} + 120| | + 121| |template< + 122| | typename TUPLE, std::size_t INDEX = 0, typename ACCESS, + 123| | typename std::enable_if< + 124| | (INDEX < std::tuple_size::value - 1), int>::type = 0> + 125| |[[nodiscard]] inline std::string + 126| |separated_list(std::string_view sep, TUPLE const &t, ACCESS const &access) + 127| |{ + 128| | std::string out{to_string(access(&std::get(t)))}; + 129| | out.append(sep); + 130| | out.append(separated_list(sep, t, access)); + 131| | return out; + 132| |} + 133| | + 134| |template< + 135| | typename TUPLE, std::size_t INDEX = 0, + 136| | typename std::enable_if< + 137| | (INDEX <= std::tuple_size::value), int>::type = 0> + 138| |[[nodiscard]] inline std::string + 139| |separated_list(std::string_view sep, TUPLE const &t) + 140| |{ + 141| | // TODO: Optimise allocation. + 142| | return separated_list(sep, t, [](TUPLE const &tup) { return *tup; }); + 143| |} + 144| |//@} + 145| |} // namespace pqxx + 146| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/strconv.hxx: + 1| |/* String conversion definitions. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stringconv instead. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_STRCONV + 12| |#define PQXX_H_STRCONV + 13| | + 14| |#if !defined(PQXX_HEADER_PRE) + 15| |# error "Include libpqxx headers as , not ." + 16| |#endif + 17| | + 18| |#include + 19| |#include + 20| |#include + 21| |#include + 22| |#include + 23| |#include + 24| |#include + 25| | + 26| |// C++20: Assume support. + 27| |#if __has_include() + 28| |# include + 29| |#endif + 30| | + 31| |#include "pqxx/except.hxx" + 32| |#include "pqxx/util.hxx" + 33| |#include "pqxx/zview.hxx" + 34| | + 35| | + 36| |namespace pqxx::internal + 37| |{ + 38| |/// Attempt to demangle @c std::type_info::name() to something human-readable. + 39| |PQXX_LIBEXPORT std::string demangle_type_name(char const[]); + 40| |} // namespace pqxx::internal + 41| | + 42| | + 43| |namespace pqxx + 44| |{ + 45| |/** + 46| | * @defgroup stringconversion String conversion + 47| | * + 48| | * The PostgreSQL server accepts and represents data in string form. It has + 49| | * its own formats for various data types. The string conversions define how + 50| | * various C++ types translate to and from their respective PostgreSQL text + 51| | * representations. + 52| | * + 53| | * Each conversion is defined by a specialisations of @c string_traits. It + 54| | * gets complicated if you want top performance, but until you do, all you + 55| | * really need to care about when converting values between C++ in-memory + 56| | * representations such as @c int and the postgres string representations is + 57| | * the @c pqxx::to_string and @c pqxx::from_string functions. + 58| | * + 59| | * If you need to convert a type which is not supported out of the box, you'll + 60| | * need to define your own specialisations for these templates, similar to the + 61| | * ones defined here and in `pqxx/conversions.hxx`. Any conversion code which + 62| | * "sees" your specialisation will now support your conversion. In particular, + 63| | * you'll be able to read result fields into a variable of the new type. + 64| | * + 65| | * There is a macro to help you define conversions for individual enumeration + 66| | * types. The conversion will represent enumeration values as numeric strings. + 67| | */ + 68| |//@{ + 69| | + 70| |/// A human-readable name for a type, used in error messages and such. + 71| |/** Actually this may not always be very user-friendly. It uses + 72| | * @c std::type_info::name(). On gcc-like compilers we try to demangle its + 73| | * output. Visual Studio produces human-friendly names out of the box. + 74| | * + 75| | * This variable is not inline. Inlining it gives rise to "memory leak" + 76| | * warnings from asan, the address sanitizer, possibly from use of + 77| | * @c std::type_info::name. + 78| | */ + 79| |template + 80| |std::string const type_name{internal::demangle_type_name(typeid(TYPE).name())}; + 81| | + 82| | + 83| |/// Traits describing a type's "null value," if any. + 84| |/** Some C++ types have a special value or state which correspond directly to + 85| | * SQL's NULL. + 86| | * + 87| | * The @c nullness traits describe whether it exists, and whether a particular + 88| | * value is null. + 89| | */ + 90| |template struct nullness + 91| |{ + 92| | /// Does this type have a null value? + 93| | static bool has_null; + 94| | + 95| | /// Is this type always null? + 96| | static bool always_null; + 97| | + 98| | /// Is @c value a null? + 99| | static bool is_null(TYPE const &value); + 100| | + 101| | /// Return a null value. + 102| | /** Don't use this in generic code to compare a value and see whether it is + 103| | * null. Some types may have multiple null values which do not compare as + 104| | * equal, or may define a null value which is not equal to anything including + 105| | * itself, like in SQL. + 106| | */ + 107| | [[nodiscard]] static TYPE null(); + 108| |}; + 109| | + 110| | + 111| |/// Nullness traits describing a type which does not have a null value. + 112| |template struct no_null + 113| |{ + 114| | /// Does @c TYPE have a "built-in null value"? + 115| | /** For example, a pointer can equal @c nullptr, which makes a very natural + 116| | * representation of an SQL null value. For such types, the code sometimes + 117| | * needs to make special allowances. + 118| | * + 119| | * for most types, such as @c int or @c std::string, there is no built-in + 120| | * null. If you want to represent an SQL null value for such a type, you + 121| | * would have to wrap it in something that does have a null value. For + 122| | * example, you could use @c std::optional for "either an @c int or a + 123| | * null value." + 124| | */ + 125| | static constexpr bool has_null = false; + 126| | + 127| | /// Are all values of this type null? + 128| | /** There are a few special C++ types which are always null - mainly + 129| | * @c std::nullptr_t. + 130| | */ + 131| | static constexpr bool always_null = false; + 132| | + 133| | /// Does a given value correspond to an SQL null value? + 134| | /** Most C++ types, such as @c int or @c std::string, have no inherent null + 135| | * value. But some types such as C-style string pointers do have a natural + 136| | * equivalent to an SQL null. + 137| | */ + 138| | [[nodiscard]] static constexpr bool is_null(TYPE const &) noexcept + 139| 0| { + 140| 0| return false; + 141| 0| } + ------------------ + | Unexecuted instantiation: _ZN4pqxx7no_nullINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEE7is_nullERKS7_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7no_nullINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEE7is_nullERKS5_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7no_nullINSt3__112basic_stringISt4byteNS1_11char_traitsIS3_EENS1_9allocatorIS3_EEEEE7is_nullERKS8_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7no_nullINSt3__117basic_string_viewISt4byteNS1_11char_traitsIS3_EEEEE7is_nullERKS6_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7no_nullINS_12binarystringEE7is_nullERKS1_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7no_nullINSt3__16chrono14year_month_dayEE7is_nullERKS3_ + ------------------ + 142| |}; + 143| | + 144| | + 145| |/// Traits class for use in string conversions. + 146| |/** Specialize this template for a type for which you wish to add to_string + 147| | * and from_string support. + 148| | * + 149| | * String conversions are not meant to work for nulls. Check for null before + 150| | * converting a value of @c TYPE to a string, or vice versa, and handle them + 151| | * separately. + 152| | */ + 153| |template struct string_traits + 154| |{ + 155| | /// Is conversion from `TYPE` to strings supported? + 156| | /** When defining your own conversions, specialise this as `true` to indicate + 157| | * that your string traits support the conversions to strings. + 158| | */ + 159| | static constexpr bool converts_to_string{false}; + 160| | + 161| | /// Is conversion from `string_view` to `TYPE` supported? + 162| | /** When defining your own conversions, specialise this as `true` to indicate + 163| | * that your string traits support `from_string`. + 164| | */ + 165| | static constexpr bool converts_from_string{false}; + 166| | + 167| | /// Return a @c string_view representing value, plus terminating zero. + 168| | /** Produces a @c string_view containing the PostgreSQL string representation + 169| | * for @c value. + 170| | * + 171| | * @warning A null value has no string representation. Do not pass a null. + 172| | * + 173| | * Uses the space from @c begin to @c end as a buffer, if needed. The + 174| | * returned string may lie somewhere in that buffer, or it may be a + 175| | * compile-time constant, or it may be null if value was a null value. Even + 176| | * if the string is stored in the buffer, its @c begin() may or may not be + 177| | * the same as @c begin. + 178| | * + 179| | * The @c string_view is guaranteed to be valid as long as the buffer from + 180| | * @c begin to @c end remains accessible and unmodified. + 181| | * + 182| | * @throws pqxx::conversion_overrun if the provided buffer space may not be + 183| | * enough. For maximum performance, this is a conservative estimate. It may + 184| | * complain about a buffer which is actually large enough for your value, if + 185| | * an exact check gets too expensive. + 186| | */ + 187| | [[nodiscard]] static inline zview + 188| | to_buf(char *begin, char *end, TYPE const &value); + 189| | + 190| | /// Write value's string representation into buffer at @c begin. + 191| | /* @warning A null value has no string representation. Do not pass a null. + 192| | * + 193| | * Writes value's string representation into the buffer, starting exactly at + 194| | * @c begin, and ensuring a trailing zero. Returns the address just beyond + 195| | * the trailing zero, so the caller could use it as the @c begin for another + 196| | * call to @c into_buf writing a next value. + 197| | */ + 198| | static inline char *into_buf(char *begin, char *end, TYPE const &value); + 199| | + 200| | /// Parse a string representation of a @c TYPE value. + 201| | /** Throws @c conversion_error if @c value does not meet the expected format + 202| | * for a value of this type. + 203| | * + 204| | * @warning A null value has no string representation. Do not parse a null. + 205| | */ + 206| | [[nodiscard]] static inline TYPE from_string(std::string_view text); + 207| | + 208| | // C++20: Can we make these all constexpr? + 209| | /// Estimate how much buffer space is needed to represent value. + 210| | /** The estimate may be a little pessimistic, if it saves time. + 211| | * + 212| | * The estimate includes the terminating zero. + 213| | */ + 214| | [[nodiscard]] static inline std::size_t + 215| | size_buffer(TYPE const &value) noexcept; + 216| | + 217| | // TODO: Move is_unquoted_safe into the traits after all? + 218| |}; + 219| | + 220| | + 221| |/// Nonexistent function to indicate a disallowed type conversion. + 222| |/** There is no implementation for this function, so any reference to it will + 223| | * fail to link. The error message will mention the function name and its + 224| | * template argument, as a deliberate message to an application developer that + 225| | * their code is attempting to use a deliberately unsupported conversion. + 226| | * + 227| | * There are some C++ types that you may want to convert to or from SQL values, + 228| | * but which libpqxx deliberately does not support. Take `char` for example: + 229| | * we define no conversions for that type because it is not inherently clear + 230| | * whether whether the corresponding SQL type should be a single-character + 231| | * string, a small integer, a raw byte value, etc. The intention could differ + 232| | * from one call site to the next. + 233| | * + 234| | * If an application attempts to convert these types, we try to make sure that + 235| | * the compiler will issue an error involving this function name, and mention + 236| | * the type, as a hint as to the reason. + 237| | */ + 238| |template [[noreturn]] void oops_forbidden_conversion() noexcept; + 239| | + 240| | + 241| |/// String traits for a forbidden type conversion. + 242| |/** If you have a C++ type for which you explicitly wish to forbid SQL + 243| | * conversion, you can derive a @ref pqxx::string_traits specialisation for + 244| | * that type from this struct. Any attempt to convert the type will then fail + 245| | * to build, and produce an error mentioning @ref oops_forbidden_conversion. + 246| | */ + 247| |template struct forbidden_conversion + 248| |{ + 249| | static constexpr bool converts_to_string{false}; + 250| | static constexpr bool converts_from_string{false}; + 251| | [[noreturn]] static zview to_buf(char *, char *, TYPE const &) + 252| | { + 253| | oops_forbidden_conversion(); + 254| | } + 255| | [[noreturn]] static char *into_buf(char *, char *, TYPE const &) + 256| | { + 257| | oops_forbidden_conversion(); + 258| | } + 259| | [[noreturn]] static TYPE from_string(std::string_view) + 260| | { + 261| | oops_forbidden_conversion(); + 262| | } + 263| | [[noreturn]] static std::size_t size_buffer(TYPE const &) noexcept + 264| | { + 265| | oops_forbidden_conversion(); + 266| | } + 267| |}; + 268| | + 269| | + 270| |/// You cannot convert a `char` to/from SQL. + 271| |/** Converting this type may seem simple enough, but it's ambiguous: Did you + 272| | * mean the `char` value as a small integer? If so, did you mean it to be + 273| | * signed or unsigned? (The C++ Standard allows the system to implement `char` + 274| | * as either a signed type or an unsigned type.) Or were you thinking of a + 275| | * single-character string (and if so, using what encoding)? Or perhaps it's + 276| | * just a raw byte value? + 277| | * + 278| | * If you meant it as an integer, use an appropriate integral type such as + 279| | * `int` or `short` or `unsigned int` etc. + 280| | * + 281| | * If you wanted a single-character string, use `std::string_view` (or a + 282| | * similar type such as `std::string`). + 283| | * + 284| | * Or if you had a raw byte in mind, try `pqxx::bytes_view` instead. + 285| | */ + 286| |template<> struct string_traits : forbidden_conversion + 287| |{}; + 288| | + 289| | + 290| |/// You cannot convert an `unsigned char` to/from SQL. + 291| |/** Converting this type may seem simple enough, but it's ambiguous: Did you + 292| | * mean the `char` value as a small integer? Or were you thinking of a + 293| | * single-character string (and if so, using what encoding)? Or perhaps it's + 294| | * just a raw byte value? + 295| | * + 296| | * If you meant it as an integer, use an appropriate integral type such as + 297| | * `int` or `short` or `unsigned int` etc. + 298| | * + 299| | * If you wanted a single-character string, use `std::string_view` (or a + 300| | * similar type such as `std::string`). + 301| | * + 302| | * Or if you had a raw byte in mind, try `pqxx::bytes_view` instead. + 303| | */ + 304| |template<> + 305| |struct string_traits : forbidden_conversion + 306| |{}; + 307| | + 308| | + 309| |/// You cannot convert a `signed char` to/from SQL. + 310| |/** Converting this type may seem simple enough, but it's ambiguous: Did you + 311| | * mean the value as a small integer? Or were you thinking of a + 312| | * single-character string (and if so, in what encoding)? Or perhaps it's just + 313| | * a raw byte value? + 314| | * + 315| | * If you meant it as an integer, use an appropriate integral type such as + 316| | * `int` or `short` etc. + 317| | * + 318| | * If you wanted a single-character string, use `std::string_view` (or a + 319| | * similar type such as `std::string`). + 320| | * + 321| | * Or if you had a raw byte in mind, try `pqxx::bytes_view` instead. + 322| | */ + 323| |template<> + 324| |struct string_traits : forbidden_conversion + 325| |{}; + 326| | + 327| | + 328| |/// You cannot convert a `std::byte` to/from SQL. + 329| |/** To convert a raw byte value, use a `bytes_view`. + 330| | * + 331| | * For example, to convert a byte `b` from C++ to SQL, convert the value + 332| | * `pqxx::bytes_view{&b, 1}` instead. + 333| | */ + 334| |template<> struct string_traits : forbidden_conversion + 335| |{}; + 336| | + 337| | + 338| |/// Nullness: Enums do not have an inherent null value. + 339| |template + 340| |struct nullness>> : no_null + 341| |{}; + 342| | + 343| | + 344| |// C++20: Concepts for "converts from string" & "converts to string." + 345| |} // namespace pqxx + 346| | + 347| | + 348| |namespace pqxx::internal + 349| |{ + 350| |/// Helper class for defining enum conversions. + 351| |/** The conversion will convert enum values to numeric strings, and vice versa. + 352| | * + 353| | * To define a string conversion for an enum type, derive a @c string_traits + 354| | * specialisation for the enum from this struct. + 355| | * + 356| | * There's usually an easier way though: the @c PQXX_DECLARE_ENUM_CONVERSION + 357| | * macro. Use @c enum_traits manually only if you need to customise your + 358| | * traits type in more detail. + 359| | */ + 360| |template struct enum_traits + 361| |{ + 362| | using impl_type = std::underlying_type_t; + 363| | using impl_traits = string_traits; + 364| | + 365| | static constexpr bool converts_to_string{true}; + 366| | static constexpr bool converts_from_string{true}; + 367| | + 368| | [[nodiscard]] static constexpr zview + 369| | to_buf(char *begin, char *end, ENUM const &value) + 370| | { + 371| | return impl_traits::to_buf(begin, end, to_underlying(value)); + 372| | } + 373| | + 374| | static constexpr char *into_buf(char *begin, char *end, ENUM const &value) + 375| 0| { + 376| 0| return impl_traits::into_buf(begin, end, to_underlying(value)); + 377| 0| } + 378| | + 379| | [[nodiscard]] static ENUM from_string(std::string_view text) + 380| | { + 381| | return static_cast(impl_traits::from_string(text)); + 382| | } + 383| | + 384| | [[nodiscard]] static std::size_t size_buffer(ENUM const &value) noexcept + 385| 0| { + 386| 0| return impl_traits::size_buffer(to_underlying(value)); + 387| 0| } + 388| | + 389| |private: + 390| | // C++23: Replace with std::to_underlying. + 391| | static constexpr impl_type to_underlying(ENUM const &value) noexcept + 392| 0| { + 393| 0| return static_cast(value); + 394| 0| } + 395| |}; + 396| |} // namespace pqxx::internal + 397| | + 398| | + 399| |// We used to inline type_name, but this triggered a "double free" error + 400| |// on program exit, when libpqxx was built as a shared library on Debian with + 401| |// gcc 12. + 402| | + 403| |/// Macro: Define a string conversion for an enum type. + 404| |/** This specialises the @c pqxx::string_traits template, so use it in the + 405| | * @c ::pqxx namespace. + 406| | * + 407| | * For example: + 408| | * + 409| | * #include + 410| | * #include + 411| | * enum X { xa, xb }; + 412| | * namespace pqxx { PQXX_DECLARE_ENUM_CONVERSION(x); } + 413| | * int main() { std::cout << pqxx::to_string(xa) << std::endl; } + 414| | */ + 415| |#define PQXX_DECLARE_ENUM_CONVERSION(ENUM) \ + 416| | template<> struct string_traits : pqxx::internal::enum_traits \ + 417| | {}; \ + 418| | template<> inline std::string_view const type_name \ + 419| | { \ + 420| | #ENUM \ + 421| | } + 422| | + 423| | + 424| |namespace pqxx + 425| |{ + 426| |/// Parse a value in postgres' text format as a TYPE. + 427| |/** If the form of the value found in the string does not match the expected + 428| | * type, e.g. if a decimal point is found when converting to an integer type, + 429| | * the conversion fails. Overflows (e.g. converting "9999999999" to a 16-bit + 430| | * C++ type) are also treated as errors. If in some cases this behaviour + 431| | * should be inappropriate, convert to something bigger such as @c long @c int + 432| | * first and then truncate the resulting value. + 433| | * + 434| | * Only the simplest possible conversions are supported. Fancy features like + 435| | * hexadecimal or octal, spurious signs, or exponent notation won't work. + 436| | * Whitespace is not stripped away. Only the kinds of strings that come out of + 437| | * PostgreSQL and out of to_string() can be converted. + 438| | */ + 439| |template + 440| |[[nodiscard]] inline TYPE from_string(std::string_view text) + 441| 0|{ + 442| 0| return string_traits::from_string(text); + 443| 0|} + ------------------ + | Unexecuted instantiation: _ZN4pqxx11from_stringIdEET_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE + ------------------ + | Unexecuted instantiation: _ZN4pqxx11from_stringINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEET_NS1_17basic_string_viewIcS4_EE + ------------------ + 444| | + 445| | + 446| |/// "Convert" a std::string_view to a std::string_view. + 447| |/** Just returns its input. + 448| | * + 449| | * @warning Of course the result is only valid for as long as the original + 450| | * string remains valid! Never access the string referenced by the return + 451| | * value after the original has been destroyed. + 452| | */ + 453| |template<> + 454| |[[nodiscard]] inline std::string_view from_string(std::string_view text) + 455| 0|{ + 456| 0| return text; + 457| 0|} + 458| | + 459| | + 460| |/// Attempt to convert postgres-generated string to given built-in object. + 461| |/** This is like the single-argument form of the function, except instead of + 462| | * returning the value, it sets @c value. + 463| | * + 464| | * You may find this more convenient in that it infers the type you want from + 465| | * the argument you pass. But there are disadvantages: it requires an + 466| | * assignment operator, and it may be less efficient. + 467| | */ + 468| |template inline void from_string(std::string_view text, T &value) + 469| |{ + 470| | value = from_string(text); + 471| |} + 472| | + 473| | + 474| |/// Convert a value to a readable string that PostgreSQL will understand. + 475| |/** The conversion does no special formatting, and ignores any locale settings. + 476| | * The resulting string will be human-readable and in a format suitable for use + 477| | * in SQL queries. It won't have niceties such as "thousands separators" + 478| | * though. + 479| | */ + 480| |template inline std::string to_string(TYPE const &value); + 481| | + 482| | + 483| |/// Convert multiple values to strings inside a single buffer. + 484| |/** There must be enough room for all values, or this will throw + 485| | * @c conversion_overrun. You can obtain a conservative estimate of the buffer + 486| | * space required by calling @c size_buffer() on the values. + 487| | * + 488| | * The @c std::string_view results may point into the buffer, so don't assume + 489| | * that they will remain valid after you destruct or move the buffer. + 490| | */ + 491| |template + 492| |[[nodiscard]] inline std::vector + 493| |to_buf(char *here, char const *end, TYPE... value) + 494| |{ + 495| | PQXX_ASSUME(here <= end); + 496| | return {[&here, end](auto v) { + 497| | auto begin = here; + 498| | here = string_traits::into_buf(begin, end, v); + 499| | // Exclude the trailing zero out of the string_view. + 500| | auto len{static_cast(here - begin) - 1}; + 501| | return std::string_view{begin, len}; + 502| | }(value)...}; + 503| |} + 504| | + 505| |/// Convert a value to a readable string that PostgreSQL will understand. + 506| |/** This variant of to_string can sometimes save a bit of time in loops, by + 507| | * re-using a std::string for multiple conversions. + 508| | */ + 509| |template + 510| |inline void into_string(TYPE const &value, std::string &out); + 511| | + 512| | + 513| |/// Is @c value null? + 514| |template + 515| |[[nodiscard]] inline constexpr bool is_null(TYPE const &value) noexcept + 516| 0|{ + 517| 0| return nullness>::is_null(value); + 518| 0|} + ------------------ + | Unexecuted instantiation: _ZN4pqxx7is_nullIPKcEEbRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7is_nullIPcEEbRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7is_nullINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEbRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7is_nullINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEEEbRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7is_nullINSt3__112basic_stringISt4byteNS1_11char_traitsIS3_EENS1_9allocatorIS3_EEEEEEbRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7is_nullINSt3__117basic_string_viewISt4byteNS1_11char_traitsIS3_EEEEEEbRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7is_nullINS_12binarystringEEEbRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx7is_nullINSt3__16chrono14year_month_dayEEEbRKT_ + ------------------ + 519| | + 520| | + 521| |/// Estimate how much buffer space is needed to represent values as a string. + 522| |/** The estimate may be a little pessimistic, if it saves time. It also + 523| | * includes room for a terminating zero after each value. + 524| | */ + 525| |template + 526| |[[nodiscard]] inline std::size_t size_buffer(TYPE const &...value) noexcept + 527| 0|{ + 528| 0| return (string_traits>::size_buffer(value) + ...); + 529| 0|} + ------------------ + | Unexecuted instantiation: _ZN4pqxx11size_bufferIJPKciS2_iS2_EEEmDpRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx11size_bufferIJPKciS2_NSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEES2_iS2_EEEmDpRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx11size_bufferIJPKciS2_EEEmDpRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx11size_bufferIJPKcNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEES2_iS2_EEEmDpRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx11size_bufferIJPKcmS2_mS2_mS2_EEEmDpRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx11size_bufferIJPKcNS_8internal14encoding_groupES2_S4_S2_EEEmDpRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx11size_bufferIJNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEEmDpRKT_ + ------------------ + 530| | + 531| | + 532| |/// Does this type translate to an SQL array? + 533| |/** Specialisations may override this to be true for container types. + 534| | * + 535| | * This may not always be a black-and-white choice. For instance, a + 536| | * @c std::string is a container, but normally it translates to an SQL string, + 537| | * not an SQL array. + 538| | */ + 539| |template inline constexpr bool is_sql_array{false}; + 540| | + 541| | + 542| |/// Can we use this type in arrays and composite types without quoting them? + 543| |/** Define this as @c true only if values of @c TYPE can never contain any + 544| | * special characters that might need escaping or confuse the parsing of array + 545| | * or composite * types, such as commas, quotes, parentheses, braces, newlines, + 546| | * and so on. + 547| | * + 548| | * When converting a value of such a type to a string in an array or a field in + 549| | * a composite type, we do not need to add quotes, nor escape any special + 550| | * characters. + 551| | * + 552| | * This is just an optimisation, so it defaults to @c false to err on the side + 553| | * of slow correctness. + 554| | */ + 555| |template inline constexpr bool is_unquoted_safe{false}; + 556| | + 557| | + 558| |/// Element separator between SQL array elements of this type. + 559| |template inline constexpr char array_separator{','}; + 560| | + 561| | + 562| |/// What's the preferred format for passing non-null parameters of this type? + 563| |/** This affects how we pass parameters of @c TYPE when calling parameterised + 564| | * statements or prepared statements. + 565| | * + 566| | * Generally we pass parameters in text format, but binary strings are the + 567| | * exception. We also pass nulls in binary format, so this function need not + 568| | * handle null values. + 569| | */ + 570| |template inline constexpr format param_format(TYPE const &) + 571| |{ + 572| | return format::text; + 573| |} + 574| | + 575| | + 576| |/// Implement @c string_traits::to_buf by calling @c into_buf. + 577| |/** When you specialise @c string_traits for a new type, most of the time its + 578| | * @c to_buf implementation has no special optimisation tricks and just writes + 579| | * its text into the buffer it receives from the caller, starting at the + 580| | * beginning. + 581| | * + 582| | * In that common situation, you can implement @c to_buf as just a call to + 583| | * @c generic_to_buf. It will call @c into_buf and return the right result for + 584| | * @c to_buf. + 585| | */ + 586| |template + 587| |inline zview generic_to_buf(char *begin, char *end, TYPE const &value) + 588| 0|{ + 589| 0| using traits = string_traits; + 590| 0| // The trailing zero does not count towards the zview's size, so subtract 1 + 591| 0| // from the result we get from into_buf(). + 592| 0| if (is_null(value)) + 593| 0| return {}; + 594| 0| else + 595| 0| return {begin, traits::into_buf(begin, end, value) - begin - 1}; + 596| 0|} + ------------------ + | Unexecuted instantiation: _ZN4pqxx14generic_to_bufIPKcEENS_5zviewEPcS4_RKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx14generic_to_bufINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS_5zviewEPcS9_RKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx14generic_to_bufINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEEENS_5zviewEPcS7_RKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx14generic_to_bufINSt3__112basic_stringISt4byteNS1_11char_traitsIS3_EENS1_9allocatorIS3_EEEEEENS_5zviewEPcSA_RKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx14generic_to_bufINSt3__117basic_string_viewISt4byteNS1_11char_traitsIS3_EEEEEENS_5zviewEPcS8_RKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx14generic_to_bufINS_12binarystringEEENS_5zviewEPcS3_RKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx14generic_to_bufINSt3__16chrono14year_month_dayEEENS_5zviewEPcS5_RKT_ + ------------------ + 597| | + 598| | + 599| |#if defined(PQXX_HAVE_CONCEPTS) + 600| |/// Concept: Binary string, akin to @c std::string for binary data. + 601| |/** Any type that satisfies this concept can represent an SQL BYTEA value. + 602| | * + 603| | * A @c binary has a @c begin(), @c end(), @c size(), and @data(). Each byte + 604| | * is a @c std::byte, and they must all be laid out contiguously in memory so + 605| | * we can reference them by a pointer. + 606| | */ + 607| |template + 608| |concept binary = std::ranges::contiguous_range and + 609| | std::is_same_v>, std::byte>; + 610| |#endif + 611| |//@} + 612| |} // namespace pqxx + 613| | + 614| | + 615| |#include "pqxx/internal/conversions.hxx" + 616| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/stream_from.hxx: + 1| |/* Definition of the pqxx::stream_from class. + 2| | * + 3| | * pqxx::stream_from enables optimized batch reads from a database table. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stream_from instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_STREAM_FROM + 14| |#define PQXX_H_STREAM_FROM + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include + 21| |#include + 22| | + 23| |#include "pqxx/connection.hxx" + 24| |#include "pqxx/except.hxx" + 25| |#include "pqxx/internal/concat.hxx" + 26| |#include "pqxx/internal/encoding_group.hxx" + 27| |#include "pqxx/internal/stream_iterator.hxx" + 28| |#include "pqxx/separated_list.hxx" + 29| |#include "pqxx/transaction_focus.hxx" + 30| | + 31| | + 32| |namespace pqxx + 33| |{ + 34| |class transaction_base; + 35| | + 36| | + 37| |/// Pass this to a `stream_from` constructor to stream table contents. + 38| |/** @deprecated Use @ref transaction_base::stream instead of stream_from. + 39| | */ + 40| |constexpr from_table_t from_table; + 41| |/// Pass this to a `stream_from` constructor to stream query results. + 42| |/** @deprecated Use transaction_base::stream instead of stream_from. + 43| | */ + 44| |constexpr from_query_t from_query; + 45| | + 46| | + 47| |/// Stream data from the database. + 48| |/** @deprecated Use @ref transaction_base::stream. + 49| | * + 50| | * For larger data sets, retrieving data this way is likely to be faster than + 51| | * executing a query and then iterating and converting the rows fields. You + 52| | * will also be able to start processing before all of the data has come in. + 53| | * + 54| | * There are also downsides. Not all kinds of query will work in a stream. + 55| | * But straightforward `SELECT` and `UPDATE ... RETURNING` queries should work. + 56| | * This function makes use of @ref pqxx::stream_from, which in turn uses + 57| | * PostgreSQL's `COPY` command, so see the documentation for those to get the + 58| | * full details. + 59| | * + 60| | * There are other downsides. If there stream encounters an error, it may + 61| | * leave the entire connection in an unusable state, so you'll have to give the + 62| | * whole thing up. Finally, opening a stream puts the connection in a special + 63| | * state, so you won't be able to do many other things with the connection or + 64| | * the transaction while the stream is open. + 65| | * + 66| | * There are two ways of starting a stream: you stream either all rows in a + 67| | * table (using one of the factories, `table()` or `raw_table()`), or the + 68| | * results of a query (using the `query()` factory). + 69| | * + 70| | * Usually you'll want the `stream` convenience wrapper in + 71| | * @ref transaction_base, * so you don't need to deal with this class directly. + 72| | * + 73| | * @warning While a stream is active, you cannot execute queries, open a + 74| | * pipeline, etc. on the same transaction. A transaction can have at most one + 75| | * object of a type derived from @ref pqxx::transaction_focus active on it at a + 76| | * time. + 77| | */ + 78| |class PQXX_LIBEXPORT stream_from : transaction_focus + 79| |{ + 80| |public: + 81| | using raw_line = + 82| | std::pair, std::size_t>; + 83| | + 84| | stream_from(stream_from &&) = delete; + 85| | stream_from &operator=(stream_from &&) = delete; + 86| | + 87| | /// Factory: Execute query, and stream the results. + 88| | /** The query can be a SELECT query or a VALUES query; or it can be an + 89| | * UPDATE, INSERT, or DELETE with a RETURNING clause. + 90| | * + 91| | * The query is executed as part of a COPY statement, so there are additional + 92| | * restrictions on what kind of query you can use here. See the PostgreSQL + 93| | * documentation for the COPY command: + 94| | * + 95| | * https://www.postgresql.org/docs/current/sql-copy.html + 96| | */ + 97| | [[deprecated("Use transaction_base::stream instead.")]] static stream_from + 98| | query(transaction_base &tx, std::string_view q) + 99| 0| { + 100| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 101| 0| return {tx, from_query, q}; + 102| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 103| 0| } + 104| | + 105| | /** + 106| | * @name Streaming data from tables + 107| | * + 108| | * You can use `stream_from` to read a table's contents. This is a quick + 109| | * and easy way to read a table, but it comes with limitations. It cannot + 110| | * stream from a view, only from a table. It does not support conditions. + 111| | * And there are no guarantees about ordering. If you need any of those + 112| | * things, consider streaming from a query instead. + 113| | */ + 114| | //@{ + 115| | + 116| | /// Factory: Stream data from a pre-quoted table and columns. + 117| | /** Use this factory if you need to create multiple streams using the same + 118| | * table path and/or columns list, and you want to save a bit of work on + 119| | * composing the internal SQL statement for starting the stream. It lets you + 120| | * compose the string representations for the table path and the columns + 121| | * list, so you can compute these once and then re-use them later. + 122| | * + 123| | * @param tx The transaction within which the stream will operate. + 124| | * @param path Name or path for the table upon which the stream will + 125| | * operate. If any part of the table path may contain special + 126| | * characters or be case-sensitive, quote the path using + 127| | * pqxx::connection::quote_table(). + 128| | * @param columns Columns which the stream will read. They should be + 129| | * comma-separated and, if needed, quoted. You can produce the string + 130| | * using pqxx::connection::quote_columns(). If you omit this argument, + 131| | * the stream will read all columns in the table, in schema order. + 132| | */ + 133| | [[deprecated("Use transaction_base::stream instead.")]] static stream_from + 134| | raw_table( + 135| | transaction_base &tx, std::string_view path, + 136| | std::string_view columns = ""sv); + 137| | + 138| | /// Factory: Stream data from a given table. + 139| | /** This is the convenient way to stream from a table. + 140| | */ + 141| | [[deprecated("Use transaction_base::stream instead.")]] static stream_from + 142| | table( + 143| | transaction_base &tx, table_path path, + 144| | std::initializer_list columns = {}); + 145| | //@} + 146| | + 147| | /// Execute query, and stream over the results. + 148| | /** @deprecated Use factory function @ref query instead. + 149| | */ + 150| | [[deprecated("Use transaction_base::stream instead.")]] stream_from( + 151| | transaction_base &, from_query_t, std::string_view query); + 152| | + 153| | /// Stream all rows in table, all columns. + 154| | /** @deprecated Use factories @ref table or @ref raw_table instead. + 155| | */ + 156| | [[deprecated("Use transaction_base::stream instead.")]] stream_from( + 157| | transaction_base &, from_table_t, std::string_view table); + 158| | + 159| | /// Stream given columns from all rows in table. + 160| | /** @deprecated Use factories @ref table or @ref raw_table instead. + 161| | */ + 162| | template + 163| | [[deprecated("Use transaction_base::stream instead.")]] stream_from( + 164| | transaction_base &, from_table_t, std::string_view table, + 165| | Iter columns_begin, Iter columns_end); + 166| | + 167| | /// Stream given columns from all rows in table. + 168| | /** @deprecated Use factory function @ref query instead. + 169| | */ + 170| | template + 171| | [[deprecated("Use transaction_base::stream() instead.")]] stream_from( + 172| | transaction_base &tx, from_table_t, std::string_view table, + 173| | Columns const &columns); + 174| | + 175| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 176| | /// @deprecated Use factories @ref table or @ref raw_table instead. + 177| | [[deprecated("Use transaction_base::stream instead.")]] stream_from( + 178| | transaction_base &tx, std::string_view table) : + 179| | stream_from{tx, from_table, table} + 180| 0| {} + 181| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 182| | + 183| | /// @deprecated Use factories @ref table or @ref raw_table instead. + 184| | template + 185| | [[deprecated("Use transaction_base::stream instead.")]] stream_from( + 186| | transaction_base &tx, std::string_view table, Columns const &columns) : + 187| | stream_from{tx, from_table, table, columns} + 188| | {} + 189| | + 190| | /// @deprecated Use factories @ref table or @ref raw_table instead. + 191| | template + 192| | [[deprecated("Use transaction_base::stream instead.")]] stream_from( + 193| | transaction_base &, std::string_view table, Iter columns_begin, + 194| | Iter columns_end); + 195| | + 196| | ~stream_from() noexcept; + 197| | + 198| | /// May this stream still produce more data? + 199| | [[nodiscard]] constexpr operator bool() const noexcept + 200| 0| { + 201| 0| return not m_finished; + 202| 0| } + 203| | /// Has this stream produced all the data it is going to produce? + 204| | [[nodiscard]] constexpr bool operator!() const noexcept + 205| 0| { + 206| 0| return m_finished; + 207| 0| } + 208| | + 209| | /// Finish this stream. Call this before continuing to use the connection. + 210| | /** Consumes all remaining lines, and closes the stream. + 211| | * + 212| | * This may take a while if you're abandoning the stream before it's done, so + 213| | * skip it in error scenarios where you're not planning to use the connection + 214| | * again afterwards. + 215| | */ + 216| | void complete(); + 217| | + 218| | /// Read one row into a tuple. + 219| | /** Converts the row's fields into the fields making up the tuple. + 220| | * + 221| | * For a column which can contain nulls, be sure to give the corresponding + 222| | * tuple field a type which can be null. For example, to read a field as + 223| | * `int` when it may contain nulls, read it as `std::optional`. + 224| | * Using `std::shared_ptr` or `std::unique_ptr` will also work. + 225| | */ + 226| | template stream_from &operator>>(Tuple &); + 227| | + 228| | /// Doing this with a `std::variant` is going to be horrifically borked. + 229| | template + 230| | stream_from &operator>>(std::variant &) = delete; + 231| | + 232| | /// Iterate over this stream. Supports range-based "for" loops. + 233| | /** Produces an input iterator over the stream. + 234| | * + 235| | * Do not call this yourself. Use it like "for (auto data : stream.iter())". + 236| | */ + 237| | template [[nodiscard]] auto iter() & + 238| | { + 239| | return pqxx::internal::stream_input_iteration{*this}; + 240| | } + 241| | + 242| | /// Read a row. Return fields as views, valid until you read the next row. + 243| | /** Returns `nullptr` when there are no more rows to read. Do not attempt + 244| | * to read any further rows after that. + 245| | * + 246| | * Do not access the vector, or the storage referenced by the views, after + 247| | * closing or completing the stream, or after attempting to read a next row. + 248| | * + 249| | * A @ref pqxx::zview is like a `std::string_view`, but with the added + 250| | * guarantee that if its data pointer is non-null, the string is followed by + 251| | * a terminating zero (which falls just outside the view itself). + 252| | * + 253| | * If any of the views' data pointer is null, that means that the + 254| | * corresponding SQL field is null. + 255| | * + 256| | * @warning The return type may change in the future, to support C++20 + 257| | * coroutine-based usage. + 258| | */ + 259| | std::vector const *read_row() &; + 260| | + 261| | /// Read a raw line of text from the COPY command. + 262| | /** @warning Do not use this unless you really know what you're doing. */ + 263| | raw_line get_raw_line(); + 264| | + 265| |private: + 266| | // TODO: Clean up this signature once we cull the deprecated constructors. + 267| | /// @deprecated + 268| | stream_from( + 269| | transaction_base &tx, std::string_view table, std::string_view columns, + 270| | from_table_t); + 271| | + 272| | // TODO: Clean up this signature once we cull the deprecated constructors. + 273| | /// @deprecated + 274| | stream_from( + 275| | transaction_base &, std::string_view unquoted_table, + 276| | std::string_view columns, from_table_t, int); + 277| | + 278| | template + 279| | void extract_fields(Tuple &t, std::index_sequence) const + 280| | { + 281| | (extract_value(t), ...); + 282| | } + 283| | + 284| | pqxx::internal::char_finder_func *m_char_finder; + 285| | + 286| | /// Current row's fields' text, combined into one reusable string. + 287| | std::string m_row; + 288| | + 289| | /// The current row's fields. + 290| | std::vector m_fields; + 291| | + 292| | bool m_finished = false; + 293| | + 294| | void close(); + 295| | + 296| | template + 297| | void extract_value(Tuple &) const; + 298| | + 299| | /// Read a line of COPY data, write `m_row` and `m_fields`. + 300| | void parse_line(); + 301| |}; + 302| | + 303| | + 304| |template + 305| |inline stream_from::stream_from( + 306| | transaction_base &tx, from_table_t, std::string_view table_name, + 307| | Columns const &columns) : + 308| | stream_from{ + 309| | tx, from_table, table_name, std::begin(columns), std::end(columns)} + 310| |{} + 311| | + 312| | + 313| |template + 314| |inline stream_from::stream_from( + 315| | transaction_base &tx, from_table_t, std::string_view table, + 316| | Iter columns_begin, Iter columns_end) : + 317| | stream_from{ + 318| | tx, table, separated_list(",", columns_begin, columns_end), + 319| | from_table, 1} + 320| |{} + 321| | + 322| | + 323| |template inline stream_from &stream_from::operator>>(Tuple &t) + 324| |{ + 325| | if (m_finished) + 326| | PQXX_UNLIKELY return *this; + 327| | static constexpr auto tup_size{std::tuple_size_v}; + 328| | m_fields.reserve(tup_size); + 329| | parse_line(); + 330| | if (m_finished) + 331| | PQXX_UNLIKELY return *this; + 332| | + 333| | if (std::size(m_fields) != tup_size) + 334| | throw usage_error{internal::concat( + 335| | "Tried to extract ", tup_size, " field(s) from a stream of ", + 336| | std::size(m_fields), ".")}; + 337| | + 338| | extract_fields(t, std::make_index_sequence{}); + 339| | return *this; + 340| |} + 341| | + 342| | + 343| |template + 344| |inline void stream_from::extract_value(Tuple &t) const + 345| |{ + 346| | using field_type = strip_t(t))>; + 347| | using nullity = nullness; + 348| | assert(index < std::size(m_fields)); + 349| | if constexpr (nullity::always_null) + 350| | { + 351| | if (std::data(m_fields[index]) != nullptr) + 352| | throw conversion_error{"Streaming non-null value into null field."}; + 353| | } + 354| | else if (std::data(m_fields[index]) == nullptr) + 355| | { + 356| | if constexpr (nullity::has_null) + 357| | std::get(t) = nullity::null(); + 358| | else + 359| | internal::throw_null_conversion(type_name); + 360| | } + 361| | else + 362| | { + 363| | // Don't ever try to convert a non-null value to nullptr_t! + 364| | std::get(t) = from_string(m_fields[index]); + 365| | } + 366| |} + 367| |} // namespace pqxx + 368| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/stream_to.hxx: + 1| |/* Definition of the pqxx::stream_to class. + 2| | * + 3| | * pqxx::stream_to enables optimized batch updates to a database table. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stream_to.hxx instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_STREAM_TO + 14| |#define PQXX_H_STREAM_TO + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include "pqxx/separated_list.hxx" + 21| |#include "pqxx/transaction_base.hxx" + 22| | + 23| | + 24| |namespace pqxx + 25| |{ + 26| |/// Efficiently write data directly to a database table. + 27| |/** If you wish to insert rows of data into a table, you can compose INSERT + 28| | * statements and execute them. But it's slow and tedious, and you need to + 29| | * worry about quoting and escaping the data. + 30| | * + 31| | * If you're just inserting a single row, it probably won't matter much. You + 32| | * can use prepared or parameterised statements to take care of the escaping + 33| | * for you. But if you're inserting large numbers of rows you will want + 34| | * something better. + 35| | * + 36| | * Inserting rows one by one using INSERT statements involves a lot of + 37| | * pointless overhead, especially when you are working with a remote database + 38| | * server over the network. You may end up sending each row over the network + 39| | * as a separate query, and waiting for a reply. Do it "in bulk" using + 40| | * `stream_to`, and you may find that it goes many times faster. Sometimes + 41| | * you gain orders of magnitude in speed. + 42| | * + 43| | * Here's how it works: you create a `stream_to` stream to start writing to + 44| | * your table. You will probably want to specify the columns. Then, you + 45| | * feed your data into the stream one row at a time. And finally, you call the + 46| | * stream's @ref complete function to tell it to finalise the operation, wait + 47| | * for completion, and check for errors. + 48| | * + 49| | * (You _must_ complete the stream before committing or aborting the + 50| | * transaction. The connection is in a special state while the stream is + 51| | * active, where it can't process commands, and can't commit or abort a + 52| | * transaction.) + 53| | * + 54| | * So how do you feed a row of data into the stream? There's several ways, but + 55| | * the preferred one is to call its @ref write_values. Pass the field values + 56| | * as arguments. Doesn't matter what type they are, as long as libpqxx knows + 57| | * how to convert them to PostgreSQL's text format: `int`, `std::string` or + 58| | * `std:string_view`, `float` and `double`, `bool`... lots of basic types + 59| | * are supported. If some of the values are null, feel free to use + 60| | * `std::optional`, `std::shared_ptr`, or `std::unique_ptr`. + 61| | * + 62| | * The arguments' types don't even have to match the fields' SQL types. If you + 63| | * want to insert an `int` into a `DECIMAL` column, that's your choice -- it + 64| | * will produce a `DECIMAL` value which happens to be integral. Insert a + 65| | * `float` into a `VARCHAR` column? That's fine, you'll get a string whose + 66| | * contents happen to read like a number. And so on. You can even insert + 67| | * different types of value in the same column on different rows. If you have + 68| | * a code path where a particular field is always null, just insert `nullptr`. + 69| | * + 70| | * There is another way to insert rows: the `<<` ("shift-left") operator. + 71| | * It's not as fast and it doesn't support variable arguments: each row must be + 72| | * either a `std::tuple` or something iterable, such as a `std::vector`, or + 73| | * anything else with a `begin()` and `end()`. + 74| | * + 75| | * @warning While a stream is active, you cannot execute queries, open a + 76| | * pipeline, etc. on the same transaction. A transaction can have at most one + 77| | * object of a type derived from @ref pqxx::transaction_focus active on it at a + 78| | * time. + 79| | */ + 80| |class PQXX_LIBEXPORT stream_to : transaction_focus + 81| |{ + 82| |public: + 83| | /// Stream data to a pre-quoted table and columns. + 84| | /** This factory can be useful when it's not convenient to provide the + 85| | * columns list in the form of a `std::initializer_list`, or when the list + 86| | * of columns is simply not known at compile time. + 87| | * + 88| | * Also use this if you need to create multiple streams using the same table + 89| | * path and/or columns list, and you want to save a bit of work on composing + 90| | * the internal SQL statement for starting the stream. It lets you compose + 91| | * the string representations for the table path and the columns list, so you + 92| | * can compute these once and then re-use them later. + 93| | * + 94| | * @param tx The transaction within which the stream will operate. + 95| | * @param path Name or path for the table upon which the stream will + 96| | * operate. If any part of the table path may contain special + 97| | * characters or be case-sensitive, quote the path using + 98| | * pqxx::connection::quote_table(). + 99| | * @param columns Columns to which the stream will write. They should be + 100| | * comma-separated and, if needed, quoted. You can produce the string + 101| | * using pqxx::connection::quote_columns(). If you omit this argument, + 102| | * the stream will write all columns in the table, in schema order. + 103| | */ + 104| | static stream_to raw_table( + 105| | transaction_base &tx, std::string_view path, std::string_view columns = "") + 106| 0| { + 107| 0| return {tx, path, columns}; + 108| 0| } + 109| | + 110| | /// Create a `stream_to` writing to a named table and columns. + 111| | /** Use this to stream data to a table, where the list of columns is known at + 112| | * compile time. + 113| | * + 114| | * @param tx The transaction within which the stream will operate. + 115| | * @param path A @ref table_path designating the target table. + 116| | * @param columns Optionally, the columns to which the stream should write. + 117| | * If you do not pass this, the stream will write to all columns in the + 118| | * table, in schema order. + 119| | */ + 120| | static stream_to table( + 121| | transaction_base &tx, table_path path, + 122| | std::initializer_list columns = {}) + 123| 0| { + 124| 0| auto const &cx{tx.conn()}; + 125| 0| return raw_table(tx, cx.quote_table(path), cx.quote_columns(columns)); + 126| 0| } + 127| | + 128| |#if defined(PQXX_HAVE_CONCEPTS) + 129| | /// Create a `stream_to` writing to a named table and columns. + 130| | /** Use this version to stream data to a table, when the list of columns is + 131| | * not known at compile time. + 132| | * + 133| | * @param tx The transaction within which the stream will operate. + 134| | * @param path A @ref table_path designating the target table. + 135| | * @param columns The columns to which the stream should write. + 136| | */ + 137| | template + 138| | static stream_to + 139| | table(transaction_base &tx, table_path path, COLUMNS const &columns) + 140| | { + 141| | auto const &cx{tx.conn()}; + 142| | return stream_to::raw_table( + 143| | tx, cx.quote_table(path), tx.conn().quote_columns(columns)); + 144| | } + 145| | + 146| | /// Create a `stream_to` writing to a named table and columns. + 147| | /** Use this version to stream data to a table, when the list of columns is + 148| | * not known at compile time. + 149| | * + 150| | * @param tx The transaction within which the stream will operate. + 151| | * @param path A @ref table_path designating the target table. + 152| | * @param columns The columns to which the stream should write. + 153| | */ + 154| | template + 155| | static stream_to + 156| | table(transaction_base &tx, std::string_view path, COLUMNS const &columns) + 157| | { + 158| | return stream_to::raw_table(tx, path, tx.conn().quote_columns(columns)); + 159| | } + 160| |#endif // PQXX_HAVE_CONCEPTS + 161| | + 162| | explicit stream_to(stream_to &&other) : + 163| | // (This first step only moves the transaction_focus base-class + 164| | // object.) + 165| | transaction_focus{std::move(other)}, + 166| | m_finished{other.m_finished}, + 167| | m_buffer{std::move(other.m_buffer)}, + 168| | m_field_buf{std::move(other.m_field_buf)}, + 169| | m_finder{other.m_finder} + 170| 0| { + 171| 0| other.m_finished = true; + 172| 0| } + 173| | ~stream_to() noexcept; + 174| | + 175| | /// Does this stream still need to @ref complete()? + 176| | [[nodiscard]] constexpr operator bool() const noexcept + 177| 0| { + 178| 0| return not m_finished; + 179| 0| } + 180| | /// Has this stream been through its concluding @c complete()? + 181| | [[nodiscard]] constexpr bool operator!() const noexcept + 182| 0| { + 183| 0| return m_finished; + 184| 0| } + 185| | + 186| | /// Complete the operation, and check for errors. + 187| | /** Always call this to close the stream in an orderly fashion, even after + 188| | * an error. (In the case of an error, abort the transaction afterwards.) + 189| | * + 190| | * The only circumstance where it's safe to skip this is after an error, if + 191| | * you're discarding the entire connection. + 192| | */ + 193| | void complete(); + 194| | + 195| | /// Insert a row of data. + 196| | /** Returns a reference to the stream, so you can chain the calls. + 197| | * + 198| | * The @c row can be a tuple, or any type that can be iterated. Each + 199| | * item becomes a field in the row, in the same order as the columns you + 200| | * specified when creating the stream. + 201| | * + 202| | * If you don't already happen to have your fields in the form of a tuple or + 203| | * container, prefer @c write_values. It's faster and more convenient. + 204| | */ + 205| | template stream_to &operator<<(Row const &row) + 206| | { + 207| | write_row(row); + 208| | return *this; + 209| | } + 210| | + 211| | /// Stream a `stream_from` straight into a `stream_to`. + 212| | /** This can be useful when copying between different databases. If the + 213| | * source and the destination are on the same database, you'll get better + 214| | * performance doing it all in a regular query. + 215| | */ + 216| | stream_to &operator<<(stream_from &); + 217| | + 218| | /// Insert a row of data, given in the form of a @c std::tuple or container. + 219| | /** The @c row can be a tuple, or any type that can be iterated. Each + 220| | * item becomes a field in the row, in the same order as the columns you + 221| | * specified when creating the stream. + 222| | * + 223| | * The preferred way to insert a row is @c write_values. + 224| | */ + 225| | template void write_row(Row const &row) + 226| | { + 227| | fill_buffer(row); + 228| | write_buffer(); + 229| | } + 230| | + 231| | /// Insert values as a row. + 232| | /** This is the recommended way of inserting data. Pass your field values, + 233| | * of any convertible type. + 234| | */ + 235| | template void write_values(Ts const &...fields) + 236| | { + 237| | fill_buffer(fields...); + 238| | write_buffer(); + 239| | } + 240| | + 241| | /// Create a stream, without specifying columns. + 242| | /** @deprecated Use @ref table or @ref raw_table as a factory. + 243| | * + 244| | * Fields will be inserted in whatever order the columns have in the + 245| | * database. + 246| | * + 247| | * You'll probably want to specify the columns, so that the mapping between + 248| | * your data fields and the table is explicit in your code, and not hidden + 249| | * in an "implicit contract" between your code and your schema. + 250| | */ + 251| | [[deprecated("Use table() or raw_table() factory.")]] stream_to( + 252| | transaction_base &tx, std::string_view table_name) : + 253| | stream_to{tx, table_name, ""sv} + 254| 0| {} + 255| | + 256| | /// Create a stream, specifying column names as a container of strings. + 257| | /** @deprecated Use @ref table or @ref raw_table as a factory. + 258| | */ + 259| | template + 260| | [[deprecated("Use table() or raw_table() factory.")]] stream_to( + 261| | transaction_base &, std::string_view table_name, Columns const &columns); + 262| | + 263| |private: + 264| | /// Stream a pre-quoted table name and columns list. + 265| | stream_to( + 266| | transaction_base &tx, std::string_view path, std::string_view columns); + 267| | + 268| | bool m_finished = false; + 269| | + 270| | /// Reusable buffer for a row. Saves doing an allocation for each row. + 271| | std::string m_buffer; + 272| | + 273| | /// Reusable buffer for converting/escaping a field. + 274| | std::string m_field_buf; + 275| | + 276| | /// Callback to find the special characters we need to watch out for. + 277| | internal::char_finder_func *m_finder; + 278| | + 279| | /// Write a row of raw text-format data into the destination table. + 280| | void write_raw_line(std::string_view); + 281| | + 282| | /// Write a row of data from @c m_buffer into the destination table. + 283| | /** Resets the buffer for the next row. + 284| | */ + 285| | void write_buffer(); + 286| | + 287| | /// COPY encoding for a null field, plus subsequent separator. + 288| | static constexpr std::string_view null_field{"\\N\t"}; + 289| | + 290| | /// Estimate buffer space needed for a field which is always null. + 291| | template + 292| | static std::enable_if_t::always_null, std::size_t> + 293| | estimate_buffer(T const &) + 294| | { + 295| | return std::size(null_field); + 296| | } + 297| | + 298| | /// Estimate buffer space needed for field f. + 299| | /** The estimate is not very precise. We don't actually know how much space + 300| | * we'll need once the escaping comes in. + 301| | */ + 302| | template + 303| | static std::enable_if_t::always_null, std::size_t> + 304| | estimate_buffer(T const &field) + 305| | { + 306| | return is_null(field) ? std::size(null_field) : size_buffer(field); + 307| | } + 308| | + 309| | /// Append escaped version of @c data to @c m_buffer, plus a tab. + 310| | void escape_field_to_buffer(std::string_view data); + 311| | + 312| | /// Append string representation for @c f to @c m_buffer. + 313| | /** This is for the general case, where the field may contain a value. + 314| | * + 315| | * Also appends a tab. The tab is meant to be a separator, not a terminator, + 316| | * so if you write any fields at all, you'll end up with one tab too many + 317| | * at the end of the buffer. + 318| | */ + 319| | template + 320| | std::enable_if_t::always_null> + 321| | append_to_buffer(Field const &f) + 322| | { + 323| | // We append each field, terminated by a tab. That will leave us with + 324| | // one tab too many, assuming we write any fields at all; we remove that + 325| | // at the end. + 326| | if (is_null(f)) + 327| | { + 328| | // Easy. Append null and tab in one go. + 329| | m_buffer.append(null_field); + 330| | } + 331| | else + 332| | { + 333| | // Convert f into m_buffer. + 334| | + 335| | using traits = string_traits; + 336| | auto const budget{estimate_buffer(f)}; + 337| | auto const offset{std::size(m_buffer)}; + 338| | + 339| | if constexpr (std::is_arithmetic_v) + 340| | { + 341| | // Specially optimised for "safe" types, which never need any + 342| | // escaping. Convert straight into m_buffer. + 343| | + 344| | // The budget we get from size_buffer() includes room for the trailing + 345| | // zero, which we must remove. But we're also inserting tabs between + 346| | // fields, so we re-purpose the extra byte for that. + 347| | auto const total{offset + budget}; + 348| | m_buffer.resize(total); + 349| | auto const data{m_buffer.data()}; + 350| | char *const end{traits::into_buf(data + offset, data + total, f)}; + 351| | *(end - 1) = '\t'; + 352| | // Shrink to fit. Keep the tab though. + 353| | m_buffer.resize(static_cast(end - data)); + 354| | } + 355| | else if constexpr ( + 356| | std::is_same_v or + 357| | std::is_same_v or + 358| | std::is_same_v) + 359| | { + 360| | // This string may need escaping. + 361| | m_field_buf.resize(budget); + 362| | escape_field_to_buffer(f); + 363| | } + 364| | else if constexpr ( + 365| | std::is_same_v> or + 366| | std::is_same_v> or + 367| | std::is_same_v>) + 368| | { + 369| | // Optional string. It's not null (we checked for that above), so... + 370| | // Treat like a string. + 371| | m_field_buf.resize(budget); + 372| | escape_field_to_buffer(f.value()); + 373| | } + 374| | // TODO: Support deleter template argument on unique_ptr. + 375| | else if constexpr ( + 376| | std::is_same_v> or + 377| | std::is_same_v> or + 378| | std::is_same_v> or + 379| | std::is_same_v> or + 380| | std::is_same_v> or + 381| | std::is_same_v>) + 382| | { + 383| | // TODO: Can we generalise this elegantly without Concepts? + 384| | // Effectively also an optional string. It's not null (we checked + 385| | // for that above). + 386| | m_field_buf.resize(budget); + 387| | escape_field_to_buffer(*f); + 388| | } + 389| | else + 390| | { + 391| | // This field needs to be converted to a string, and after that, + 392| | // escaped as well. + 393| | m_field_buf.resize(budget); + 394| | auto const data{m_field_buf.data()}; + 395| | escape_field_to_buffer( + 396| | traits::to_buf(data, data + std::size(m_field_buf), f)); + 397| | } + 398| | } + 399| | } + 400| | + 401| | /// Append string representation for a null field to @c m_buffer. + 402| | /** This special case is for types which are always null. + 403| | * + 404| | * Also appends a tab. The tab is meant to be a separator, not a terminator, + 405| | * so if you write any fields at all, you'll end up with one tab too many + 406| | * at the end of the buffer. + 407| | */ + 408| | template + 409| | std::enable_if_t::always_null> + 410| | append_to_buffer(Field const &) + 411| | { + 412| | m_buffer.append(null_field); + 413| | } + 414| | + 415| | /// Write raw COPY line into @c m_buffer, based on a container of fields. + 416| | template + 417| | std::enable_if_t> + 418| | fill_buffer(Container const &c) + 419| | { + 420| | // To avoid unnecessary allocations and deallocations, we run through c + 421| | // twice: once to determine how much buffer space we may need, and once to + 422| | // actually write it into the buffer. + 423| | std::size_t budget{0}; + 424| | for (auto const &f : c) budget += estimate_buffer(f); + 425| | m_buffer.reserve(budget); + 426| | for (auto const &f : c) append_to_buffer(f); + 427| | } + 428| | + 429| | /// Estimate how many buffer bytes we need to write tuple. + 430| | template + 431| | static std::size_t + 432| | budget_tuple(Tuple const &t, std::index_sequence) + 433| | { + 434| | return (estimate_buffer(std::get(t)) + ...); + 435| | } + 436| | + 437| | /// Write tuple of fields to @c m_buffer. + 438| | template + 439| | void append_tuple(Tuple const &t, std::index_sequence) + 440| | { + 441| | (append_to_buffer(std::get(t)), ...); + 442| | } + 443| | + 444| | /// Write raw COPY line into @c m_buffer, based on a tuple of fields. + 445| | template void fill_buffer(std::tuple const &t) + 446| | { + 447| | using indexes = std::make_index_sequence; + 448| | + 449| | m_buffer.reserve(budget_tuple(t, indexes{})); + 450| | append_tuple(t, indexes{}); + 451| | } + 452| | + 453| | /// Write raw COPY line into @c m_buffer, based on varargs fields. + 454| | template void fill_buffer(const Ts &...fields) + 455| | { + 456| | (..., append_to_buffer(fields)); + 457| | } + 458| | + 459| | constexpr static std::string_view s_classname{"stream_to"}; + 460| |}; + 461| | + 462| | + 463| |template + 464| |inline stream_to::stream_to( + 465| | transaction_base &tx, std::string_view table_name, Columns const &columns) : + 466| | stream_to{tx, table_name, std::begin(columns), std::end(columns)} + 467| |{} + 468| |} // namespace pqxx + 469| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/subtransaction.hxx: + 1| |/* Definition of the pqxx::subtransaction class. + 2| | * + 3| | * pqxx::subtransaction is a nested transaction, i.e. one within a transaction. + 4| | * + 5| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/subtransaction instead. + 6| | * + 7| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 8| | * + 9| | * See COPYING for copyright license. If you did not receive a file called + 10| | * COPYING with this source code, please notify the distributor of this + 11| | * mistake, or contact the author. + 12| | */ + 13| |#ifndef PQXX_H_SUBTRANSACTION + 14| |#define PQXX_H_SUBTRANSACTION + 15| | + 16| |#if !defined(PQXX_HEADER_PRE) + 17| |# error "Include libpqxx headers as , not ." + 18| |#endif + 19| | + 20| |#include "pqxx/dbtransaction.hxx" + 21| | + 22| |namespace pqxx + 23| |{ + 24| |/** + 25| | * @ingroup transactions + 26| | */ + 27| |/// "Transaction" nested within another transaction + 28| |/** A subtransaction can be executed inside a backend transaction, or inside + 29| | * another subtransaction. This can be useful when, for example, statements in + 30| | * a transaction may harmlessly fail and you don't want them to abort the + 31| | * entire transaction. Here's an example of how a temporary table may be + 32| | * dropped before re-creating it, without failing if the table did not exist: + 33| | * + 34| | * ```cxx + 35| | * void do_job(connection &cx) + 36| | * { + 37| | * string const temptable = "fleetingtable"; + 38| | * + 39| | * work tx(cx, "do_job"); + 40| | * do_firstpart(tx); + 41| | * + 42| | * // Attempt to delete our temporary table if it already existed. + 43| | * try + 44| | * { + 45| | * subtransaction S(tx, "droptemp"); + 46| | * S.exec0("DROP TABLE " + temptable); + 47| | * S.commit(); + 48| | * } + 49| | * catch (undefined_table const &) + 50| | * { + 51| | * // Table did not exist. Which is what we were hoping to achieve anyway. + 52| | * // Carry on without regrets. + 53| | * } + 54| | * + 55| | * // S may have gone into a failed state and been destroyed, but the + 56| | * // upper-level transaction tx is still fine. We can continue to use it. + 57| | * tx.exec0("CREATE TEMP TABLE " + temptable + "(bar integer, splat + 58| | * varchar)"); + 59| | * + 60| | * do_lastpart(tx); + 61| | * } + 62| | * ``` + 63| | * + 64| | * (This is just an example. If you really wanted to do drop a table without + 65| | * an error if it doesn't exist, you'd use DROP TABLE IF EXISTS.) + 66| | * + 67| | * There are no isolation levels inside a transaction. They are not needed + 68| | * because all actions within the same backend transaction are always performed + 69| | * sequentially anyway. + 70| | * + 71| | * @warning While the subtransaction is "live," you cannot execute queries or + 72| | * open streams etc. on its parent transaction. A transaction can have at most + 73| | * one object of a type derived from @ref pqxx::transaction_focus active on it + 74| | * at a time. + 75| | */ + 76| |class PQXX_LIBEXPORT subtransaction : public transaction_focus, + 77| | public dbtransaction + 78| |{ + 79| |public: + 80| | /// Nest a subtransaction nested in another transaction. + 81| | explicit subtransaction(dbtransaction &t, std::string_view tname = ""sv); + 82| | + 83| | /// Nest a subtransaction in another subtransaction. + 84| | explicit subtransaction(subtransaction &t, std::string_view name = ""sv); + 85| | + 86| | virtual ~subtransaction() noexcept override; + 87| | + 88| |private: + 89| | std::string quoted_name() const + 90| 0| { + 91| 0| return quote_name(transaction_focus::name()); + 92| 0| } + 93| | virtual void do_commit() override; + 94| |}; + 95| |} // namespace pqxx + 96| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/time.hxx: + 1| |/** Support for date/time values. + 2| | * + 3| | * At the moment this supports dates, but not times. + 4| | */ + 5| |#ifndef PQXX_H_TIME + 6| |#define PQXX_H_TIME + 7| | + 8| |#if !defined(PQXX_HEADER_PRE) + 9| |# error "Include libpqxx headers as , not ." + 10| |#endif + 11| | + 12| |#include + 13| |#include + 14| | + 15| |#include "pqxx/internal/concat.hxx" + 16| |#include "pqxx/strconv.hxx" + 17| | + 18| | + 19| |#if defined(PQXX_HAVE_YEAR_MONTH_DAY) + 20| | + 21| |namespace pqxx + 22| |{ + 23| |using namespace std::literals; + 24| | + 25| |template<> + 26| |struct nullness + 27| | : no_null + 28| |{}; + 29| | + 30| | + 31| |/// String representation for a Gregorian date in ISO-8601 format. + 32| |/** @warning Experimental. There may still be design problems, particularly + 33| | * when it comes to BC years. + 34| | * + 35| | * PostgreSQL supports a choice of date formats, but libpqxx does not. The + 36| | * other formats in turn support a choice of "month before day" versus "day + 37| | * before month," meaning that it's not necessarily known which format a given + 38| | * date is supposed to be. So I repeat: ISO-8601-style format only! + 39| | * + 40| | * Invalid dates will not convert. This includes February 29 on non-leap + 41| | * years, which is why it matters that `year_month_day` represents a + 42| | * _Gregorian_ date. + 43| | * + 44| | * The range of years is limited. At the time of writing, PostgreSQL 14 + 45| | * supports years from 4713 BC to 294276 AD inclusive, and C++20 supports + 46| | * a range of 32767 BC to 32767 AD inclusive. So in practice, years must fall + 47| | * between 4713 BC and 32767 AD, inclusive. + 48| | * + 49| | * @warning Support for BC (or BCE) years is still experimental. I still need + 50| | * confirmation on this issue: it looks as if C++ years are astronomical years, + 51| | * which means they have a Year Zero. Regular BC/AD years do not have a year + 52| | * zero, so the year 1 AD follows directly after 1 BC. + 53| | * + 54| | * So, what to our calendars (and to PostgreSQL) is the year "0001 BC" seems to + 55| | * count as year "0" in a `std::chrono::year_month_day`. The year 0001 AD is + 56| | * still equal to 1 as you'd expect, and all AD years work normally, but all + 57| | * years before then are shifted by one. For instance, the year 543 BC would + 58| | * be -542 in C++. + 59| | */ + 60| |template<> struct PQXX_LIBEXPORT string_traits + 61| |{ + 62| | [[nodiscard]] static zview + 63| | to_buf(char *begin, char *end, std::chrono::year_month_day const &value) + 64| 0| { + 65| 0| return generic_to_buf(begin, end, value); + 66| 0| } + 67| | + 68| | static char * + 69| | into_buf(char *begin, char *end, std::chrono::year_month_day const &value); + 70| | + 71| | [[nodiscard]] static std::chrono::year_month_day + 72| | from_string(std::string_view text); + 73| | + 74| | [[nodiscard]] static std::size_t + 75| | size_buffer(std::chrono::year_month_day const &) noexcept + 76| 0| { + 77| 0| static_assert(int{(std::chrono::year::min)()} >= -99999); + 78| 0| static_assert(int{(std::chrono::year::max)()} <= 99999); + 79| 0| return 5 + 1 + 2 + 1 + 2 + std::size(s_bc) + 1; + 80| 0| } + 81| | + 82| |private: + 83| | /// The "BC" suffix for years before 1 AD. + 84| | static constexpr std::string_view s_bc{" BC"sv}; + 85| |}; + 86| |} // namespace pqxx + 87| |#endif // PQXX_HAVE_YEAR_MONTH_DAY + 88| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/transaction.hxx: + 1| |/* Definition of the pqxx::transaction class. + 2| | * pqxx::transaction represents a standard database transaction. + 3| | * + 4| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction instead. + 5| | * + 6| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 7| | * + 8| | * See COPYING for copyright license. If you did not receive a file called + 9| | * COPYING with this source code, please notify the distributor of this + 10| | * mistake, or contact the author. + 11| | */ + 12| |#ifndef PQXX_H_TRANSACTION + 13| |#define PQXX_H_TRANSACTION + 14| | + 15| |#if !defined(PQXX_HEADER_PRE) + 16| |# error "Include libpqxx headers as , not ." + 17| |#endif + 18| | + 19| |#include "pqxx/dbtransaction.hxx" + 20| | + 21| |namespace pqxx::internal + 22| |{ + 23| |/// Helper base class for the @ref transaction class template. + 24| |class PQXX_LIBEXPORT basic_transaction : public dbtransaction + 25| |{ + 26| |protected: + 27| | basic_transaction( + 28| | connection &cx, zview begin_command, std::string_view tname); + 29| | basic_transaction(connection &cx, zview begin_command, std::string &&tname); + 30| | basic_transaction(connection &cx, zview begin_command); + 31| | + 32| | virtual ~basic_transaction() noexcept override = 0; + 33| | + 34| |private: + 35| | virtual void do_commit() override; + 36| |}; + 37| |} // namespace pqxx::internal + 38| | + 39| | + 40| |namespace pqxx + 41| |{ + 42| |/** + 43| | * @ingroup transactions + 44| | */ + 45| |//@{ + 46| | + 47| |/// Standard back-end transaction, templatised on isolation level. + 48| |/** This is the type you'll normally want to use to represent a transaction on + 49| | * the database. + 50| | * + 51| | * Usage example: double all wages. + 52| | * + 53| | * ```cxx + 54| | * extern connection cx; + 55| | * work tx(cx); + 56| | * try + 57| | * { + 58| | * tx.exec("UPDATE employees SET wage=wage*2").no_rows(); + 59| | * tx.commit(); // NOTE: do this inside try block + 60| | * } + 61| | * catch (exception const &e) + 62| | * { + 63| | * cerr << e.what() << endl; + 64| | * tx.abort(); // Usually not needed; same happens when tx's life ends. + 65| | * } + 66| | * ``` + 67| | */ + 68| |template< + 69| | isolation_level ISOLATION = isolation_level::read_committed, + 70| | write_policy READWRITE = write_policy::read_write> + 71| |class transaction final : public internal::basic_transaction + 72| |{ + 73| |public: + 74| | /// Begin a transaction. + 75| | /** + 76| | * @param cx Connection for this transaction to operate on. + 77| | * @param tname Optional name for transaction. Must begin with a letter and + 78| | * may contain letters and digits only. + 79| | */ + 80| | transaction(connection &cx, std::string_view tname) : + 81| | internal::basic_transaction{ + 82| | cx, internal::begin_cmd, tname} + 83| | {} + 84| | + 85| | /// Begin a transaction. + 86| | /** + 87| | * @param cx Connection for this transaction to operate on. + 88| | * may contain letters and digits only. + 89| | */ + 90| | explicit transaction(connection &cx) : + 91| | internal::basic_transaction{ + 92| | cx, internal::begin_cmd} + 93| 0| {} + 94| | + 95| 0| virtual ~transaction() noexcept override { close(); } + 96| |}; + 97| | + 98| | + 99| |/// The default transaction type. + 100| |using work = transaction<>; + 101| | + 102| |/// Read-only transaction. + 103| |using read_transaction = + 104| | transaction; + 105| | + 106| |//@} + 107| |} // namespace pqxx + 108| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/transaction_base.hxx: + 1| |/* Common code and definitions for the transaction classes. + 2| | * + 3| | * pqxx::transaction_base defines the interface for any abstract class that + 4| | * represents a database transaction. + 5| | * + 6| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction_base instead. + 7| | * + 8| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 9| | * + 10| | * See COPYING for copyright license. If you did not receive a file called + 11| | * COPYING with this source code, please notify the distributor of this + 12| | * mistake, or contact the author. + 13| | */ + 14| |#ifndef PQXX_H_TRANSACTION_BASE + 15| |#define PQXX_H_TRANSACTION_BASE + 16| | + 17| |#if !defined(PQXX_HEADER_PRE) + 18| |# error "Include libpqxx headers as , not ." + 19| |#endif + 20| | + 21| |#include + 22| | + 23| |/* End-user programs need not include this file, unless they define their own + 24| | * transaction classes. This is not something the typical program should want + 25| | * to do. + 26| | * + 27| | * However, reading this file is worthwhile because it defines the public + 28| | * interface for the available transaction classes such as transaction and + 29| | * nontransaction. + 30| | */ + 31| | + 32| |#include "pqxx/connection.hxx" + 33| |#include "pqxx/internal/concat.hxx" + 34| |#include "pqxx/internal/encoding_group.hxx" + 35| |#include "pqxx/internal/stream_query.hxx" + 36| |#include "pqxx/isolation.hxx" + 37| |#include "pqxx/prepared_statement.hxx" + 38| |#include "pqxx/result.hxx" + 39| |#include "pqxx/row.hxx" + 40| |#include "pqxx/util.hxx" + 41| | + 42| |namespace pqxx::internal::gate + 43| |{ + 44| |class transaction_subtransaction; + 45| |class transaction_sql_cursor; + 46| |class transaction_stream_to; + 47| |class transaction_transaction_focus; + 48| |} // namespace pqxx::internal::gate + 49| | + 50| | + 51| |namespace pqxx + 52| |{ + 53| |using namespace std::literals; + 54| | + 55| | + 56| |class transaction_focus; + 57| | + 58| | + 59| |/** + 60| | * @defgroup transactions Transaction classes + 61| | * + 62| | * All database access goes through instances of these classes. In libpqxx + 63| | * you can't execute SQL directly on the connection object; that all happens + 64| | * only on a transaction object. If you don't actually want to start a + 65| | * transaction on the server, there's a @ref nontransaction class which + 66| | * operates in _autocommit,_ i.e. without a transaction. + 67| | * + 68| | * (Why do you always need a transaction object? It ended up being the cleaner + 69| | * choice in terms of interface design. It avoids a bunch of API maladies: + 70| | * duplicating API between classes, messy inheritance, inviting mistakes by + 71| | * making the transaction afterthought, and so on.) + 72| | * + 73| | * Like most other things in libpqxx, transactions follow RAII principles. + 74| | * Creating a transaction object starts the transaction on the backend (if + 75| | * appropriate), and to destroying one ends the transaction. But there's one + 76| | * extra step: if you want to make the transaction's changes permanent, you + 77| | * need to _commit_ it before you destroy it. If you destroy the transaction + 78| | * object without committing, or if you call its `abort()` member function, + 79| | * then any transaction type (other than @ref nontransaction) will roll back + 80| | * its changes to the database instead. + 81| | * + 82| | * There is a choice of transaction types. To start with you'll probably want + 83| | * to use @ref work, represents a regular, vanilla transaction with the default + 84| | * isolation level. + 85| | * + 86| | * All the actual transaction functionality, including all the functions for + 87| | * executing SQL statements, lives in the abstract @ref transaction_base class. + 88| | * It defines the API for each type of transaction. You create a transaction, + 89| | * you use it by calling @ref transaction_base member functions, and then you + 90| | * either commit or (in the case of failure) abort. If you destroy your + 91| | * transaction object without doing either, it automatically aborts. + 92| | * + 93| | * Once you're done with your transaction, you can start a new one using the + 94| | * same connection. But there can be only one main transaction going on on a + 95| | * connection at any given time. (You _can_ have more "nested" transactions, + 96| | * but I'm not counting those as "main" transactions here. See below.) + 97| | * + 98| | * The concrete transaction types, all derived from @ref transaction_base, are: + 99| | * + 100| | * First and foremost, the plain @ref transaction template. Template + 101| | * parameters let you select isolation level, and whether it should be + 102| | * read-only. Two aliases are usually more convenient: @ref work is a + 103| | * regular, run-of-the-mill default transaction. @ref read_transaction is a + 104| | * read-only transaction that will not let you modify the database. + 105| | * + 106| | * Then there's @ref nontransaction. This one runs in autocommit, meaning + 107| | * that we don't start any transaction at all. (Technically in this mode each + 108| | * SQL command runs in its own little transaction, hence the term + 109| | * "autocommit." There is no way to "undo" an SQL statement in this kind of + 110| | * transaction.) Autocommit is sometimes a bit faster, and sometimes a bit + 111| | * slower. Mainly you'll use it for specific operations that cannot be done + 112| | *inside a database transaction, such as some kinds of schema changes. + 113| | * + 114| | * And then ther's @ref robusttransaction to help you deal with those painful + 115| | * situations where you don't know for sure whether a transaction actually + 116| | * succeeded. This can happen if you lose your network connection to the + 117| | * database _just_ while you're trying to commit your transaction, before you + 118| | * receive word about the outcome. You can re-connect and find out, but what + 119| | * if the server is still executing the commit? + 120| | * + 121| | * You could say that @ref robusttransaction is not more robust, exactly, but + 122| | * it goes to some extra effort to try and figure these situations out and give + 123| | * you clarity. Extra effort does actually mean more things that can go wrong, + 124| | * and it may be a litte slower, so investigate carefully before using this + 125| | * transaction class. + 126| | * + 127| | * All of the transaction types that actually begin and commit/abort on the + 128| | * database itself are derived from @ref dbtransaction, which can be a useful + 129| | * type if your code needs a reference to such a transaction but doesn't need + 130| | * to enforce a particular one. These types are @ref transaction, @ref work, + 131| | * @ref read_transaction, and @ref robusttransaction. + 132| | * + 133| | * Finally, there's @ref subtransaction. This one is not at all like the + 134| | * others: it can only exist inside a @ref dbtransaction. (Which includes + 135| | * @ref subtransaction itself: you can nest them freely.) You can only + 136| | * operate on the "innermost" active subtransaction at any given time, until + 137| | * you either commit or abort it. Subtransactions are built on _savepoints_ + 138| | * in the database; these are efficient to a point but do consume some server + 139| | * resources. So use them when they make sense, e.g. to try an SQL statement + 140| | * but continue your main transation if it fails. But don't create them in + 141| | * enormous numbers, or performance may start to suffer. + 142| | */ + 143| | + 144| |/// Interface definition (and common code) for "transaction" classes. + 145| |/** + 146| | * @ingroup transactions + 147| | * + 148| | * Abstract base class for all transaction types. + 149| | */ + 150| |class PQXX_LIBEXPORT PQXX_NOVTABLE transaction_base + 151| |{ + 152| |public: + 153| | transaction_base() = delete; + 154| | transaction_base(transaction_base const &) = delete; + 155| | transaction_base(transaction_base &&) = delete; + 156| | transaction_base &operator=(transaction_base const &) = delete; + 157| | transaction_base &operator=(transaction_base &&) = delete; + 158| | + 159| | virtual ~transaction_base() = 0; + 160| | + 161| | /// Commit the transaction. + 162| | /** Make the effects of this transaction definite. If you destroy a + 163| | * transaction without invoking its @ref commit() first, that will implicitly + 164| | * abort it. (For the @ref nontransaction class though, "commit" and "abort" + 165| | * really don't do anything, hence its name.) + 166| | * + 167| | * There is, however, a minute risk that you might lose your connection to + 168| | * the database at just the wrong moment here. In that case, libpqxx may be + 169| | * unable to determine whether the database was able to complete the + 170| | * transaction, or had to roll it back. In that scenario, @ref commit() will + 171| | * throw an in_doubt_error. There is a different transaction class called + 172| | * @ref robusttransaction which takes some special precautions to reduce this + 173| | * risk. + 174| | */ + 175| | void commit(); + 176| | + 177| | /// Abort the transaction. + 178| | /** No special effort is required to call this function; it will be called + 179| | * implicitly when the transaction is destructed. + 180| | */ + 181| | void abort(); + 182| | + 183| | /** + 184| | * @ingroup escaping-functions + 185| | * + 186| | * Use these when writing SQL queries that incorporate C++ values as SQL + 187| | * constants. + 188| | * + 189| | * The functions you see here are just convenience shortcuts to the same + 190| | * functions on the connection object. + 191| | */ + 192| | //@{ + 193| | /// Escape string for use as SQL string literal in this transaction. + 194| | template [[nodiscard]] auto esc(ARGS &&...args) const + 195| | { + 196| | return conn().esc(std::forward(args)...); + 197| | } + 198| | + 199| | /// Escape binary data for use as SQL string literal in this transaction. + 200| | /** Raw, binary data is treated differently from regular strings. Binary + 201| | * strings are never interpreted as text, so they may safely include byte + 202| | * values or byte sequences that don't happen to represent valid characters + 203| | * in the character encoding being used. + 204| | * + 205| | * The binary string does not stop at the first zero byte, as is the case + 206| | * with textual strings. Instead, it may contain zero bytes anywhere. If + 207| | * it happens to contain bytes that look like quote characters, or other + 208| | * things that can disrupt their use in SQL queries, they will be replaced + 209| | * with special escape sequences. + 210| | */ + 211| | template [[nodiscard]] auto esc_raw(ARGS &&...args) const + 212| | { + 213| | return conn().esc_raw(std::forward(args)...); + 214| | } + 215| | + 216| | /// Unescape binary data, e.g. from a `bytea` field. + 217| | /** Takes a binary string as escaped by PostgreSQL, and returns a restored + 218| | * copy of the original binary data. + 219| | */ + 220| | [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string + 221| | unesc_raw(zview text) const + 222| 0| { + 223| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 224| 0| return conn().unesc_raw(text); + 225| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 226| 0| } + 227| | + 228| | /// Unescape binary data, e.g. from a `bytea` field. + 229| | /** Takes a binary string as escaped by PostgreSQL, and returns a restored + 230| | * copy of the original binary data. + 231| | */ + 232| 0| [[nodiscard]] bytes unesc_bin(zview text) { return conn().unesc_bin(text); } + 233| | + 234| | /// Unescape binary data, e.g. from a `bytea` field. + 235| | /** Takes a binary string as escaped by PostgreSQL, and returns a restored + 236| | * copy of the original binary data. + 237| | */ + 238| | [[nodiscard, deprecated("Use unesc_bin() instead.")]] std::string + 239| | unesc_raw(char const *text) const + 240| 0| { + 241| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 242| 0| return conn().unesc_raw(text); + 243| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 244| 0| } + 245| | + 246| | /// Unescape binary data, e.g. from a `bytea` field. + 247| | /** Takes a binary string as escaped by PostgreSQL, and returns a restored + 248| | * copy of the original binary data. + 249| | */ + 250| | [[nodiscard]] bytes unesc_bin(char const text[]) + 251| 0| { + 252| 0| return conn().unesc_bin(text); + 253| 0| } + 254| | + 255| | /// Represent object as SQL string, including quoting & escaping. + 256| | /** Nulls are recognized and represented as SQL nulls. */ + 257| | template [[nodiscard]] std::string quote(T const &t) const + 258| 0| { + 259| 0| return conn().quote(t); + 260| 0| } + 261| | + 262| | [[deprecated("Use bytes instead of binarystring.")]] std::string + 263| | quote(binarystring const &t) const + 264| 0| { + 265| 0| return conn().quote(t.bytes_view()); + 266| 0| } + 267| | + 268| | /// Binary-escape and quote a binary string for use as an SQL constant. + 269| | [[deprecated("Use quote(pqxx::bytes_view).")]] std::string + 270| | quote_raw(unsigned char const bin[], std::size_t len) const + 271| 0| { + 272| 0| return quote(binary_cast(bin, len)); + 273| 0| } + 274| | + 275| | /// Binary-escape and quote a binary string for use as an SQL constant. + 276| | [[deprecated("Use quote(pqxx::bytes_view).")]] std::string + 277| | quote_raw(zview bin) const; + 278| | + 279| |#if defined(PQXX_HAVE_CONCEPTS) + 280| | /// Binary-escape and quote a binary string for use as an SQL constant. + 281| | /** For binary data you can also just use @ref quote(data). */ + 282| | template + 283| | [[nodiscard]] std::string quote_raw(DATA const &data) const + 284| | { + 285| | return conn().quote_raw(data); + 286| | } + 287| |#endif + 288| | + 289| | /// Escape an SQL identifier for use in a query. + 290| | [[nodiscard]] std::string quote_name(std::string_view identifier) const + 291| 0| { + 292| 0| return conn().quote_name(identifier); + 293| 0| } + 294| | + 295| | /// Escape string for literal LIKE match. + 296| | [[nodiscard]] std::string + 297| | esc_like(std::string_view bin, char escape_char = '\\') const + 298| 0| { + 299| 0| return conn().esc_like(bin, escape_char); + 300| 0| } + 301| | //@} + 302| | + 303| | /** + 304| | * @name Command execution + 305| | * + 306| | * There are many functions for executing (or "performing") a command (or + 307| | * "query"). This is the most fundamental thing you can do in libpqxx, and + 308| | * it always starts at a transaction class. + 309| | * + 310| | * Command execution can throw many types of exception, including sql_error, + 311| | * broken_connection, and many sql_error subtypes such as + 312| | * feature_not_supported or insufficient_privilege. But any exception thrown + 313| | * by the C++ standard library may also occur here. All exceptions you will + 314| | * see libpqxx throw are derived from std::exception. + 315| | * + 316| | * Most of the differences between the query execution functions are in how + 317| | * they return the query's results. + 318| | * + 319| | * * The "query" functions run your query, wait for it to complete, and load + 320| | * all of the results into memory on the client side. You can then access + 321| | * rows of result data, converted to C++ types that you request. + 322| | * * The "stream" functions execute your query in a completely different way. + 323| | * Called _streaming queries,_ these don't support quite the full range of + 324| | * SQL queries, and they're a bit slower to start. But they are + 325| | * significantly _faster_ for queries that return larger numbers of rows. + 326| | * They don't load the entire result set, so you can start processing data + 327| | * as soon as the first row of data comes in from the database. This can + 328| | * This can save you a lot of time. Processing itself may also be faster. + 329| | * And of course, it also means you don't need enough memory to hold the + 330| | * entire result set, just the row you're working on. + 331| | * * The "exec" functions are a more low-level interface. Most of them + 332| | * return a pqxx::result object. This is an object that contains all + 333| | * information abouut the query's result: the data itself, but also the + 334| | * number of rows in the result, the column names, the number of rows that + 335| | * your query may have modified, and so on. + 336| | */ + 337| | //@{ + 338| | + 339| | /// Execute a command. + 340| | /** + 341| | * @param query Query or command to execute. + 342| | * @param desc Optional identifier for query, to help pinpoint SQL errors. + 343| | * @return A result set describing the query's or command's result. + 344| | */ + 345| | [[deprecated("The desc parameter is going away.")]] + 346| | result exec(std::string_view query, std::string_view desc); + 347| | + 348| | // TODO: Wrap PQdescribePrepared(). + 349| | + 350| | result exec(std::string_view query, params parms) + 351| 0| { + 352| 0| return internal_exec_params(query, parms.make_c_params()); + 353| 0| } + 354| | + 355| | /// Execute a command. + 356| | /** + 357| | * @param query Query or command to execute. + 358| | * @return A result set describing the query's or command's result. + 359| | */ + 360| | result exec(std::string_view query) + 361| 0| { + 362| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 363| 0| return exec(query, std::string_view{}); + 364| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 365| 0| } + 366| | + 367| | /// Execute a command. + 368| | /** + 369| | * @param query Query or command to execute. + 370| | * @param desc Optional identifier for query, to help pinpoint SQL errors. + 371| | * @return A result set describing the query's or command's result. + 372| | */ + 373| | [[deprecated( + 374| | "Pass your query as a std::string_view, not stringstream.")]] result + 375| | exec(std::stringstream const &query, std::string_view desc) + 376| 0| { + 377| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 378| 0| return exec(query.str(), desc); + 379| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 380| 0| } + 381| | + 382| | /// Execute command, which should return zero rows of data. + 383| | /** Works like @ref exec, but fails if the result contains data. It still + 384| | * returns a result, however, which may contain useful metadata. + 385| | * + 386| | * @throw unexpected_rows If the query returned the wrong number of rows. + 387| | */ + 388| | [[deprecated("Use exec(string_view) and call no_rows() on the result.")]] + 389| | result exec0(zview query, std::string_view desc) + 390| 0| { + 391| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 392| 0| return exec(query, desc).no_rows(); + 393| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 394| 0| } + 395| | + 396| | /// Execute command, which should return zero rows of data. + 397| | /** Works like @ref exec, but fails if the result contains data. It still + 398| | * returns a result, however, which may contain useful metadata. + 399| | * + 400| | * @throw unexpected_rows If the query returned the wrong number of rows. + 401| | */ + 402| | [[deprecated("Use exec() and call no_rows() on the result.")]] + 403| | result exec0(zview query) + 404| 0| { + 405| 0| return exec(query).no_rows(); + 406| 0| } + 407| | + 408| | /// Execute command returning a single row of data. + 409| | /** Works like @ref exec, but requires the result to contain exactly one row. + 410| | * The row can be addressed directly, without the need to find the first row + 411| | * in a result set. + 412| | * + 413| | * @throw unexpected_rows If the query returned the wrong number of rows. + 414| | */ + 415| | [[deprecated("Use exec(string_view), and call one_row() on the result.")]] + 416| | row exec1(zview query, std::string_view desc) + 417| 0| { + 418| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 419| 0| return exec(query, desc).one_row(); + 420| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 421| 0| } + 422| | + 423| | /// Execute command returning a single row of data. + 424| | /** Works like @ref exec, but requires the result to contain exactly one row. + 425| | * The row can be addressed directly, without the need to find the first row + 426| | * in a result set. + 427| | * + 428| | * @throw unexpected_rows If the query returned the wrong number of rows. + 429| | */ + 430| | [[deprecated("Use exec() instead, and call one_row() on the result.")]] + 431| | row exec1(zview query) + 432| 0| { + 433| 0| return exec(query).one_row(); + 434| 0| } + 435| | + 436| | /// Execute command, expect given number of rows. + 437| | /** Works like @ref exec, but checks that the result has exactly the expected + 438| | * number of rows. + 439| | * + 440| | * @throw unexpected_rows If the query returned the wrong number of rows. + 441| | */ + 442| | [[deprecated("Use exec() instead, and call expect_rows() on the result.")]] + 443| | result exec_n(result::size_type rows, zview query, std::string_view desc); + 444| | + 445| | /// Execute command, expect given number of rows. + 446| | /** Works like @ref exec, but checks that the result has exactly the expected + 447| | * number of rows. + 448| | * + 449| | * @throw unexpected_rows If the query returned the wrong number of rows. + 450| | */ + 451| | [[deprecated("Use exec() instead, and call expect_rows() on the result.")]] + 452| | result exec_n(result::size_type rows, zview query) + 453| 0| { + 454| 0|#include "pqxx/internal/ignore-deprecated-pre.hxx" + 455| 0| return exec(query, std::string_view{}).expect_rows(rows); + 456| 0|#include "pqxx/internal/ignore-deprecated-post.hxx" + 457| 0| } + 458| | + 459| | /// Perform query, expecting exactly 1 row with 1 field, and convert it. + 460| | /** This is convenience shorthand for querying exactly one value from the + 461| | * database. It returns that value, converted to the type you specify. + 462| | */ + 463| | template + 464| | [[deprecated("The desc parameter is going away.")]] + 465| | TYPE query_value(zview query, std::string_view desc) + 466| | { + 467| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 468| | return exec(query, desc).one_field().as(); + 469| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 470| | } + 471| | + 472| | /// Perform query, expecting exactly 1 row with 1 field, and convert it. + 473| | /** This is convenience shorthand for querying exactly one value from the + 474| | * database. It returns that value, converted to the type you specify. + 475| | * + 476| | * @throw unexpected_rows If the query did not return exactly 1 row. + 477| | * @throw usage_error If the row did not contain exactly 1 field. + 478| | */ + 479| | template TYPE query_value(zview query) + 480| | { + 481| | return exec(query).one_field().as(); + 482| | } + 483| | + 484| | /// Perform query returning exactly one row, and convert its fields. + 485| | /** This is a convenient way of querying one row's worth of data, and + 486| | * converting its fields to a tuple of the C++-side types you specify. + 487| | * + 488| | * @throw unexpected_rows If the query did not return exactly 1 row. + 489| | * @throw usage_error If the number of columns in the result does not match + 490| | * the number of fields in the tuple. + 491| | */ + 492| | template + 493| | [[nodiscard]] std::tuple query1(zview query) + 494| | { + 495| | return exec(query).expect_columns(sizeof...(TYPE)).one_row().as(); + 496| | } + 497| | + 498| | /// Query at most one row of data, and if there is one, convert it. + 499| | /** If the query produced a row of data, this converts it to a tuple of the + 500| | * C++ types you specify. Otherwise, this returns no tuple. + 501| | * + 502| | * @throw unexpected_rows If the query returned more than 1 row. + 503| | * @throw usage_error If the number of columns in the result does not match + 504| | * the number of fields in the tuple. + 505| | */ + 506| | template + 507| | [[nodiscard]] std::optional> query01(zview query) + 508| | { + 509| | std::optional const r{exec(query).opt_row()}; + 510| | if (r) + 511| | return {r->as()}; + 512| | else + 513| | return {}; + 514| | } + 515| | + 516| | /// Execute a query, in streaming fashion; loop over the results row by row. + 517| | /** Converts the rows to `std::tuple`, of the column types you specify. + 518| | * + 519| | * Use this with a range-based "for" loop. It executes the query, and + 520| | * directly maps the resulting rows onto a `std::tuple` of the types you + 521| | * specify. Unlike with the "exec" functions, processing can start before + 522| | * all the data from the server is in. + 523| | * + 524| | * Streaming is also documented in @ref streams. + 525| | * + 526| | * The column types must all be types that have conversions from PostgreSQL's + 527| | * text format defined. Many built-in types such as `int` or `std::string` + 528| | * have pre-defined conversions; if you want to define your own conversions + 529| | * for additional types, see @ref datatypes. + 530| | * + 531| | * As a special case, tuple may contain `std::string_view` fields, but the + 532| | * strings to which they point will only remain valid until you extract the + 533| | * next row. After that, the memory holding the string may be overwritten or + 534| | * deallocated. + 535| | * + 536| | * If any of the columns can be null, and the C++ type to which you're + 537| | * translating it does not have a null value, wrap the type in a + 538| | * `std::optional<>` (or if you prefer, a `std::shared_ptr<>` or a + 539| | * `std::unique_ptr`). These templates do support null values, and libpqxx + 540| | * will know how to convert to them. + 541| | * + 542| | * The stream lives entirely within the lifetime of the transaction. Make + 543| | * sure you complete the stream before you destroy the transaction. Until + 544| | * the stream has finished, the transaction and the connection are in a + 545| | * special state where they cannot be used for anything else. + 546| | * + 547| | * @warning If the stream fails, you will have to destroy the transaction + 548| | * and the connection. If this is a problem, use the "exec" functions + 549| | * instead. + 550| | * + 551| | * Streaming your query is likely to be faster than the `exec()` methods for + 552| | * larger results (but slower for small results), and start useful processing + 553| | * sooner. Also, `stream()` scales better in terms of memory usage: it only + 554| | * needs to keep the current row in memory. The "exec" functions read the + 555| | * entire result into memory at once. + 556| | * + 557| | * Your query executes as part of a COPY command, not as a stand-alone query, + 558| | * so there are limitations to what you can do in the query. It can be + 559| | * either a SELECT or VALUES query; or an INSERT, UPDATE, or DELETE with a + 560| | * RETURNING clause. See the documentation for PostgreSQL's + 561| | * [COPY command](https://www.postgresql.org/docs/current/sql-copy.html) for + 562| | * the exact restrictions. + 563| | * + 564| | * Iterating in this way does require each of the field types you pass to be + 565| | * default-constructible, copy-constructible, and assignable. These + 566| | * requirements may loosen a bit once libpqxx moves on to C++20. + 567| | */ + 568| | template + 569| | [[nodiscard]] auto stream(std::string_view query) & + 570| | { + 571| | return pqxx::internal::stream_query{*this, query}; + 572| | } + 573| | + 574| | /// Execute a query, in streaming fashion; loop over the results row by row. + 575| | /** Like @ref stream(std::string_view), but with parameters. + 576| | */ + 577| | template + 578| | [[nodiscard]] auto stream(std::string_view query, params parms) & + 579| | { + 580| | return pqxx::internal::stream_query{*this, query, parms}; + 581| | } + 582| | + 583| | // C++20: Concept like std::invocable, but without specifying param types. + 584| | /// Perform a streaming query, and for each result row, call `func`. + 585| | /** Here, `func` can be a function, a `std::function`, a lambda, or an + 586| | * object that supports the function call operator. Of course `func` must + 587| | * have an unambiguous signature; it can't be overloaded or generic. + 588| | * + 589| | * The `for_stream` function executes `query` in a stream similar to + 590| | * @ref stream. Every time a row of data comes in from the server, it + 591| | * converts the row's fields to the types of `func`'s respective parameters, + 592| | * and calls `func` with those values. + 593| | * + 594| | * This will not work for all queries, but straightforward `SELECT` and + 595| | * `UPDATE ... RETURNING` queries should work. Consult the documentation for + 596| | * @ref pqxx::internal::stream_query and PostgreSQL's underlying `COPY` + 597| | * command for the full details. + 598| | * + 599| | * Streaming a query like this is likely to be slower than the @ref exec() + 600| | * functions for small result sets, but faster for larger result sets. So if + 601| | * performance matters, you'll want to use `for_stream` if you query large + 602| | * amounts of data, but not if you do lots of queries with small outputs. + 603| | * + 604| | * However, the transaction and the connection are in a special state while + 605| | * the iteration is ongoing. If `func` throws an exception, or the iteration + 606| | * fails in some way, the only way out is to destroy the transaction and the + 607| | * connection. + 608| | * + 609| | * Each of the parameter types must have a conversion from PostgreSQL's text + 610| | * format defined. To define conversions for additional types, see + 611| | * @ref datatypes. + 612| | */ + 613| | template + 614| | auto for_stream(std::string_view query, CALLABLE &&func) + 615| | { + 616| | using param_types = + 617| | pqxx::internal::strip_types_t>; + 618| | param_types const *const sample{nullptr}; + 619| | auto data_stream{stream_like(query, sample)}; + 620| | for (auto const &fields : data_stream) std::apply(func, fields); + 621| | } + 622| | + 623| | template + 624| | [[deprecated( + 625| | "pqxx::transaction_base::for_each is now called for_stream.")]] auto + 626| | for_each(std::string_view query, CALLABLE &&func) + 627| | { + 628| | return for_stream(query, std::forward(func)); + 629| | } + 630| | + 631| | /// Execute query, read full results, then iterate rows of data. + 632| | /** Converts each row of the result to a `std::tuple` of the types you pass + 633| | * as template arguments. (The number of template arguments must match the + 634| | * number of columns in the query's result.) + 635| | * + 636| | * Example: + 637| | * + 638| | * ```cxx + 639| | * for ( + 640| | * auto [name, salary] : + 641| | * tx.query( + 642| | * "SELECT name, salary FROM employee" + 643| | ) + 644| | * ) + 645| | * std::cout << name << " earns " << salary << ".\n"; + 646| | * ``` + 647| | * + 648| | * You can't normally convert a field value to `std::string_view`, but this + 649| | * is one of the places where you can. The underlying string to which the + 650| | * `string_view` points exists only for the duration of the one iteration. + 651| | * After that, the buffer that holds the actual string may have disappeared, + 652| | * or it may contain a new string value. + 653| | * + 654| | * If you expect a lot of rows from your query, it's probably faster to use + 655| | * transaction_base::stream() instead. Or if you need to access metadata of + 656| | * the result, such as the number of rows in the result, or the number of + 657| | * rows that your query updates, then you'll need to use + 658| | * transaction_base::exec() instead. + 659| | * + 660| | * @return Something you can iterate using "range `for`" syntax. The actual + 661| | * type details may change. + 662| | */ + 663| | template auto query(zview query) + 664| | { + 665| | return exec(query).iter(); + 666| | } + 667| | + 668| | /// Perform query, expect given number of rows, iterate results. + 669| | template + 670| | [[deprecated("Use query() instead, and call expect_rows() on the result.")]] + 671| | auto query_n(result::size_type rows, zview query) + 672| | { + 673| | return exec(query).expect_rows(rows).iter(); + 674| | } + 675| | + 676| | // C++20: Concept like std::invocable, but without specifying param types. + 677| | /// Execute a query, load the full result, and perform `func` for each row. + 678| | /** Converts each row to data types matching `func`'s parameter types. The + 679| | * number of columns in the result set must match the number of parameters. + 680| | * + 681| | * This is a lot like for_stream(). The differences are: + 682| | * 1. It can execute some unusual queries that for_stream() can't. + 683| | * 2. The `exec` functions are faster for small results, but slower for large + 684| | * results. + 685| | */ + 686| | template void for_query(zview query, CALLABLE &&func) + 687| | { + 688| | exec(query).for_each(std::forward(func)); + 689| | } + 690| | + 691| | /** + 692| | * @name Parameterized statements + 693| | * + 694| | * You'll often need parameters in the queries you execute: "select the + 695| | * car with this licence plate." If the parameter is a string, you need to + 696| | * quote it and escape any special characters inside it, or it may become a + 697| | * target for an SQL injection attack. If it's an integer (for example), + 698| | * you need to convert it to a string, but in the database's format, without + 699| | * locale-specific niceties such as "," separators between the thousands. + 700| | * + 701| | * Parameterised statements are an easier and safer way to do this. They're + 702| | * like prepared statements, but for a single use. You don't need to name + 703| | * them, and you don't need to prepare them first. + 704| | * + 705| | * Your query will include placeholders like `$1` and `$2` etc. in the places + 706| | * where you want the arguments to go. Then, you pass the argument values + 707| | * and the actual query is constructed for you. + 708| | * + 709| | * Pass the exact right number of parameters, and in the right order. The + 710| | * parameters in the query don't have to be neatly ordered from `$1` to + 711| | * `$2` to `$3` - but you must pass the argument for `$1` first, the one + 712| | * for `$2` second, etc. + 713| | * + 714| | * @warning Beware of "nul" bytes. Any string you pass as a parameter will + 715| | * end at the first char with value zero. If you pass a string that contains + 716| | * a zero byte, the last byte in the value will be the one just before the + 717| | * zero. + 718| | */ + 719| | //@{ + 720| | + 721| | /// Execute an SQL statement with parameters. + 722| | /** This is like calling `exec()`, except it will substitute the first + 723| | * parameter after `query` (the first in `args`) for a `$1` in the query, the + 724| | * next one for `$2`, etc. + 725| | */ + 726| | template + 727| | [[deprecated("Use exec(zview, params) instead.")]] + 728| | result exec_params(std::string_view query, Args &&...args) + 729| | { + 730| | return exec(query, params{args...}); + 731| | } + 732| | + 733| | // Execute parameterised statement, expect a single-row result. + 734| | /** @throw unexpected_rows if the result does not consist of exactly one row. + 735| | */ + 736| | template + 737| | [[deprecated("Use exec() instead, and call one_row() on the result.")]] + 738| | row exec_params1(zview query, Args &&...args) + 739| | { + 740| | return exec(query, params{args...}).one_row(); + 741| | } + 742| | + 743| | // Execute parameterised statement, expect a result with zero rows. + 744| | /** @throw unexpected_rows if the result contains rows. + 745| | */ + 746| | template + 747| | [[deprecated( + 748| | "Use exec(string_view, params) and call no_rows() on the result.")]] + 749| | result exec_params0(zview query, Args &&...args) + 750| | { + 751| | return exec(query, params{args...}).no_rows(); + 752| | } + 753| | + 754| | // Execute parameterised statement, expect exactly a given number of rows. + 755| | /** @throw unexpected_rows if the result contains the wrong number of rows. + 756| | */ + 757| | template + 758| | [[deprecated("Use exec(), and call expect_rows() on the result.")]] + 759| | result exec_params_n(std::size_t rows, zview query, Args &&...args) + 760| | { + 761| | return exec(query, params{args...}) + 762| | .expect_rows(check_cast(rows, "number of rows")); + 763| | } + 764| | + 765| | // Execute parameterised statement, expect exactly a given number of rows. + 766| | /** @throw unexpected_rows if the result contains the wrong number of rows. + 767| | */ + 768| | template + 769| | [[deprecated("Use exec(), and call expect_rows() on the result.")]] + 770| | result exec_params_n(result::size_type rows, zview query, Args &&...args) + 771| | { + 772| | return exec(query, params{args...}).expect_rows(rows); + 773| | } + 774| | + 775| | /// Execute parameterised query, read full results, iterate rows of data. + 776| | /** Like @ref query, but the query can contain parameters. + 777| | * + 778| | * Converts each row of the result to a `std::tuple` of the types you pass + 779| | * as template arguments. (The number of template arguments must match the + 780| | * number of columns in the query's result.) + 781| | * + 782| | * Example: + 783| | * + 784| | * ```cxx + 785| | * for ( + 786| | * auto [name, salary] : + 787| | * tx.query( + 788| | * "SELECT name, salary FROM employee" + 789| | ) + 790| | * ) + 791| | * std::cout << name << " earns " << salary << ".\n"; + 792| | * ``` + 793| | * + 794| | * You can't normally convert a field value to `std::string_view`, but this + 795| | * is one of the places where you can. The underlying string to which the + 796| | * `string_view` points exists only for the duration of the one iteration. + 797| | * After that, the buffer that holds the actual string may have disappeared, + 798| | * or it may contain a new string value. + 799| | * + 800| | * If you expect a lot of rows from your query, it's probably faster to use + 801| | * transaction_base::stream() instead. Or if you need to access metadata of + 802| | * the result, such as the number of rows in the result, or the number of + 803| | * rows that your query updates, then you'll need to use + 804| | * transaction_base::exec() instead. + 805| | * + 806| | * @return Something you can iterate using "range `for`" syntax. The actual + 807| | * type details may change. + 808| | */ + 809| | template auto query(zview query, params const &parms) + 810| | { + 811| | return exec(query, parms).iter(); + 812| | } + 813| | + 814| | /// Perform query parameterised, expect given number of rows, iterate + 815| | /// results. + 816| | /** Works like @ref query, but checks that the result has exactly the + 817| | * expected number of rows. + 818| | * + 819| | * @throw unexpected_rows If the query returned the wrong number of rows. + 820| | * + 821| | * @return Something you can iterate using "range `for`" syntax. The actual + 822| | * type details may change. + 823| | */ + 824| | template + 825| | [[deprecated("Use exec(), and call expect_rows() & iter() on the result.")]] + 826| | auto query_n(result::size_type rows, zview query, params const &parms) + 827| | { + 828| | return exec(query, parms).expect_rows(rows).iter(); + 829| | } + 830| | + 831| | /// Perform query, expecting exactly 1 row with 1 field, and convert it. + 832| | /** This is convenience shorthand for querying exactly one value from the + 833| | * database. It returns that value, converted to the type you specify. + 834| | * + 835| | * @throw unexpected_rows If the query did not return exactly 1 row. + 836| | * @throw usage_error If the row did not contain exactly 1 field. + 837| | */ + 838| | template TYPE query_value(zview query, params const &parms) + 839| | { + 840| | return exec(query, parms).expect_columns(1).one_field().as(); + 841| | } + 842| | + 843| | /// Perform query returning exactly one row, and convert its fields. + 844| | /** This is a convenient way of querying one row's worth of data, and + 845| | * converting its fields to a tuple of the C++-side types you specify. + 846| | * + 847| | * @throw unexpected_rows If the query did not return exactly 1 row. + 848| | * @throw usage_error If the number of columns in the result does not match + 849| | * the number of fields in the tuple. + 850| | */ + 851| | template + 852| | [[nodiscard]] + 853| | std::tuple query1(zview query, params const &parms) + 854| | { + 855| | return exec(query, parms).one_row().as(); + 856| | } + 857| | + 858| | /// Query at most one row of data, and if there is one, convert it. + 859| | /** If the query produced a row of data, this converts it to a tuple of the + 860| | * C++ types you specify. Otherwise, this returns no tuple. + 861| | * + 862| | * @throw unexpected_rows If the query returned more than 1 row. + 863| | * @throw usage_error If the number of columns in the result does not match + 864| | * the number of fields in the tuple. + 865| | */ + 866| | template + 867| | [[nodiscard]] std::optional> + 868| | query01(zview query, params const &parms) + 869| | { + 870| | std::optional r{exec(query, parms).opt_row()}; + 871| | if (r) + 872| | return {r->as()}; + 873| | else + 874| | return {}; + 875| | } + 876| | + 877| | // C++20: Concept like std::invocable, but without specifying param types. + 878| | /// Execute a query, load the full result, and perform `func` for each row. + 879| | /** The query may use parameters. So for example, the query may contain `$1` + 880| | * to denote the first parameter value in `parms`, and so on. + 881| | * + 882| | * Converts each row to data types matching `func`'s parameter types. The + 883| | * number of columns in the result set must match the number of parameters. + 884| | * + 885| | * This is a lot like for_stream(). The differences are: + 886| | * 1. It can execute some unusual queries that for_stream() can't. + 887| | * 2. The `exec` functions are faster for small results, but slower for large + 888| | * results. + 889| | */ + 890| | template + 891| | void for_query(zview query, CALLABLE &&func, params const &parms) + 892| | { + 893| | exec(query, parms).for_each(std::forward(func)); + 894| | } + 895| | + 896| | /// Send a notification. + 897| | /** Convenience shorthand for executing a "NOTIFY" command. Most of the + 898| | * logic for handling _incoming_ notifications is in @ref pqxx::connection + 899| | * (particularly @ref pqxx::connection::listen), but _outgoing_ + 900| | * notifications happen here. + 901| | * + 902| | * Unless this transaction is a nontransaction, the actual notification only + 903| | * goes out once the outer transaction is committed. + 904| | * + 905| | * @param channel Name of the "channel" on which clients will need to be + 906| | * listening in order to receive this notification. + 907| | * + 908| | * @param payload Optional argument string which any listeners will also + 909| | * receive. If you leave this out, they will receive an empty string as the + 910| | * payload. + 911| | */ + 912| | void notify(std::string_view channel, std::string_view payload = {}); + 913| | //@} + 914| | + 915| | /// Execute a prepared statement, with optional arguments. + 916| | template + 917| | [[deprecated("Use exec(prepped, params) instead.")]] + 918| | result exec_prepared(zview statement, Args &&...args) + 919| | { + 920| | return exec(prepped{statement}, params{args...}); + 921| | } + 922| | + 923| | /// Execute a prepared statement taking no parameters. + 924| | result exec(prepped statement) + 925| 0| { + 926| 0| params pp; + 927| 0| return internal_exec_prepared(statement, pp.make_c_params()); + 928| 0| } + 929| | + 930| | /// Execute prepared statement, read full results, iterate rows of data. + 931| | /** Like @ref query(zview), but using a prepared statement. + 932| | * + 933| | * @return Something you can iterate using "range `for`" syntax. The actual + 934| | * type details may change. + 935| | */ + 936| | template + 937| | auto query(prepped statement, params const &parms = {}) + 938| | { + 939| | return exec(statement, parms).iter(); + 940| | } + 941| | + 942| | /// Perform prepared statement returning exactly 1 value. + 943| | /** This is just like @ref query_value(zview), but using a prepared + 944| | * statement. + 945| | */ + 946| | template + 947| | TYPE query_value(prepped statement, params const &parms = {}) + 948| | { + 949| | return exec(statement, parms).expect_columns(1).one_field().as(); + 950| | } + 951| | + 952| | // C++20: Concept like std::invocable, but without specifying param types. + 953| | /// Execute prepared statement, load result, perform `func` for each row. + 954| | /** This is just like @ref for_query(zview), but using a prepared statement. + 955| | */ + 956| | template + 957| | void for_query(prepped statement, CALLABLE &&func, params const &parms = {}) + 958| | { + 959| | exec(statement, parms).for_each(std::forward(func)); + 960| | } + 961| | + 962| | // TODO: stream() with prepped. + 963| | // TODO: stream_like() with prepped. + 964| | + 965| | /// Execute a prepared statement with parameters. + 966| | result exec(prepped statement, params const &parms) + 967| 0| { + 968| 0| return internal_exec_prepared(statement, parms.make_c_params()); + 969| 0| } + 970| | + 971| | /// Execute a prepared statement, and expect a single-row result. + 972| | /** @throw pqxx::unexpected_rows if the result was not exactly 1 row. + 973| | */ + 974| | template + 975| | [[deprecated( + 976| | "Use exec(string_view, params) and call one_row() on the result.")]] + 977| | row exec_prepared1(zview statement, Args &&...args) + 978| | { + 979| | return exec(prepped{statement}, params{args...}).one_row(); + 980| | } + 981| | + 982| | /// Execute a prepared statement, and expect a result with zero rows. + 983| | /** @throw pqxx::unexpected_rows if the result contained rows. + 984| | */ + 985| | template + 986| | [[deprecated( + 987| | "Use exec(prepped, params), and call no_rows() on the result.")]] + 988| | result exec_prepared0(zview statement, Args &&...args) + 989| | { + 990| | return exec(prepped{statement}, params{args...}).no_rows(); + 991| | } + 992| | + 993| | /// Execute a prepared statement, expect a result with given number of rows. + 994| | /** @throw pqxx::unexpected_rows if the result did not contain exactly the + 995| | * given number of rows. + 996| | */ + 997| | template + 998| | [[deprecated( + 999| | "Use exec(prepped, params), and call expect_rows() on the result.")]] + 1000| | result + 1001| | exec_prepared_n(result::size_type rows, zview statement, Args &&...args) + 1002| | { + 1003| | return exec(pqxx::prepped{statement}, params{args...}).expect_rows(rows); + 1004| | } + 1005| | + 1006| | /** + 1007| | * @name Error/warning output + 1008| | */ + 1009| | //@{ + 1010| | /// Have connection process a warning message. + 1011| 0| void process_notice(char const msg[]) const { m_conn.process_notice(msg); } + 1012| | /// Have connection process a warning message. + 1013| 0| void process_notice(zview msg) const { m_conn.process_notice(msg); } + 1014| | //@} + 1015| | + 1016| | /// The connection in which this transaction lives. + 1017| 0| [[nodiscard]] constexpr connection &conn() const noexcept { return m_conn; } + 1018| | + 1019| | /// Set session variable using SQL "SET" command. + 1020| | /** @deprecated To set a transaction-local variable, execute an SQL `SET` + 1021| | * command. To set a session variable, use the connection's + 1022| | * @ref set_session_var function. + 1023| | * + 1024| | * @warning When setting a string value, you must make sure that the string + 1025| | * is "safe." If you call @ref quote() on the string, it will return a + 1026| | * safely escaped and quoted version for use as an SQL literal. + 1027| | * + 1028| | * @warning This function executes SQL. Do not try to set or get variables + 1029| | * while a pipeline or table stream is active. + 1030| | * + 1031| | * @param var The variable to set. + 1032| | * @param value The new value to store in the variable. This can be any SQL + 1033| | * expression. + 1034| | */ + 1035| | [[deprecated("Set transaction-local variables using SQL SET statements.")]] + 1036| | void set_variable(std::string_view var, std::string_view value); + 1037| | + 1038| | /// Read session variable using SQL "SHOW" command. + 1039| | /** @warning This executes SQL. Do not try to set or get variables while a + 1040| | * pipeline or table stream is active. + 1041| | */ + 1042| | [[deprecated("Read variables using SQL SHOW statements.")]] + 1043| | std::string get_variable(std::string_view); + 1044| | + 1045| | // C++20: constexpr. + 1046| | /// Transaction name, if you passed one to the constructor; or empty string. + 1047| 0| [[nodiscard]] std::string_view name() const & noexcept { return m_name; } + 1048| | + 1049| |protected: + 1050| | /// Create a transaction (to be called by implementation classes only). + 1051| | /** The name, if nonempty, must begin with a letter and may contain letters + 1052| | * and digits only. + 1053| | */ + 1054| | transaction_base( + 1055| | connection &cx, std::string_view tname, + 1056| | std::shared_ptr rollback_cmd) : + 1057| | m_conn{cx}, m_name{tname}, m_rollback_cmd{rollback_cmd} + 1058| 0| {} + 1059| | + 1060| | /// Create a transaction (to be called by implementation classes only). + 1061| | /** Its rollback command will be "ROLLBACK". + 1062| | * + 1063| | * The name, if nonempty, must begin with a letter and may contain letters + 1064| | * and digits only. + 1065| | */ + 1066| | transaction_base(connection &cx, std::string_view tname); + 1067| | + 1068| | /// Create a transaction (to be called by implementation classes only). + 1069| | explicit transaction_base(connection &cx); + 1070| | + 1071| | /// Register this transaction with the connection. + 1072| | void register_transaction(); + 1073| | + 1074| | /// End transaction. To be called by implementing class' destructor. + 1075| | void close() noexcept; + 1076| | + 1077| | /// To be implemented by derived implementation class: commit transaction. + 1078| | virtual void do_commit() = 0; + 1079| | + 1080| | /// Transaction type-specific way of aborting a transaction. + 1081| | /** @warning This will become "final", since this function can be called + 1082| | * from the implementing class destructor. + 1083| | */ + 1084| | virtual void do_abort(); + 1085| | + 1086| | /// Set the rollback command. + 1087| | void set_rollback_cmd(std::shared_ptr cmd) + 1088| 0| { + 1089| 0| m_rollback_cmd = cmd; + 1090| 0| } + 1091| | + 1092| | /// Execute query on connection directly. + 1093| | result direct_exec(std::string_view, std::string_view desc = ""sv); + 1094| | result + 1095| | direct_exec(std::shared_ptr, std::string_view desc = ""sv); + 1096| | + 1097| |private: + 1098| | enum class status + 1099| | { + 1100| | active, + 1101| | aborted, + 1102| | committed, + 1103| | in_doubt + 1104| | }; + 1105| | + 1106| | PQXX_PRIVATE void check_pending_error(); + 1107| | + 1108| | result internal_exec_prepared( + 1109| | std::string_view statement, internal::c_params const &args); + 1110| | + 1111| | result + 1112| | internal_exec_params(std::string_view query, internal::c_params const &args); + 1113| | + 1114| | /// Describe this transaction to humans, e.g. "transaction 'foo'". + 1115| | [[nodiscard]] std::string description() const; + 1116| | + 1117| | friend class pqxx::internal::gate::transaction_transaction_focus; + 1118| | PQXX_PRIVATE void register_focus(transaction_focus *); + 1119| | PQXX_PRIVATE void unregister_focus(transaction_focus *) noexcept; + 1120| | PQXX_PRIVATE void register_pending_error(zview) noexcept; + 1121| | PQXX_PRIVATE void register_pending_error(std::string &&) noexcept; + 1122| | + 1123| | /// Like @ref stream(), but takes a tuple rather than a parameter pack. + 1124| | template + 1125| | auto stream_like(std::string_view query, std::tuple const *) + 1126| | { + 1127| | return stream(query); + 1128| | } + 1129| | + 1130| | connection &m_conn; + 1131| | + 1132| | /// Current "focus": a pipeline, a nested transaction, a stream... + 1133| | /** This pointer is used for only one purpose: sanity checks against mistakes + 1134| | * such as opening one while another is still active. + 1135| | */ + 1136| | transaction_focus const *m_focus = nullptr; + 1137| | + 1138| | status m_status = status::active; + 1139| | bool m_registered = false; + 1140| | std::string m_name; + 1141| | std::string m_pending_error; + 1142| | + 1143| | /// SQL command for aborting this type of transaction. + 1144| | std::shared_ptr m_rollback_cmd; + 1145| | + 1146| | static constexpr std::string_view s_type_name{"transaction"sv}; + 1147| |}; + 1148| | + 1149| | + 1150| |// C++20: Can borrowed_range help? + 1151| |/// Forbidden specialisation: underlying buffer immediately goes out of scope. + 1152| |template<> + 1153| |std::string_view transaction_base::query_value( + 1154| | zview query, std::string_view desc) = delete; + 1155| |/// Forbidden specialisation: underlying buffer immediately goes out of scope. + 1156| |template<> + 1157| |zview transaction_base::query_value( + 1158| | zview query, std::string_view desc) = delete; + 1159| | + 1160| |} // namespace pqxx + 1161| | + 1162| | + 1163| |namespace pqxx::internal + 1164| |{ + 1165| |/// The SQL command for starting a given type of transaction. + 1166| |template + 1167| |extern const zview begin_cmd; + 1168| | + 1169| |// These are not static members, so "constexpr" does not imply "inline". + 1170| |template<> + 1171| |inline constexpr zview begin_cmd{ + 1172| | "BEGIN"_zv}; + 1173| |template<> + 1174| |inline constexpr zview begin_cmd{ + 1175| | "BEGIN READ ONLY"_zv}; + 1176| |template<> + 1177| |inline constexpr zview begin_cmd{ + 1178| | "BEGIN ISOLATION LEVEL REPEATABLE READ"_zv}; + 1179| |template<> + 1180| |inline constexpr zview begin_cmd{ + 1181| | "BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY"_zv}; + 1182| |template<> + 1183| |inline constexpr zview begin_cmd{ + 1184| | "BEGIN ISOLATION LEVEL SERIALIZABLE"_zv}; + 1185| |template<> + 1186| |inline constexpr zview begin_cmd{ + 1187| | "BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY"_zv}; + 1188| |} // namespace pqxx::internal + 1189| | + 1190| |#include "pqxx/internal/stream_query_impl.hxx" + 1191| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/transaction_focus.hxx: + 1| |/** Transaction focus: types which monopolise a transaction's attention. + 2| | * + 3| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 4| | * + 5| | * See COPYING for copyright license. If you did not receive a file called + 6| | * COPYING with this source code, please notify the distributor of this + 7| | * mistake, or contact the author. + 8| | */ + 9| |#ifndef PQXX_H_TRANSACTION_FOCUS + 10| |#define PQXX_H_TRANSACTION_FOCUS + 11| | + 12| |#if !defined(PQXX_HEADER_PRE) + 13| |# error "Include libpqxx headers as , not ." + 14| |#endif + 15| | + 16| |#include "pqxx/util.hxx" + 17| | + 18| |namespace pqxx + 19| |{ + 20| |/// Base class for things that monopolise a transaction's attention. + 21| |/** You probably won't need to use this class. But it can be useful to _know_ + 22| | * that a given libpqxx class is derived from it. + 23| | * + 24| | * Pipelines, SQL statements, and data streams are examples of classes derived + 25| | * from `transaction_focus`. In any given transaction, only one object of + 26| | * such a class can be active at any given time. + 27| | */ + 28| |class PQXX_LIBEXPORT transaction_focus + 29| |{ + 30| |public: + 31| | transaction_focus( + 32| | transaction_base &t, std::string_view cname, std::string_view oname) : + 33| | m_trans{&t}, m_classname{cname}, m_name{oname} + 34| 0| {} + 35| | + 36| | transaction_focus( + 37| | transaction_base &t, std::string_view cname, std::string &&oname) : + 38| | m_trans{&t}, m_classname{cname}, m_name{std::move(oname)} + 39| 0| {} + 40| | + 41| | transaction_focus(transaction_base &t, std::string_view cname) : + 42| | m_trans{&t}, m_classname{cname} + 43| 0| {} + 44| | + 45| | transaction_focus() = delete; + 46| | transaction_focus(transaction_focus const &) = delete; + 47| | transaction_focus &operator=(transaction_focus const &) = delete; + 48| | + 49| | /// Class name, for human consumption. + 50| | [[nodiscard]] constexpr std::string_view classname() const noexcept + 51| 0| { + 52| 0| return m_classname; + 53| 0| } + 54| | + 55| | /// Name for this object, if the caller passed one; empty string otherwise. + 56| 0| [[nodiscard]] std::string_view name() const & noexcept { return m_name; } + 57| | + 58| | [[nodiscard]] std::string description() const + 59| 0| { + 60| 0| return pqxx::internal::describe_object(m_classname, m_name); + 61| 0| } + 62| | + 63| | transaction_focus(transaction_focus &&other) : + 64| | m_trans{other.m_trans}, + 65| | m_registered{other.m_registered}, + 66| | m_classname{other.m_classname}, + 67| | // We can't move the name until later. + 68| | m_name{} + 69| 0| { + 70| 0| // This is a bit more complicated than you might expect. The transaction + 71| 0| // has a backpointer to the focus, and we need to transfer that to the new + 72| 0| // focus. + 73| 0| move_name_and_registration(other); + 74| 0| } + 75| | + 76| | transaction_focus &operator=(transaction_focus &&other) + 77| 0| { + 78| 0| if (&other != this) + 79| 0| { + 80| 0| if (m_registered) + 81| 0| unregister_me(); + 82| 0| m_trans = other.m_trans; + 83| 0| m_classname = other.m_classname; + 84| 0| move_name_and_registration(other); + 85| 0| } + 86| 0| return *this; + 87| 0| } + 88| | + 89| |protected: + 90| | void register_me(); + 91| | void unregister_me() noexcept; + 92| | void reg_pending_error(std::string const &) noexcept; + 93| 0| bool registered() const noexcept { return m_registered; } + 94| | + 95| | transaction_base *m_trans; + 96| | + 97| |private: + 98| | bool m_registered = false; + 99| | std::string_view m_classname; + 100| | std::string m_name; + 101| | + 102| | /// Perform part of a move operation. + 103| | void move_name_and_registration(transaction_focus &other) + 104| 0| { + 105| 0| bool const reg{other.m_registered}; + 106| 0| // Unregister the original while it still owns its name. + 107| 0| if (reg) + 108| 0| other.unregister_me(); + 109| 0| // Now! Quick! Steal that name. + 110| 0| m_name = std::move(other.m_name); + 111| 0| // Now that we own the name, register ourselves instead. + 112| 0| if (reg) + 113| 0| this->register_me(); + 114| 0| } + 115| |}; + 116| |} // namespace pqxx + 117| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/util.hxx: + 1| |/* Various utility definitions for libpqxx. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/util instead. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_UTIL + 12| |#define PQXX_H_UTIL + 13| | + 14| |#if !defined(PQXX_HEADER_PRE) + 15| |# error "Include libpqxx headers as , not ." + 16| |#endif + 17| | + 18| |#include + 19| |#include + 20| |#include + 21| |#include + 22| |#include + 23| |#include + 24| |#include + 25| |#include + 26| |#include + 27| |#include + 28| |#include + 29| |#include + 30| |#include + 31| |#include + 32| |#include + 33| |#include + 34| | + 35| |#include "pqxx/except.hxx" + 36| |#include "pqxx/types.hxx" + 37| |#include "pqxx/version.hxx" + 38| | + 39| | + 40| |/// The home of all libpqxx classes, functions, templates, etc. + 41| |namespace pqxx + 42| |{} + 43| | + 44| |#include + 45| | + 46| | + 47| |// C++23: Retire wrapper. + 48| |// PQXX_UNREACHABLE: equivalent to `std::unreachable()` if available. + 49| |#if !defined(__cpp_lib_unreachable) + 50| |# define PQXX_UNREACHABLE while (false) + 51| |#elif !__cpp_lib_unreachable + 52| |# define PQXX_UNREACHABLE while (false) + 53| |#else + 54| |# define PQXX_UNREACHABLE std::unreachable() + 55| |#endif + 56| | + 57| | + 58| |/// Internal items for libpqxx' own use. Do not use these yourself. + 59| |namespace pqxx::internal + 60| |{ + 61| | + 62| |// C++20: Retire wrapper. + 63| |/// Same as `std::cmp_less`, or a workaround where that's not available. + 64| |template + 65| |inline constexpr bool cmp_less(LEFT lhs, RIGHT rhs) noexcept + 66| 0|{ + 67| 0|#if defined(PQXX_HAVE_CMP) + 68| 0| return std::cmp_less(lhs, rhs); + 69| 0|#else + 70| 0| // We need a variable just because lgtm.com gives off a false positive + 71| 0| // warning when we compare the values directly. It considers that a + 72| 0| // "self-comparison." + 73| 0| constexpr bool left_signed{std::is_signed_v}; + 74| 0| if constexpr (left_signed == std::is_signed_v) + 75| 0| return lhs < rhs; + 76| 0| else if constexpr (std::is_signed_v) + 77| 0| return (lhs <= 0) ? true : (std::make_unsigned_t(lhs) < rhs); + 78| 0| else + 79| 0| return (rhs <= 0) ? false : (lhs < std::make_unsigned_t(rhs)); + 80| 0|#endif + 81| 0|} + 82| | + 83| | + 84| |// C++20: Retire wrapper. + 85| |/// C++20 std::cmp_greater, or workaround if not available. + 86| |template + 87| |inline constexpr bool cmp_greater(LEFT lhs, RIGHT rhs) noexcept + 88| 0|{ + 89| 0|#if defined(PQXX_HAVE_CMP) + 90| 0| return std::cmp_greater(lhs, rhs); + 91| 0|#else + 92| 0| return cmp_less(rhs, lhs); + 93| 0|#endif + 94| 0|} + 95| | + 96| | + 97| |// C++20: Retire wrapper. + 98| |/// C++20 std::cmp_less_equal, or workaround if not available. + 99| |template + 100| |inline constexpr bool cmp_less_equal(LEFT lhs, RIGHT rhs) noexcept + 101| 0|{ + 102| 0|#if defined(PQXX_HAVE_CMP) + 103| 0| return std::cmp_less_equal(lhs, rhs); + 104| 0|#else + 105| 0| return not cmp_less(rhs, lhs); + 106| 0|#endif + 107| 0|} + 108| | + 109| | + 110| |// C++20: Retire wrapper. + 111| |/// C++20 std::cmp_greater_equal, or workaround if not available. + 112| |template + 113| |inline constexpr bool cmp_greater_equal(LEFT lhs, RIGHT rhs) noexcept + 114| 0|{ + 115| 0|#if defined(PQXX_HAVE_CMP) + 116| 0| return std::cmp_greater_equal(lhs, rhs); + 117| 0|#else + 118| 0| return not cmp_less(lhs, rhs); + 119| 0|#endif + 120| 0|} + 121| | + 122| | + 123| |/// Efficiently concatenate two strings. + 124| |/** This is a special case of concatenate(), needed because dependency + 125| | * management does not let us use that function here. + 126| | */ + 127| |[[nodiscard]] inline std::string cat2(std::string_view x, std::string_view y) + 128| 0|{ + 129| 0| std::string buf; + 130| 0| auto const xs{std::size(x)}, ys{std::size(y)}; + 131| 0| buf.resize(xs + ys); + 132| 0| x.copy(std::data(buf), xs); + 133| 0| y.copy(std::data(buf) + xs, ys); + 134| 0| return buf; + 135| 0|} + 136| |} // namespace pqxx::internal + 137| | + 138| | + 139| |namespace pqxx + 140| |{ + 141| |using namespace std::literals; + 142| | + 143| |/// Suppress compiler warning about an unused item. + 144| |template inline constexpr void ignore_unused(T &&...) noexcept + 145| 0|{} + ------------------ + | Unexecuted instantiation: _ZN4pqxx13ignore_unusedIJRKiEEEvDpOT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx13ignore_unusedIJRNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEEEEvDpOT_ + ------------------ + 146| | + 147| | + 148| |/// Cast a numeric value to another type, or throw if it underflows/overflows. + 149| |/** Both types must be arithmetic types, and they must either be both integral + 150| | * or both floating-point types. + 151| | */ + 152| |template + 153| |inline TO check_cast(FROM value, std::string_view description) + 154| 0|{ + 155| 0| static_assert(std::is_arithmetic_v); + 156| 0| static_assert(std::is_arithmetic_v); + 157| 0| static_assert(std::is_integral_v == std::is_integral_v); + 158| 0| + 159| 0| // The rest of this code won't quite work for bool, but bool is trivially + 160| 0| // convertible to other arithmetic types as far as I can see. + 161| 0| if constexpr (std::is_same_v) + 162| 0| return static_cast(value); + 163| 0| + 164| 0| // Depending on our "if constexpr" conditions, this parameter may not be + 165| 0| // needed. Some compilers will warn. + 166| 0| ignore_unused(description); + 167| 0| + 168| 0| using from_limits = std::numeric_limits; + 169| 0| using to_limits = std::numeric_limits; + 170| 0| if constexpr (std::is_signed_v) + 171| 0| { + 172| 0| if constexpr (std::is_signed_v) + 173| 0| { + 174| 0| if (value < to_limits::lowest()) + 175| 0| throw range_error{internal::cat2("Cast underflow: "sv, description)}; + 176| 0| } + 177| 0| else + 178| 0| { + 179| 0| // FROM is signed, but TO is not. Treat this as a special case, because + 180| 0| // there may not be a good broader type in which the compiler can even + 181| 0| // perform our check. + 182| 0| if (value < 0) + 183| 0| throw range_error{internal::cat2( + 184| 0| "Casting negative value to unsigned type: "sv, description)}; + 185| 0| } + 186| 0| } + 187| 0| else + 188| 0| { + 189| 0| // No need to check: the value is unsigned so can't fall below the range + 190| 0| // of the TO type. + 191| 0| } + 192| 0| + 193| 0| if constexpr (std::is_integral_v) + 194| 0| { + 195| 0| using unsigned_from = std::make_unsigned_t; + 196| 0| using unsigned_to = std::make_unsigned_t; + 197| 0| constexpr auto from_max{static_cast((from_limits::max)())}; + 198| 0| constexpr auto to_max{static_cast((to_limits::max)())}; + 199| 0| if constexpr (from_max > to_max) + 200| 0| { + 201| 0| if (internal::cmp_greater(value, to_max)) + 202| 0| throw range_error{internal::cat2("Cast overflow: "sv, description)}; + 203| 0| } + 204| 0| } + 205| 0| else if constexpr ((from_limits::max)() > (to_limits::max)()) + 206| 0| { + 207| 0| if (value > (to_limits::max)()) + 208| 0| throw range_error{internal::cat2("Cast overflow: ", description)}; + 209| 0| } + 210| 0| + 211| 0| return static_cast(value); + 212| 0|} + 213| | + 214| | + 215| |/** Check library version at link time. + 216| | * + 217| | * Ensures a failure when linking an application against a radically + 218| | * different libpqxx version than the one against which it was compiled. + 219| | * + 220| | * Sometimes application builds fail in unclear ways because they compile + 221| | * using headers from libpqxx version X, but then link against libpqxx + 222| | * binary version Y. A typical scenario would be one where you're building + 223| | * against a libpqxx which you have built yourself, but a different version + 224| | * is installed on the system. + 225| | * + 226| | * The check_library_version template is declared for any library version, + 227| | * but only actually defined for the version of the libpqxx binary against + 228| | * which the code is linked. + 229| | * + 230| | * If the library binary is a different version than the one declared in + 231| | * these headers, then this call will fail to link: there will be no + 232| | * definition for the function with these exact template parameter values. + 233| | * There will be a definition, but the version in the parameter values will + 234| | * be different. + 235| | */ + 236| |inline PQXX_PRIVATE void check_version() noexcept + 237| 0|{ + 238| | // There is no particular reason to do this here in @ref connection, except + 239| | // to ensure that every meaningful libpqxx client will execute it. The call + 240| | // must be in the execution path somewhere or the compiler won't try to link + 241| | // it. We can't use it to initialise a global or class-static variable, + 242| | // because a smart compiler might resolve it at compile time. + 243| | // + 244| | // On the other hand, we don't want to make a useless function call too + 245| | // often for performance reasons. A local static variable is initialised + 246| | // only on the definition's first execution. Compilers will be well + 247| | // optimised for this behaviour, so there's a minimal one-time cost. + 248| 0| static auto const version_ok{internal::PQXX_VERSION_CHECK()}; + 249| 0| ignore_unused(version_ok); + 250| 0|} + 251| | + 252| | + 253| |/// Descriptor of library's thread-safety model. + 254| |/** This describes what the library knows about various risks to thread-safety. + 255| | */ + 256| |struct PQXX_LIBEXPORT thread_safety_model + 257| |{ + 258| | /// Is the underlying libpq build thread-safe? + 259| | bool safe_libpq = false; + 260| | + 261| | /// Is Kerberos thread-safe? + 262| | /** @warning Is currently always `false`. + 263| | * + 264| | * If your application uses Kerberos, all accesses to libpqxx or Kerberos + 265| | * must be serialized. Confine their use to a single thread, or protect it + 266| | * with a global lock. + 267| | */ + 268| | bool safe_kerberos = false; + 269| | + 270| | /// A human-readable description of any thread-safety issues. + 271| | std::string description; + 272| |}; + 273| | + 274| | + 275| |/// Describe thread safety available in this build. + 276| |[[nodiscard]] PQXX_LIBEXPORT thread_safety_model describe_thread_safety(); + 277| | + 278| | + 279| |#if defined(PQXX_HAVE_CONCEPTS) + 280| |# define PQXX_POTENTIAL_BINARY_ARG pqxx::potential_binary + 281| |#else + 282| |# define PQXX_POTENTIAL_BINARY_ARG typename + 283| |#endif + 284| | + 285| |/// Custom `std::char_trast` if the compiler does not provide one. + 286| |/** Needed if the standard library lacks a generic implementation or a + 287| | * specialisation for std::byte. They aren't strictly required to provide + 288| | * either, and libc++ 19 removed its generic implementation. + 289| | */ + 290| |struct byte_char_traits : std::char_traits + 291| |{ + 292| | using char_type = std::byte; + 293| | + 294| 0| static void assign(std::byte &a, const std::byte &b) noexcept { a = b; } + 295| 0| static bool eq(std::byte a, std::byte b) { return a == b; } + 296| 0| static bool lt(std::byte a, std::byte b) { return a < b; } + 297| | + 298| | static int compare(const std::byte *a, const std::byte *b, std::size_t size) + 299| 0| { + 300| 0| return std::memcmp(a, b, size); + 301| 0| } + 302| | + 303| | /// Deliberately undefined: "guess" the length of an array of bytes. + 304| | /* This is nonsense: we can't determine the length of a random sequence of + 305| | * bytes. There is no terminating zero like there is for C strings. + 306| | * + 307| | * But `std::char_traits` requires us to provide this function, so we + 308| | * declare it without defining it. + 309| | */ + 310| | static size_t length(const std::byte *data); + 311| | + 312| | static const std::byte * + 313| | find(const std::byte *data, std::size_t size, const std::byte &value) + 314| 0| { + 315| 0| return static_cast( + 316| 0| std::memchr(data, static_cast(value), size)); + 317| 0| } + 318| | + 319| | static std::byte * + 320| | move(std::byte *dest, const std::byte *src, std::size_t size) + 321| 0| { + 322| 0| return static_cast(std::memmove(dest, src, size)); + 323| 0| } + 324| | + 325| | static std::byte * + 326| | copy(std::byte *dest, const std::byte *src, std::size_t size) + 327| 0| { + 328| 0| return static_cast(std::memcpy(dest, src, size)); + 329| 0| } + 330| | + 331| | static std::byte *assign(std::byte *dest, std::size_t size, std::byte value) + 332| 0| { + 333| 0| return static_cast( + 334| 0| std::memset(dest, static_cast(value), size)); + 335| 0| } + 336| | + 337| | /// Declared but not defined: makes no sense for binary data. + 338| | static int_type not_eof(int_type value); + 339| | + 340| 0| static std::byte to_char_type(int_type value) { return std::byte(value); } + 341| | + 342| 0| static int_type to_int_type(std::byte value) { return int_type(value); } + 343| | + 344| 0| static bool eq_int_type(int_type a, int_type b) { return a == b; } + 345| | + 346| | /// Declared but not defined: makes no sense for binary data. + 347| | static int_type eof(); + 348| |}; + 349| | + 350| |template + 351| |struct has_generic_char_traits : std::false_type + 352| |{}; + 353| | + 354| |template + 355| |struct has_generic_char_traits< + 356| | TYPE, std::void_t::eof)>> : std::true_type + 357| |{}; + 358| | + 359| |inline constexpr bool has_generic_bytes_char_traits = + 360| | has_generic_char_traits::value; + 361| | + 362| |// Supress warnings from potentially using a deprecated generic + 363| |// std::char_traits. + 364| |// Necessary for libc++ 18. + 365| |#include "pqxx/internal/ignore-deprecated-pre.hxx" + 366| | + 367| |// C++20: Change this type. + 368| |/// Type alias for a container containing bytes. + 369| |/* Required to support standard libraries without a generic implementation for + 370| | * `std::char_traits`. + 371| | * @warn Will change to `std::vector` in the next major release. + 372| | */ + 373| |using bytes = std::conditional< + 374| | has_generic_bytes_char_traits, std::basic_string, + 375| | std::basic_string>::type; + 376| | + 377| |// C++20: Change this type. + 378| |/// Type alias for a view of bytes. + 379| |/* Required to support standard libraries without a generic implementation for + 380| | * `std::char_traits`. + 381| | * @warn Will change to `std::span` in the next major release. + 382| | */ + 383| |using bytes_view = std::conditional< + 384| | has_generic_bytes_char_traits, std::basic_string_view, + 385| | std::basic_string_view>::type; + 386| | + 387| |#include "pqxx/internal/ignore-deprecated-post.hxx" + 388| | + 389| | + 390| |/// Cast binary data to a type that libpqxx will recognise as binary. + 391| |/** There are many different formats for storing binary data in memory. You + 392| | * may have yours as a `std::string`, or a `std::vector`, or one of + 393| | * many other types. + 394| | * + 395| | * But for libpqxx to recognise your data as binary, it needs to be a + 396| | * `pqxx::bytes`, or a `pqxx::bytes_view`; or in C++20 or better, any + 397| | * contiguous block of `std::byte`. + 398| | * + 399| | * Use `binary_cast` as a convenience helper to cast your data as a + 400| | * `pqxx::bytes_view`. + 401| | * + 402| | * @warning There are two things you should be aware of! First, the data must + 403| | * be contiguous in memory. In C++20 the compiler will enforce this, but in + 404| | * C++17 it's your own problem. Second, you must keep the object where you + 405| | * store the actual data alive for as long as you might use this function's + 406| | * return value. + 407| | */ + 408| |template + 409| |bytes_view binary_cast(TYPE const &data) + 410| 0|{ + 411| 0| static_assert(sizeof(value_type) == 1); + 412| 0| // C++20: Use std::as_bytes. + 413| 0| return { + 414| 0| reinterpret_cast( + 415| 0| const_cast const *>( + 416| 0| std::data(data))), + 417| 0| std::size(data)}; + 418| 0|} + 419| | + 420| | + 421| |#if defined(PQXX_HAVE_CONCEPTS) + 422| |template + 423| |concept char_sized = (sizeof(CHAR) == 1); + 424| |# define PQXX_CHAR_SIZED_ARG char_sized + 425| |#else + 426| |# define PQXX_CHAR_SIZED_ARG typename + 427| |#endif + 428| | + 429| |/// Construct a type that libpqxx will recognise as binary. + 430| |/** Takes a data pointer and a size, without being too strict about their + 431| | * types, and constructs a `pqxx::bytes_view` pointing to the same data. + 432| | * + 433| | * This makes it a little easier to turn binary data, in whatever form you + 434| | * happen to have it, into binary data as libpqxx understands it. + 435| | */ + 436| |template + 437| |bytes_view binary_cast(CHAR const *data, SIZE size) + 438| 0|{ + 439| 0| static_assert(sizeof(CHAR) == 1); + 440| 0| return { + 441| 0| reinterpret_cast(data), + 442| 0| check_cast(size, "binary data size")}; + 443| 0|} + 444| | + 445| | + 446| |/// The "null" oid. + 447| |constexpr oid oid_none{0}; + 448| |} // namespace pqxx + 449| | + 450| | + 451| |/// Private namespace for libpqxx's internal use; do not access. + 452| |/** This namespace hides definitions internal to libpqxx. These are not + 453| | * supposed to be used by client programs, and they may change at any time + 454| | * without notice. + 455| | * + 456| | * Conversely, if you find something in this namespace tremendously useful, by + 457| | * all means do lodge a request for its publication. + 458| | * + 459| | * @warning Here be dragons! + 460| | */ + 461| |namespace pqxx::internal + 462| |{ + 463| |using namespace std::literals; + 464| | + 465| | + 466| |/// A safer and more generic replacement for `std::isdigit`. + 467| |/** Turns out `std::isdigit` isn't as easy to use as it sounds. It takes an + 468| | * `int`, but requires it to be nonnegative. Which means it's an outright + 469| | * liability on systems where `char` is signed. + 470| | */ + 471| |template inline constexpr bool is_digit(CHAR c) noexcept + 472| |{ + 473| | return (c >= '0') and (c <= '9'); + 474| |} + 475| | + 476| | + 477| |/// Describe an object for humans, based on class name and optional name. + 478| |/** Interprets an empty name as "no name given." + 479| | */ + 480| |[[nodiscard]] std::string + 481| |describe_object(std::string_view class_name, std::string_view name); + 482| | + 483| | + 484| |/// Check validity of registering a new "guest" in a "host." + 485| |/** The host might be e.g. a connection, and the guest a transaction. The + 486| | * host can only have one guest at a time, so it is an error to register a new + 487| | * guest while the host already has a guest. + 488| | * + 489| | * If the new registration is an error, this function throws a descriptive + 490| | * exception. + 491| | * + 492| | * Pass the old guest (if any) and the new guest (if any), for both, a type + 493| | * name (at least if the guest is not null), and optionally an object name + 494| | * (but which may be omitted if the caller did not assign one). + 495| | */ + 496| |void check_unique_register( + 497| | void const *old_guest, std::string_view old_class, std::string_view old_name, + 498| | void const *new_guest, std::string_view new_class, + 499| | std::string_view new_name); + 500| | + 501| | + 502| |/// Like @ref check_unique_register, but for un-registering a guest. + 503| |/** Pass the guest which was registered, as well as the guest which is being + 504| | * unregistered, so that the function can check that they are the same one. + 505| | */ + 506| |void check_unique_unregister( + 507| | void const *old_guest, std::string_view old_class, std::string_view old_name, + 508| | void const *new_guest, std::string_view new_class, + 509| | std::string_view new_name); + 510| | + 511| | + 512| |/// Compute buffer size needed to escape binary data for use as a BYTEA. + 513| |/** This uses the hex-escaping format. The return value includes room for the + 514| | * "\x" prefix. + 515| | */ + 516| |inline constexpr std::size_t size_esc_bin(std::size_t binary_bytes) noexcept + 517| 0|{ + 518| 0| return 2 + (2 * binary_bytes) + 1; + 519| 0|} + 520| | + 521| | + 522| |/// Compute binary size from the size of its escaped version. + 523| |/** Do not include a terminating zero in `escaped_bytes`. + 524| | */ + 525| |inline constexpr std::size_t size_unesc_bin(std::size_t escaped_bytes) noexcept + 526| 0|{ + 527| 0| return (escaped_bytes - 2) / 2; + 528| 0|} + 529| | + 530| | + 531| |// TODO: Use actual binary type for "data". + 532| |/// Hex-escape binary data into a buffer. + 533| |/** The buffer must be able to accommodate + 534| | * `size_esc_bin(std::size(binary_data))` bytes, and the function will write + 535| | * exactly that number of bytes into the buffer. This includes a trailing + 536| | * zero. + 537| | */ + 538| |void PQXX_LIBEXPORT esc_bin(bytes_view binary_data, char buffer[]) noexcept; + 539| | + 540| | + 541| |/// Hex-escape binary data into a std::string. + 542| |std::string PQXX_LIBEXPORT esc_bin(bytes_view binary_data); + 543| | + 544| | + 545| |/// Reconstitute binary data from its escaped version. + 546| |void PQXX_LIBEXPORT + 547| |unesc_bin(std::string_view escaped_data, std::byte buffer[]); + 548| | + 549| | + 550| |/// Reconstitute binary data from its escaped version. + 551| |bytes PQXX_LIBEXPORT unesc_bin(std::string_view escaped_data); + 552| | + 553| | + 554| |/// Transitional: std::ssize(), or custom implementation if not available. + 555| |template auto ssize(T const &c) + 556| 0|{ + 557| 0|#if defined(PQXX_HAVE_SSIZE) + 558| 0| return std::ssize(c); + 559| 0|#else + 560| 0| using signed_t = std::make_signed_t; + 561| 0| return static_cast(std::size(c)); + 562| 0|#endif // PQXX_HAVE_SSIZe + 563| 0|} + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal5ssizeINSt3__16vectorINS2_7variantIJDnNS_5zviewENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS2_17basic_string_viewISt4byteNS7_ISD_EEEENS6_ISD_SE_NS9_ISD_EEEEEEENS9_ISI_EEEEEEDaRKT_ + ------------------ + | Unexecuted instantiation: _ZN4pqxx8internal5ssizeINS_5zviewEEEDaRKT_ + ------------------ + 564| | + 565| | + 566| |/// Helper for determining a function's parameter types. + 567| |/** This function has no definition. It's not meant to be actually called. + 568| | * It's just there for pattern-matching in the compiler, so we can use its + 569| | * hypothetical return value. + 570| | */ + 571| |template + 572| |std::tuple args_f(RETURN (&func)(ARGS...)); + 573| | + 574| | + 575| |/// Helper for determining a `std::function`'s parameter types. + 576| |/** This function has no definition. It's not meant to be actually called. + 577| | * It's just there for pattern-matching in the compiler, so we can use its + 578| | * hypothetical return value. + 579| | */ + 580| |template + 581| |std::tuple args_f(std::function const &); + 582| | + 583| | + 584| |/// Helper for determining a member function's parameter types. + 585| |/** This function has no definition. It's not meant to be actually called. + 586| | * It's just there for pattern-matching in the compiler, so we can use its + 587| | * hypothetical return value. + 588| | */ + 589| |template + 590| |std::tuple member_args_f(RETURN (CLASS::*)(ARGS...)); + 591| | + 592| | + 593| |/// Helper for determining a const member function's parameter types. + 594| |/** This function has no definition. It's not meant to be actually called. + 595| | * It's just there for pattern-matching in the compiler, so we can use its + 596| | * hypothetical return value. + 597| | */ + 598| |template + 599| |std::tuple member_args_f(RETURN (CLASS::*)(ARGS...) const); + 600| | + 601| | + 602| |/// Helper for determining a callable type's parameter types. + 603| |/** This specialisation should work for lambdas. + 604| | * + 605| | * This function has no definition. It's not meant to be actually called. + 606| | * It's just there for pattern-matching in the compiler, so we can use its + 607| | * hypothetical return value. + 608| | */ + 609| |template + 610| |auto args_f(CALLABLE const &f) + 611| | -> decltype(member_args_f(&CALLABLE::operator())); + 612| | + 613| | + 614| |/// A callable's parameter types, as a tuple. + 615| |template + 616| |using args_t = decltype(args_f(std::declval())); + 617| | + 618| | + 619| |/// Helper: Apply `strip_t` to each of a tuple type's component types. + 620| |/** This function has no definition. It is not meant to be called, only to be + 621| | * used to deduce the right types. + 622| | */ + 623| |template + 624| |std::tuple...> strip_types(std::tuple const &); + 625| | + 626| | + 627| |/// Take a tuple type and apply @ref strip_t to its component types. + 628| |template + 629| |using strip_types_t = decltype(strip_types(std::declval())); + 630| | + 631| | + 632| |/// Return original byte for escaped character. + 633| |inline constexpr char unescape_char(char escaped) noexcept + 634| 0|{ + 635| 0| switch (escaped) + 636| 0| { + 637| 0| case 'b': // Backspace. + 638| 0| PQXX_UNLIKELY return '\b'; + 639| 0| case 'f': // Form feed + 640| 0| PQXX_UNLIKELY return '\f'; + 641| 0| case 'n': // Line feed. + 642| 0| return '\n'; + 643| 0| case 'r': // Carriage return. + 644| 0| return '\r'; + 645| 0| case 't': // Horizontal tab. + 646| 0| return '\t'; + 647| 0| case 'v': // Vertical tab. + 648| 0| return '\v'; + 649| 0| default: break; + 650| 0| } + 651| 0| // Regular character ("self-escaped"). + 652| 0| return escaped; + 653| 0|} + 654| | + 655| | + 656| |// C++20: std::span? + 657| |/// Get error string for a given @c errno value. + 658| |template + 659| |char const *PQXX_COLD + 660| |error_string(int err_num, std::array &buffer) + 661| |{ + 662| | // Not entirely clear whether strerror_s will be in std or global namespace. + 663| | using namespace std; + 664| | + 665| |#if defined(PQXX_HAVE_STERROR_S) || defined(PQXX_HAVE_STRERROR_R) + 666| |# if defined(PQXX_HAVE_STRERROR_S) + 667| | auto const err_result{strerror_s(std::data(buffer), BYTES, err_num)}; + 668| |# else + 669| | auto const err_result{strerror_r(err_num, std::data(buffer), BYTES)}; + 670| |# endif + 671| | if constexpr (std::is_same_v, char *>) + 672| | { + 673| | // GNU version of strerror_r; returns the error string, which may or may + 674| | // not reside within buffer. + 675| | return err_result; + 676| | } + 677| | else + 678| | { + 679| | // Either strerror_s or POSIX strerror_r; returns an error code. + 680| | // Sorry for being lazy here: Not reporting error string for the case + 681| | // where we can't retrieve an error string. + 682| | if (err_result == 0) + 683| | return std::data(buffer); + 684| | else + 685| | return "Compound errors."; + 686| | } + 687| | + 688| |#else + 689| | // Fallback case, hopefully for no actual platforms out there. + 690| | pqxx::ignore_unused(err_num, buffer); + 691| | return "(No error information available.)"; + 692| |#endif + 693| |} + 694| |} // namespace pqxx::internal + 695| | + 696| | + 697| |namespace pqxx::internal::pq + 698| |{ + 699| |/// Wrapper for `PQfreemem()`, with C++ linkage. + 700| |PQXX_LIBEXPORT void pqfreemem(void const *) noexcept; + 701| |} // namespace pqxx::internal::pq + 702| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/version.hxx: + 1| |/* Version info for libpqxx. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/version instead. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#if !defined(PQXX_H_VERSION) + 12| |# define PQXX_H_VERSION + 13| | + 14| |# if !defined(PQXX_HEADER_PRE) + 15| |# error "Include libpqxx headers as , not ." + 16| |# endif + 17| | + 18| |/// Full libpqxx version string. + 19| |# define PQXX_VERSION "7.10.1" + 20| |/// Library ABI version. + 21| |# define PQXX_ABI "7.10" + 22| | + 23| |/// Major version number. + 24| |# define PQXX_VERSION_MAJOR 7 + 25| |/// Minor version number. + 26| |# define PQXX_VERSION_MINOR 10 + 27| | + 28| 0|# define PQXX_VERSION_CHECK check_pqxx_version_7_10 + 29| | + 30| |namespace pqxx::internal + 31| |{ + 32| |/// Library version check stub. + 33| |/** Helps detect version mismatches between libpqxx headers and the libpqxx + 34| | * library binary. + 35| | * + 36| | * Sometimes users run into trouble linking their code against libpqxx because + 37| | * they build their own libpqxx, but the system also has a different version + 38| | * installed. The declarations in the headers against which they compile their + 39| | * code will differ from the ones used to build the libpqxx version they're + 40| | * using, leading to confusing link errors. The solution is to generate a link + 41| | * error when the libpqxx binary is not the same version as the libpqxx headers + 42| | * used to compile the code. + 43| | * + 44| | * This function's definition is in the libpqxx binary, so it's based on the + 45| | * version as found in the binary. The headers contain a call to the function, + 46| | * whose name contains the libpqxx version as found in the headers. (The + 47| | * library build process will use its own local headers even if another version + 48| | * of the headers is installed on the system.) + 49| | * + 50| | * If the libpqxx binary was compiled for a different version than the user's + 51| | * code, linking will fail with an error: `check_pqxx_version_*_*` will not + 52| | * exist for the given version number. + 53| | */ + 54| |PQXX_LIBEXPORT int PQXX_VERSION_CHECK() noexcept; + 55| |} // namespace pqxx::internal + 56| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/libpqxx/include/pqxx/zview.hxx: + 1| |/* Zero-terminated string view. + 2| | * + 3| | * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/zview instead. + 4| | * + 5| | * Copyright (c) 2000-2024, Jeroen T. Vermeulen. + 6| | * + 7| | * See COPYING for copyright license. If you did not receive a file called + 8| | * COPYING with this source code, please notify the distributor of this + 9| | * mistake, or contact the author. + 10| | */ + 11| |#ifndef PQXX_H_ZVIEW + 12| |#define PQXX_H_ZVIEW + 13| | + 14| |#include + 15| |#include + 16| |#include + 17| | + 18| |#include "pqxx/types.hxx" + 19| | + 20| | + 21| |namespace pqxx + 22| |{ + 23| |/// Marker-type wrapper: zero-terminated `std::string_view`. + 24| |/** @warning Use this only if the underlying string is zero-terminated. + 25| | * + 26| | * When you construct a zview, you are promising that if the data pointer is + 27| | * non-null, the underlying string is zero-terminated. It otherwise behaves + 28| | * exactly like a std::string_view. + 29| | * + 30| | * The terminating zero is not "in" the string, so it does not count as part of + 31| | * the view's length. + 32| | * + 33| | * The added guarantee lets the view be used as a C-style string, which often + 34| | * matters since libpqxx builds on top of a C library. For this reason, zview + 35| | * also adds a @ref c_str method. + 36| | */ + 37| |class zview : public std::string_view + 38| |{ + 39| |public: + 40| | constexpr zview() noexcept = default; + 41| | + 42| | /// Convenience overload: construct using pointer and signed length. + 43| | constexpr zview(char const text[], std::ptrdiff_t len) noexcept( + 44| | noexcept(std::string_view{text, static_cast(len)})) : + 45| | std::string_view{text, static_cast(len)} + 46| 0| {} + 47| | + 48| | /// Convenience overload: construct using pointer and signed length. + 49| | constexpr zview(char text[], std::ptrdiff_t len) noexcept( + 50| | noexcept(std::string_view{text, static_cast(len)})) : + 51| | std::string_view{text, static_cast(len)} + 52| 0| {} + 53| | + 54| | /// Explicitly promote a `string_view` to a `zview`. + 55| | explicit constexpr zview(std::string_view other) noexcept : + 56| | std::string_view{other} + 57| 0| {} + 58| | + 59| | /// Construct from any initialiser you might use for `std::string_view`. + 60| | /** @warning Only do this if you are sure that the string is zero-terminated. + 61| | */ + 62| | template + 63| | explicit constexpr zview(Args &&...args) : + 64| | std::string_view(std::forward(args)...) + 65| | {} + 66| | + 67| | // C++20: constexpr. + 68| | /// @warning There's an implicit conversion from `std::string`. + 69| | zview(std::string const &str) noexcept : + 70| | std::string_view{str.c_str(), str.size()} + 71| 0| {} + 72| | + 73| | /// Construct a `zview` from a C-style string. + 74| | /** @warning This scans the string to discover its length. So if you need to + 75| | * do it many times, it's probably better to create the `zview` once and + 76| | * re-use it. + 77| | */ + 78| | constexpr zview(char const str[]) noexcept(noexcept(std::string_view{str})) : + 79| | std::string_view{str} + 80| 0| {} + 81| | + 82| | /// Construct a `zview` from a string literal. + 83| | /** A C++ string literal ("foo") normally looks a lot like a pointer to + 84| | * char const, but that's not really true. It's actually an array of char, + 85| | * which _devolves_ to a pointer when you pass it. + 86| | * + 87| | * For the purpose of creating a `zview` there is one big difference: if we + 88| | * know the array's size, we don't need to scan through the string in order + 89| | * to find out its length. + 90| | */ + 91| | template + 92| | constexpr zview(char const (&literal)[size]) : zview(literal, size - 1) + 93| | {} + 94| | + 95| | /// Either a null pointer, or a zero-terminated text buffer. + 96| | [[nodiscard]] constexpr char const *c_str() const & noexcept + 97| 0| { + 98| 0| return data(); + 99| 0| } + 100| |}; + 101| | + 102| | + 103| |/// Support @ref zview literals. + 104| |/** You can "import" this selectively into your namespace, without pulling in + 105| | * all of the @ref pqxx namespace: + 106| | * + 107| | * ```cxx + 108| | * using pqxx::operator"" _zv; + 109| | * ``` + 110| | */ + 111| |constexpr zview operator"" _zv(char const str[], std::size_t len) noexcept + 112| 0|{ + 113| 0| return zview{str, len}; + 114| 0|} + 115| |} // namespace pqxx + 116| | + 117| | + 118| |#if defined(PQXX_HAVE_CONCEPTS) + 119| |/// A zview is a view. + 120| |template<> inline constexpr bool std::ranges::enable_view{true}; + 121| | + 122| | + 123| |/// A zview is a borrowed range. + 124| |template<> + 125| |inline constexpr bool std::ranges::enable_borrowed_range{true}; + 126| | + 127| |namespace pqxx::internal + 128| |{ + 129| |/// Concept: T is a known zero-terminated string type. + 130| |/** There's no unified API for these string types. It's just a check for some + 131| | * known types. Any code that makes use of the concept will still have to + 132| | * support each of these individually. + 133| | */ + 134| |template + 135| |concept ZString = std::is_convertible_v, char const *> or + 136| | std::is_convertible_v, zview> or + 137| | std::is_convertible_v; + 138| |} // namespace pqxx::internal + 139| |#endif // PQXX_HAVE_CONCEPTS + 140| | + 141| | + 142| |namespace pqxx::internal + 143| |{ + 144| |/// Get a raw C string pointer. + 145| |inline constexpr char const *as_c_string(char const str[]) noexcept + 146| 0|{ + 147| 0| return str; + 148| 0|} + 149| |/// Get a raw C string pointer. + 150| |template + 151| |inline constexpr char const *as_c_string(char (&str)[N]) noexcept + 152| |{ + 153| | return str; + 154| |} + 155| |/// Get a raw C string pointer. + 156| |inline constexpr char const *as_c_string(pqxx::zview str) noexcept + 157| 0|{ + 158| 0| return str.c_str(); + 159| 0|} + 160| |// C++20: Make this constexpr. + 161| |/// Get a raw C string pointer. + 162| |inline char const *as_c_string(std::string const &str) noexcept + 163| 0|{ + 164| 0| return str.c_str(); + 165| 0|} + 166| |} // namespace pqxx::internal + 167| |#endif + +/Users/ryan/dev/cpp/backtesting-cpp/external/nlohmann/json.hpp: + 1| |// __ _____ _____ _____ + 2| |// __| | __| | | | JSON for Modern C++ + 3| |// | | |__ | | | | | | version 3.11.3 + 4| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 5| |// + 6| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 7| |// SPDX-License-Identifier: MIT + 8| | + 9| |/****************************************************************************\ + 10| | * Note on documentation: The source files contain links to the online * + 11| | * documentation of the public API at https://json.nlohmann.me. This URL * + 12| | * contains the most recent documentation and should also be applicable to * + 13| | * previous versions; documentation for deprecated functions is not * + 14| | * removed, but marked deprecated. See "Generate documentation" section in * + 15| | * file docs/README.md. * + 16| |\****************************************************************************/ + 17| | + 18| |#ifndef INCLUDE_NLOHMANN_JSON_HPP_ + 19| |#define INCLUDE_NLOHMANN_JSON_HPP_ + 20| | + 21| |#include // all_of, find, for_each + 22| |#include // nullptr_t, ptrdiff_t, size_t + 23| |#include // hash, less + 24| |#include // initializer_list + 25| |#ifndef JSON_NO_IO + 26| | #include // istream, ostream + 27| |#endif // JSON_NO_IO + 28| |#include // random_access_iterator_tag + 29| |#include // unique_ptr + 30| |#include // string, stoi, to_string + 31| |#include // declval, forward, move, pair, swap + 32| |#include // vector + 33| | + 34| |// #include + 35| |// __ _____ _____ _____ + 36| |// __| | __| | | | JSON for Modern C++ + 37| |// | | |__ | | | | | | version 3.11.3 + 38| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 39| |// + 40| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 41| |// SPDX-License-Identifier: MIT + 42| | + 43| | + 44| | + 45| |#include + 46| | + 47| |// #include + 48| |// __ _____ _____ _____ + 49| |// __| | __| | | | JSON for Modern C++ + 50| |// | | |__ | | | | | | version 3.11.3 + 51| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 52| |// + 53| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 54| |// SPDX-License-Identifier: MIT + 55| | + 56| | + 57| | + 58| |// This file contains all macro definitions affecting or depending on the ABI + 59| | + 60| |#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + 61| | #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + 62| | #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + 63| | #warning "Already included a different version of the library!" + 64| | #endif + 65| | #endif + 66| |#endif + 67| | + 68| |#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) + 69| |#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) + 70| |#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) + 71| | + 72| |#ifndef JSON_DIAGNOSTICS + 73| | #define JSON_DIAGNOSTICS 0 + 74| |#endif + 75| | + 76| |#ifndef JSON_DIAGNOSTIC_POSITIONS + 77| | #define JSON_DIAGNOSTIC_POSITIONS 0 + 78| |#endif + 79| | + 80| |#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + 81| | #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 + 82| |#endif + 83| | + 84| |#if JSON_DIAGNOSTICS + 85| | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag + 86| |#else + 87| | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS + 88| |#endif + 89| | + 90| |#if JSON_DIAGNOSTIC_POSITIONS + 91| | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp + 92| |#else + 93| | #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS + 94| |#endif + 95| | + 96| |#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + 97| | #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp + 98| |#else + 99| | #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON + 100| |#endif + 101| | + 102| |#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + 103| | #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 + 104| |#endif + 105| | + 106| |// Construct the namespace ABI tags component + 107| |#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c + 108| |#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \ + 109| | NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) + 110| | + 111| |#define NLOHMANN_JSON_ABI_TAGS \ + 112| | NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + 113| | NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + 114| | NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \ + 115| | NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS) + 116| | + 117| |// Construct the namespace version component + 118| |#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + 119| | _v ## major ## _ ## minor ## _ ## patch + 120| |#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + 121| | NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + 122| | + 123| |#if NLOHMANN_JSON_NAMESPACE_NO_VERSION + 124| |#define NLOHMANN_JSON_NAMESPACE_VERSION + 125| |#else + 126| |#define NLOHMANN_JSON_NAMESPACE_VERSION \ + 127| | NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + 128| | NLOHMANN_JSON_VERSION_MINOR, \ + 129| | NLOHMANN_JSON_VERSION_PATCH) + 130| |#endif + 131| | + 132| |// Combine namespace components + 133| |#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b + 134| |#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + 135| | NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + 136| | + 137| |#ifndef NLOHMANN_JSON_NAMESPACE + 138| |#define NLOHMANN_JSON_NAMESPACE \ + 139| | nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + 140| | NLOHMANN_JSON_ABI_TAGS, \ + 141| | NLOHMANN_JSON_NAMESPACE_VERSION) + 142| |#endif + 143| | + 144| |#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN + 145| |#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + 146| | namespace nlohmann \ + 147| | { \ + 148| | inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + 149| | NLOHMANN_JSON_ABI_TAGS, \ + 150| | NLOHMANN_JSON_NAMESPACE_VERSION) \ + 151| | { + 152| |#endif + 153| | + 154| |#ifndef NLOHMANN_JSON_NAMESPACE_END + 155| |#define NLOHMANN_JSON_NAMESPACE_END \ + 156| | } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + 157| | } // namespace nlohmann + 158| |#endif + 159| | + 160| |// #include + 161| |// __ _____ _____ _____ + 162| |// __| | __| | | | JSON for Modern C++ + 163| |// | | |__ | | | | | | version 3.11.3 + 164| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 165| |// + 166| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 167| |// SPDX-License-Identifier: MIT + 168| | + 169| | + 170| | + 171| |#include // transform + 172| |#include // array + 173| |#include // forward_list + 174| |#include // inserter, front_inserter, end + 175| |#include // map + 176| |#ifdef JSON_HAS_CPP_17 + 177| | #include // optional + 178| |#endif + 179| |#include // string + 180| |#include // tuple, make_tuple + 181| |#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible + 182| |#include // unordered_map + 183| |#include // pair, declval + 184| |#include // valarray + 185| | + 186| |// #include + 187| |// __ _____ _____ _____ + 188| |// __| | __| | | | JSON for Modern C++ + 189| |// | | |__ | | | | | | version 3.11.3 + 190| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 191| |// + 192| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 193| |// SPDX-License-Identifier: MIT + 194| | + 195| | + 196| | + 197| |#include // nullptr_t + 198| |#include // exception + 199| |#if JSON_DIAGNOSTICS + 200| | #include // accumulate + 201| |#endif + 202| |#include // runtime_error + 203| |#include // to_string + 204| |#include // vector + 205| | + 206| |// #include + 207| |// __ _____ _____ _____ + 208| |// __| | __| | | | JSON for Modern C++ + 209| |// | | |__ | | | | | | version 3.11.3 + 210| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 211| |// + 212| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 213| |// SPDX-License-Identifier: MIT + 214| | + 215| | + 216| | + 217| |#include // array + 218| |#include // size_t + 219| |#include // uint8_t + 220| |#include // string + 221| | + 222| |// #include + 223| |// __ _____ _____ _____ + 224| |// __| | __| | | | JSON for Modern C++ + 225| |// | | |__ | | | | | | version 3.11.3 + 226| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 227| |// + 228| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 229| |// SPDX-License-Identifier: MIT + 230| | + 231| | + 232| | + 233| |#include // declval, pair + 234| |// #include + 235| |// __ _____ _____ _____ + 236| |// __| | __| | | | JSON for Modern C++ + 237| |// | | |__ | | | | | | version 3.11.3 + 238| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 239| |// + 240| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 241| |// SPDX-License-Identifier: MIT + 242| | + 243| | + 244| | + 245| |#include + 246| | + 247| |// #include + 248| |// __ _____ _____ _____ + 249| |// __| | __| | | | JSON for Modern C++ + 250| |// | | |__ | | | | | | version 3.11.3 + 251| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 252| |// + 253| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 254| |// SPDX-License-Identifier: MIT + 255| | + 256| | + 257| | + 258| |// #include + 259| | + 260| | + 261| |NLOHMANN_JSON_NAMESPACE_BEGIN + 262| |namespace detail + 263| |{ + 264| | + 265| |template struct make_void + 266| |{ + 267| | using type = void; + 268| |}; + 269| |template using void_t = typename make_void::type; + 270| | + 271| |} // namespace detail + 272| |NLOHMANN_JSON_NAMESPACE_END + 273| | + 274| | + 275| |NLOHMANN_JSON_NAMESPACE_BEGIN + 276| |namespace detail + 277| |{ + 278| | + 279| |// https://en.cppreference.com/w/cpp/experimental/is_detected + 280| |struct nonesuch + 281| |{ + 282| | nonesuch() = delete; + 283| | ~nonesuch() = delete; + 284| | nonesuch(nonesuch const&) = delete; + 285| | nonesuch(nonesuch const&&) = delete; + 286| | void operator=(nonesuch const&) = delete; + 287| | void operator=(nonesuch&&) = delete; + 288| |}; + 289| | + 290| |template class Op, + 293| | class... Args> + 294| |struct detector + 295| |{ + 296| | using value_t = std::false_type; + 297| | using type = Default; + 298| |}; + 299| | + 300| |template class Op, class... Args> + 301| |struct detector>, Op, Args...> + 302| |{ + 303| | using value_t = std::true_type; + 304| | using type = Op; + 305| |}; + 306| | + 307| |template class Op, class... Args> + 308| |using is_detected = typename detector::value_t; + 309| | + 310| |template class Op, class... Args> + 311| |struct is_detected_lazy : is_detected { }; + 312| | + 313| |template class Op, class... Args> + 314| |using detected_t = typename detector::type; + 315| | + 316| |template class Op, class... Args> + 317| |using detected_or = detector; + 318| | + 319| |template class Op, class... Args> + 320| |using detected_or_t = typename detected_or::type; + 321| | + 322| |template class Op, class... Args> + 323| |using is_detected_exact = std::is_same>; + 324| | + 325| |template class Op, class... Args> + 326| |using is_detected_convertible = + 327| | std::is_convertible, To>; + 328| | + 329| |} // namespace detail + 330| |NLOHMANN_JSON_NAMESPACE_END + 331| | + 332| |// #include + 333| | + 334| | + 335| |// __ _____ _____ _____ + 336| |// __| | __| | | | JSON for Modern C++ + 337| |// | | |__ | | | | | | version 3.11.3 + 338| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 339| |// + 340| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 341| |// SPDX-FileCopyrightText: 2016 - 2021 Evan Nemerson + 342| |// SPDX-License-Identifier: MIT + 343| | + 344| |/* Hedley - https://nemequ.github.io/hedley + 345| | * Created by Evan Nemerson + 346| | */ + 347| | + 348| |#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) + 349| |#if defined(JSON_HEDLEY_VERSION) + 350| | #undef JSON_HEDLEY_VERSION + 351| |#endif + 352| |#define JSON_HEDLEY_VERSION 15 + 353| | + 354| |#if defined(JSON_HEDLEY_STRINGIFY_EX) + 355| | #undef JSON_HEDLEY_STRINGIFY_EX + 356| |#endif + 357| |#define JSON_HEDLEY_STRINGIFY_EX(x) #x + 358| | + 359| |#if defined(JSON_HEDLEY_STRINGIFY) + 360| | #undef JSON_HEDLEY_STRINGIFY + 361| |#endif + 362| |#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + 363| | + 364| |#if defined(JSON_HEDLEY_CONCAT_EX) + 365| | #undef JSON_HEDLEY_CONCAT_EX + 366| |#endif + 367| |#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + 368| | + 369| |#if defined(JSON_HEDLEY_CONCAT) + 370| | #undef JSON_HEDLEY_CONCAT + 371| |#endif + 372| |#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + 373| | + 374| |#if defined(JSON_HEDLEY_CONCAT3_EX) + 375| | #undef JSON_HEDLEY_CONCAT3_EX + 376| |#endif + 377| |#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + 378| | + 379| |#if defined(JSON_HEDLEY_CONCAT3) + 380| | #undef JSON_HEDLEY_CONCAT3 + 381| |#endif + 382| |#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + 383| | + 384| |#if defined(JSON_HEDLEY_VERSION_ENCODE) + 385| | #undef JSON_HEDLEY_VERSION_ENCODE + 386| |#endif + 387| |#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + 388| | + 389| |#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + 390| | #undef JSON_HEDLEY_VERSION_DECODE_MAJOR + 391| |#endif + 392| |#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + 393| | + 394| |#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + 395| | #undef JSON_HEDLEY_VERSION_DECODE_MINOR + 396| |#endif + 397| |#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + 398| | + 399| |#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + 400| | #undef JSON_HEDLEY_VERSION_DECODE_REVISION + 401| |#endif + 402| |#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + 403| | + 404| |#if defined(JSON_HEDLEY_GNUC_VERSION) + 405| | #undef JSON_HEDLEY_GNUC_VERSION + 406| |#endif + 407| |#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + 408| | #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) + 409| |#elif defined(__GNUC__) + 410| | #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) + 411| |#endif + 412| | + 413| |#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + 414| | #undef JSON_HEDLEY_GNUC_VERSION_CHECK + 415| |#endif + 416| |#if defined(JSON_HEDLEY_GNUC_VERSION) + 417| | #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 418| |#else + 419| | #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) + 420| |#endif + 421| | + 422| |#if defined(JSON_HEDLEY_MSVC_VERSION) + 423| | #undef JSON_HEDLEY_MSVC_VERSION + 424| |#endif + 425| |#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) + 426| | #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) + 427| |#elif defined(_MSC_FULL_VER) && !defined(__ICL) + 428| | #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) + 429| |#elif defined(_MSC_VER) && !defined(__ICL) + 430| | #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) + 431| |#endif + 432| | + 433| |#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + 434| | #undef JSON_HEDLEY_MSVC_VERSION_CHECK + 435| |#endif + 436| |#if !defined(JSON_HEDLEY_MSVC_VERSION) + 437| | #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) + 438| |#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + 439| | #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) + 440| |#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + 441| | #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) + 442| |#else + 443| | #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) + 444| |#endif + 445| | + 446| |#if defined(JSON_HEDLEY_INTEL_VERSION) + 447| | #undef JSON_HEDLEY_INTEL_VERSION + 448| |#endif + 449| |#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) + 450| | #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) + 451| |#elif defined(__INTEL_COMPILER) && !defined(__ICL) + 452| | #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) + 453| |#endif + 454| | + 455| |#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + 456| | #undef JSON_HEDLEY_INTEL_VERSION_CHECK + 457| |#endif + 458| |#if defined(JSON_HEDLEY_INTEL_VERSION) + 459| | #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 460| |#else + 461| | #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) + 462| |#endif + 463| | + 464| |#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + 465| | #undef JSON_HEDLEY_INTEL_CL_VERSION + 466| |#endif + 467| |#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + 468| | #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) + 469| |#endif + 470| | + 471| |#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + 472| | #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK + 473| |#endif + 474| |#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + 475| | #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 476| |#else + 477| | #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) + 478| |#endif + 479| | + 480| |#if defined(JSON_HEDLEY_PGI_VERSION) + 481| | #undef JSON_HEDLEY_PGI_VERSION + 482| |#endif + 483| |#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + 484| | #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) + 485| |#endif + 486| | + 487| |#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + 488| | #undef JSON_HEDLEY_PGI_VERSION_CHECK + 489| |#endif + 490| |#if defined(JSON_HEDLEY_PGI_VERSION) + 491| | #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 492| |#else + 493| | #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) + 494| |#endif + 495| | + 496| |#if defined(JSON_HEDLEY_SUNPRO_VERSION) + 497| | #undef JSON_HEDLEY_SUNPRO_VERSION + 498| |#endif + 499| |#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + 500| | #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) + 501| |#elif defined(__SUNPRO_C) + 502| | #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) + 503| |#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + 504| | #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) + 505| |#elif defined(__SUNPRO_CC) + 506| | #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) + 507| |#endif + 508| | + 509| |#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + 510| | #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK + 511| |#endif + 512| |#if defined(JSON_HEDLEY_SUNPRO_VERSION) + 513| | #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 514| |#else + 515| | #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) + 516| |#endif + 517| | + 518| |#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + 519| | #undef JSON_HEDLEY_EMSCRIPTEN_VERSION + 520| |#endif + 521| |#if defined(__EMSCRIPTEN__) + 522| | #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) + 523| |#endif + 524| | + 525| |#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + 526| | #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK + 527| |#endif + 528| |#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + 529| | #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 530| |#else + 531| | #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) + 532| |#endif + 533| | + 534| |#if defined(JSON_HEDLEY_ARM_VERSION) + 535| | #undef JSON_HEDLEY_ARM_VERSION + 536| |#endif + 537| |#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + 538| | #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) + 539| |#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + 540| | #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) + 541| |#endif + 542| | + 543| |#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + 544| | #undef JSON_HEDLEY_ARM_VERSION_CHECK + 545| |#endif + 546| |#if defined(JSON_HEDLEY_ARM_VERSION) + 547| | #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 548| |#else + 549| | #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) + 550| |#endif + 551| | + 552| |#if defined(JSON_HEDLEY_IBM_VERSION) + 553| | #undef JSON_HEDLEY_IBM_VERSION + 554| |#endif + 555| |#if defined(__ibmxl__) + 556| | #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) + 557| |#elif defined(__xlC__) && defined(__xlC_ver__) + 558| | #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) + 559| |#elif defined(__xlC__) + 560| | #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) + 561| |#endif + 562| | + 563| |#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + 564| | #undef JSON_HEDLEY_IBM_VERSION_CHECK + 565| |#endif + 566| |#if defined(JSON_HEDLEY_IBM_VERSION) + 567| | #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 568| |#else + 569| | #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) + 570| |#endif + 571| | + 572| |#if defined(JSON_HEDLEY_TI_VERSION) + 573| | #undef JSON_HEDLEY_TI_VERSION + 574| |#endif + 575| |#if \ + 576| | defined(__TI_COMPILER_VERSION__) && \ + 577| | ( \ + 578| | defined(__TMS470__) || defined(__TI_ARM__) || \ + 579| | defined(__MSP430__) || \ + 580| | defined(__TMS320C2000__) \ + 581| | ) + 582| |#if (__TI_COMPILER_VERSION__ >= 16000000) + 583| | #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) + 584| |#endif + 585| |#endif + 586| | + 587| |#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + 588| | #undef JSON_HEDLEY_TI_VERSION_CHECK + 589| |#endif + 590| |#if defined(JSON_HEDLEY_TI_VERSION) + 591| | #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 592| |#else + 593| | #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) + 594| |#endif + 595| | + 596| |#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + 597| | #undef JSON_HEDLEY_TI_CL2000_VERSION + 598| |#endif + 599| |#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + 600| | #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) + 601| |#endif + 602| | + 603| |#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + 604| | #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK + 605| |#endif + 606| |#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + 607| | #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 608| |#else + 609| | #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) + 610| |#endif + 611| | + 612| |#if defined(JSON_HEDLEY_TI_CL430_VERSION) + 613| | #undef JSON_HEDLEY_TI_CL430_VERSION + 614| |#endif + 615| |#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + 616| | #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) + 617| |#endif + 618| | + 619| |#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + 620| | #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK + 621| |#endif + 622| |#if defined(JSON_HEDLEY_TI_CL430_VERSION) + 623| | #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 624| |#else + 625| | #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) + 626| |#endif + 627| | + 628| |#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + 629| | #undef JSON_HEDLEY_TI_ARMCL_VERSION + 630| |#endif + 631| |#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + 632| | #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) + 633| |#endif + 634| | + 635| |#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + 636| | #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK + 637| |#endif + 638| |#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + 639| | #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 640| |#else + 641| | #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) + 642| |#endif + 643| | + 644| |#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + 645| | #undef JSON_HEDLEY_TI_CL6X_VERSION + 646| |#endif + 647| |#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + 648| | #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) + 649| |#endif + 650| | + 651| |#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + 652| | #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK + 653| |#endif + 654| |#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + 655| | #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 656| |#else + 657| | #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) + 658| |#endif + 659| | + 660| |#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + 661| | #undef JSON_HEDLEY_TI_CL7X_VERSION + 662| |#endif + 663| |#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + 664| | #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) + 665| |#endif + 666| | + 667| |#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + 668| | #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK + 669| |#endif + 670| |#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + 671| | #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 672| |#else + 673| | #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) + 674| |#endif + 675| | + 676| |#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + 677| | #undef JSON_HEDLEY_TI_CLPRU_VERSION + 678| |#endif + 679| |#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + 680| | #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) + 681| |#endif + 682| | + 683| |#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + 684| | #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK + 685| |#endif + 686| |#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + 687| | #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 688| |#else + 689| | #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) + 690| |#endif + 691| | + 692| |#if defined(JSON_HEDLEY_CRAY_VERSION) + 693| | #undef JSON_HEDLEY_CRAY_VERSION + 694| |#endif + 695| |#if defined(_CRAYC) + 696| | #if defined(_RELEASE_PATCHLEVEL) + 697| | #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + 698| | #else + 699| | #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + 700| | #endif + 701| |#endif + 702| | + 703| |#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + 704| | #undef JSON_HEDLEY_CRAY_VERSION_CHECK + 705| |#endif + 706| |#if defined(JSON_HEDLEY_CRAY_VERSION) + 707| | #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 708| |#else + 709| | #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) + 710| |#endif + 711| | + 712| |#if defined(JSON_HEDLEY_IAR_VERSION) + 713| | #undef JSON_HEDLEY_IAR_VERSION + 714| |#endif + 715| |#if defined(__IAR_SYSTEMS_ICC__) + 716| | #if __VER__ > 1000 + 717| | #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + 718| | #else + 719| | #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) + 720| | #endif + 721| |#endif + 722| | + 723| |#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + 724| | #undef JSON_HEDLEY_IAR_VERSION_CHECK + 725| |#endif + 726| |#if defined(JSON_HEDLEY_IAR_VERSION) + 727| | #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 728| |#else + 729| | #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) + 730| |#endif + 731| | + 732| |#if defined(JSON_HEDLEY_TINYC_VERSION) + 733| | #undef JSON_HEDLEY_TINYC_VERSION + 734| |#endif + 735| |#if defined(__TINYC__) + 736| | #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) + 737| |#endif + 738| | + 739| |#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + 740| | #undef JSON_HEDLEY_TINYC_VERSION_CHECK + 741| |#endif + 742| |#if defined(JSON_HEDLEY_TINYC_VERSION) + 743| | #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 744| |#else + 745| | #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) + 746| |#endif + 747| | + 748| |#if defined(JSON_HEDLEY_DMC_VERSION) + 749| | #undef JSON_HEDLEY_DMC_VERSION + 750| |#endif + 751| |#if defined(__DMC__) + 752| | #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) + 753| |#endif + 754| | + 755| |#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + 756| | #undef JSON_HEDLEY_DMC_VERSION_CHECK + 757| |#endif + 758| |#if defined(JSON_HEDLEY_DMC_VERSION) + 759| | #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 760| |#else + 761| | #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) + 762| |#endif + 763| | + 764| |#if defined(JSON_HEDLEY_COMPCERT_VERSION) + 765| | #undef JSON_HEDLEY_COMPCERT_VERSION + 766| |#endif + 767| |#if defined(__COMPCERT_VERSION__) + 768| | #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) + 769| |#endif + 770| | + 771| |#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + 772| | #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK + 773| |#endif + 774| |#if defined(JSON_HEDLEY_COMPCERT_VERSION) + 775| | #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 776| |#else + 777| | #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) + 778| |#endif + 779| | + 780| |#if defined(JSON_HEDLEY_PELLES_VERSION) + 781| | #undef JSON_HEDLEY_PELLES_VERSION + 782| |#endif + 783| |#if defined(__POCC__) + 784| | #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) + 785| |#endif + 786| | + 787| |#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + 788| | #undef JSON_HEDLEY_PELLES_VERSION_CHECK + 789| |#endif + 790| |#if defined(JSON_HEDLEY_PELLES_VERSION) + 791| | #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 792| |#else + 793| | #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) + 794| |#endif + 795| | + 796| |#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + 797| | #undef JSON_HEDLEY_MCST_LCC_VERSION + 798| |#endif + 799| |#if defined(__LCC__) && defined(__LCC_MINOR__) + 800| | #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) + 801| |#endif + 802| | + 803| |#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + 804| | #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK + 805| |#endif + 806| |#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + 807| | #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 808| |#else + 809| | #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) + 810| |#endif + 811| | + 812| |#if defined(JSON_HEDLEY_GCC_VERSION) + 813| | #undef JSON_HEDLEY_GCC_VERSION + 814| |#endif + 815| |#if \ + 816| | defined(JSON_HEDLEY_GNUC_VERSION) && \ + 817| | !defined(__clang__) && \ + 818| | !defined(JSON_HEDLEY_INTEL_VERSION) && \ + 819| | !defined(JSON_HEDLEY_PGI_VERSION) && \ + 820| | !defined(JSON_HEDLEY_ARM_VERSION) && \ + 821| | !defined(JSON_HEDLEY_CRAY_VERSION) && \ + 822| | !defined(JSON_HEDLEY_TI_VERSION) && \ + 823| | !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + 824| | !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + 825| | !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + 826| | !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + 827| | !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + 828| | !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + 829| | !defined(__COMPCERT__) && \ + 830| | !defined(JSON_HEDLEY_MCST_LCC_VERSION) + 831| | #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION + 832| |#endif + 833| | + 834| |#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + 835| | #undef JSON_HEDLEY_GCC_VERSION_CHECK + 836| |#endif + 837| |#if defined(JSON_HEDLEY_GCC_VERSION) + 838| | #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) + 839| |#else + 840| | #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) + 841| |#endif + 842| | + 843| |#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + 844| | #undef JSON_HEDLEY_HAS_ATTRIBUTE + 845| |#endif + 846| |#if \ + 847| | defined(__has_attribute) && \ + 848| | ( \ + 849| | (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + 850| | ) + 851| |# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) + 852| |#else + 853| |# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) + 854| |#endif + 855| | + 856| |#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + 857| | #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE + 858| |#endif + 859| |#if defined(__has_attribute) + 860| | #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + 861| |#else + 862| | #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) + 863| |#endif + 864| | + 865| |#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + 866| | #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE + 867| |#endif + 868| |#if defined(__has_attribute) + 869| | #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + 870| |#else + 871| | #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) + 872| |#endif + 873| | + 874| |#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + 875| | #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE + 876| |#endif + 877| |#if \ + 878| | defined(__has_cpp_attribute) && \ + 879| | defined(__cplusplus) && \ + 880| | (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + 881| | #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) + 882| |#else + 883| | #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) + 884| |#endif + 885| | + 886| |#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + 887| | #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS + 888| |#endif + 889| |#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + 890| | #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) + 891| |#elif \ + 892| | !defined(JSON_HEDLEY_PGI_VERSION) && \ + 893| | !defined(JSON_HEDLEY_IAR_VERSION) && \ + 894| | (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + 895| | (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + 896| | #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) + 897| |#else + 898| | #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) + 899| |#endif + 900| | + 901| |#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + 902| | #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE + 903| |#endif + 904| |#if defined(__has_cpp_attribute) && defined(__cplusplus) + 905| | #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) + 906| |#else + 907| | #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) + 908| |#endif + 909| | + 910| |#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + 911| | #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE + 912| |#endif + 913| |#if defined(__has_cpp_attribute) && defined(__cplusplus) + 914| | #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) + 915| |#else + 916| | #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) + 917| |#endif + 918| | + 919| |#if defined(JSON_HEDLEY_HAS_BUILTIN) + 920| | #undef JSON_HEDLEY_HAS_BUILTIN + 921| |#endif + 922| |#if defined(__has_builtin) + 923| | #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) + 924| |#else + 925| | #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) + 926| |#endif + 927| | + 928| |#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + 929| | #undef JSON_HEDLEY_GNUC_HAS_BUILTIN + 930| |#endif + 931| |#if defined(__has_builtin) + 932| | #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) + 933| |#else + 934| | #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) + 935| |#endif + 936| | + 937| |#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + 938| | #undef JSON_HEDLEY_GCC_HAS_BUILTIN + 939| |#endif + 940| |#if defined(__has_builtin) + 941| | #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) + 942| |#else + 943| | #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) + 944| |#endif + 945| | + 946| |#if defined(JSON_HEDLEY_HAS_FEATURE) + 947| | #undef JSON_HEDLEY_HAS_FEATURE + 948| |#endif + 949| |#if defined(__has_feature) + 950| | #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) + 951| |#else + 952| | #define JSON_HEDLEY_HAS_FEATURE(feature) (0) + 953| |#endif + 954| | + 955| |#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + 956| | #undef JSON_HEDLEY_GNUC_HAS_FEATURE + 957| |#endif + 958| |#if defined(__has_feature) + 959| | #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) + 960| |#else + 961| | #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) + 962| |#endif + 963| | + 964| |#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + 965| | #undef JSON_HEDLEY_GCC_HAS_FEATURE + 966| |#endif + 967| |#if defined(__has_feature) + 968| | #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) + 969| |#else + 970| | #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) + 971| |#endif + 972| | + 973| |#if defined(JSON_HEDLEY_HAS_EXTENSION) + 974| | #undef JSON_HEDLEY_HAS_EXTENSION + 975| |#endif + 976| |#if defined(__has_extension) + 977| | #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) + 978| |#else + 979| | #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) + 980| |#endif + 981| | + 982| |#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + 983| | #undef JSON_HEDLEY_GNUC_HAS_EXTENSION + 984| |#endif + 985| |#if defined(__has_extension) + 986| | #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) + 987| |#else + 988| | #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) + 989| |#endif + 990| | + 991| |#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + 992| | #undef JSON_HEDLEY_GCC_HAS_EXTENSION + 993| |#endif + 994| |#if defined(__has_extension) + 995| | #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) + 996| |#else + 997| | #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) + 998| |#endif + 999| | + 1000| |#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + 1001| | #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE + 1002| |#endif + 1003| |#if defined(__has_declspec_attribute) + 1004| | #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) + 1005| |#else + 1006| | #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) + 1007| |#endif + 1008| | + 1009| |#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + 1010| | #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE + 1011| |#endif + 1012| |#if defined(__has_declspec_attribute) + 1013| | #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) + 1014| |#else + 1015| | #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) + 1016| |#endif + 1017| | + 1018| |#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + 1019| | #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE + 1020| |#endif + 1021| |#if defined(__has_declspec_attribute) + 1022| | #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) + 1023| |#else + 1024| | #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) + 1025| |#endif + 1026| | + 1027| |#if defined(JSON_HEDLEY_HAS_WARNING) + 1028| | #undef JSON_HEDLEY_HAS_WARNING + 1029| |#endif + 1030| |#if defined(__has_warning) + 1031| | #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) + 1032| |#else + 1033| | #define JSON_HEDLEY_HAS_WARNING(warning) (0) + 1034| |#endif + 1035| | + 1036| |#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + 1037| | #undef JSON_HEDLEY_GNUC_HAS_WARNING + 1038| |#endif + 1039| |#if defined(__has_warning) + 1040| | #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) + 1041| |#else + 1042| | #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) + 1043| |#endif + 1044| | + 1045| |#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + 1046| | #undef JSON_HEDLEY_GCC_HAS_WARNING + 1047| |#endif + 1048| |#if defined(__has_warning) + 1049| | #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) + 1050| |#else + 1051| | #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) + 1052| |#endif + 1053| | + 1054| |#if \ + 1055| | (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + 1056| | defined(__clang__) || \ + 1057| | JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + 1058| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1059| | JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + 1060| | JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + 1061| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1062| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1063| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + 1064| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + 1065| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + 1066| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + 1067| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1068| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1069| | JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + 1070| | JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + 1071| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + 1072| | (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + 1073| | #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) + 1074| |#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + 1075| | #define JSON_HEDLEY_PRAGMA(value) __pragma(value) + 1076| |#else + 1077| | #define JSON_HEDLEY_PRAGMA(value) + 1078| |#endif + 1079| | + 1080| |#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + 1081| | #undef JSON_HEDLEY_DIAGNOSTIC_PUSH + 1082| |#endif + 1083| |#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + 1084| | #undef JSON_HEDLEY_DIAGNOSTIC_POP + 1085| |#endif + 1086| |#if defined(__clang__) + 1087| | #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + 1088| | #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") + 1089| |#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + 1090| | #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + 1091| | #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") + 1092| |#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + 1093| | #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + 1094| | #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") + 1095| |#elif \ + 1096| | JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + 1097| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1098| | #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + 1099| | #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) + 1100| |#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + 1101| | #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + 1102| | #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") + 1103| |#elif \ + 1104| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1105| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1106| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + 1107| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + 1108| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1109| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + 1110| | #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + 1111| | #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") + 1112| |#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + 1113| | #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + 1114| | #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") + 1115| |#else + 1116| | #define JSON_HEDLEY_DIAGNOSTIC_PUSH + 1117| | #define JSON_HEDLEY_DIAGNOSTIC_POP + 1118| |#endif + 1119| | + 1120| |/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + 1121| | HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ + 1122| |#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + 1123| | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ + 1124| |#endif + 1125| |#if defined(__cplusplus) + 1126| |# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") + 1127| |# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") + 1128| |# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") + 1129| |# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + 1130| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 1131| | _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + 1132| | _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + 1133| | _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + 1134| | xpr \ + 1135| | JSON_HEDLEY_DIAGNOSTIC_POP + 1136| |# else + 1137| |# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + 1138| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 1139| | _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + 1140| | _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + 1141| | xpr \ + 1142| | JSON_HEDLEY_DIAGNOSTIC_POP + 1143| |# endif + 1144| |# else + 1145| |# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + 1146| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 1147| | _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + 1148| | xpr \ + 1149| | JSON_HEDLEY_DIAGNOSTIC_POP + 1150| |# endif + 1151| |# endif + 1152| |#endif + 1153| |#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + 1154| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x + 1155| |#endif + 1156| | + 1157| |#if defined(JSON_HEDLEY_CONST_CAST) + 1158| | #undef JSON_HEDLEY_CONST_CAST + 1159| |#endif + 1160| |#if defined(__cplusplus) + 1161| |# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) + 1162| |#elif \ + 1163| | JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + 1164| | JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + 1165| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + 1166| |# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + 1167| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 1168| | JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + 1169| | ((T) (expr)); \ + 1170| | JSON_HEDLEY_DIAGNOSTIC_POP \ + 1171| | })) + 1172| |#else + 1173| |# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) + 1174| |#endif + 1175| | + 1176| |#if defined(JSON_HEDLEY_REINTERPRET_CAST) + 1177| | #undef JSON_HEDLEY_REINTERPRET_CAST + 1178| |#endif + 1179| |#if defined(__cplusplus) + 1180| | #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) + 1181| |#else + 1182| | #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) + 1183| |#endif + 1184| | + 1185| |#if defined(JSON_HEDLEY_STATIC_CAST) + 1186| | #undef JSON_HEDLEY_STATIC_CAST + 1187| |#endif + 1188| |#if defined(__cplusplus) + 1189| | #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) + 1190| |#else + 1191| | #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) + 1192| |#endif + 1193| | + 1194| |#if defined(JSON_HEDLEY_CPP_CAST) + 1195| | #undef JSON_HEDLEY_CPP_CAST + 1196| |#endif + 1197| |#if defined(__cplusplus) + 1198| |# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") + 1199| |# define JSON_HEDLEY_CPP_CAST(T, expr) \ + 1200| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 1201| | _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + 1202| | ((T) (expr)) \ + 1203| | JSON_HEDLEY_DIAGNOSTIC_POP + 1204| |# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) + 1205| |# define JSON_HEDLEY_CPP_CAST(T, expr) \ + 1206| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 1207| | _Pragma("diag_suppress=Pe137") \ + 1208| | JSON_HEDLEY_DIAGNOSTIC_POP + 1209| |# else + 1210| |# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) + 1211| |# endif + 1212| |#else + 1213| |# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) + 1214| |#endif + 1215| | + 1216| |#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + 1217| | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED + 1218| |#endif + 1219| |#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + 1220| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") + 1221| |#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + 1222| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") + 1223| |#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1224| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) + 1225| |#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + 1226| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") + 1227| |#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + 1228| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") + 1229| |#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + 1230| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") + 1231| |#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + 1232| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) + 1233| |#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1234| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") + 1235| |#elif \ + 1236| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1237| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1238| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1239| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1240| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1241| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1242| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1243| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1244| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1245| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1246| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + 1247| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") + 1248| |#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + 1249| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") + 1250| |#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + 1251| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") + 1252| |#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + 1253| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") + 1254| |#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + 1255| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") + 1256| |#else + 1257| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED + 1258| |#endif + 1259| | + 1260| |#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + 1261| | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS + 1262| |#endif + 1263| |#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + 1264| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") + 1265| |#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + 1266| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") + 1267| |#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1268| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) + 1269| |#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + 1270| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") + 1271| |#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + 1272| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") + 1273| |#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + 1274| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) + 1275| |#elif \ + 1276| | JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + 1277| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + 1278| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1279| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + 1280| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") + 1281| |#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + 1282| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") + 1283| |#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + 1284| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") + 1285| |#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1286| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") + 1287| |#else + 1288| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS + 1289| |#endif + 1290| | + 1291| |#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + 1292| | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES + 1293| |#endif + 1294| |#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + 1295| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") + 1296| |#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + 1297| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") + 1298| |#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + 1299| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") + 1300| |#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1301| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) + 1302| |#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + 1303| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) + 1304| |#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + 1305| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") + 1306| |#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + 1307| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") + 1308| |#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + 1309| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") + 1310| |#elif \ + 1311| | JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + 1312| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + 1313| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + 1314| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") + 1315| |#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + 1316| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") + 1317| |#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1318| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") + 1319| |#else + 1320| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES + 1321| |#endif + 1322| | + 1323| |#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + 1324| | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL + 1325| |#endif + 1326| |#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + 1327| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") + 1328| |#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + 1329| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") + 1330| |#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + 1331| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") + 1332| |#else + 1333| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL + 1334| |#endif + 1335| | + 1336| |#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + 1337| | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION + 1338| |#endif + 1339| |#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + 1340| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") + 1341| |#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + 1342| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") + 1343| |#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + 1344| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) + 1345| |#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1346| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") + 1347| |#else + 1348| | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION + 1349| |#endif + 1350| | + 1351| |#if defined(JSON_HEDLEY_DEPRECATED) + 1352| | #undef JSON_HEDLEY_DEPRECATED + 1353| |#endif + 1354| |#if defined(JSON_HEDLEY_DEPRECATED_FOR) + 1355| | #undef JSON_HEDLEY_DEPRECATED_FOR + 1356| |#endif + 1357| |#if \ + 1358| | JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + 1359| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1360| | #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + 1361| | #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) + 1362| |#elif \ + 1363| | (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + 1364| | JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + 1365| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1366| | JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + 1367| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + 1368| | JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + 1369| | JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + 1370| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + 1371| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + 1372| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1373| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + 1374| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1375| | #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + 1376| | #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) + 1377| |#elif defined(__cplusplus) && (__cplusplus >= 201402L) + 1378| | #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + 1379| | #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) + 1380| |#elif \ + 1381| | JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + 1382| | JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + 1383| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1384| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1385| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1386| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1387| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1388| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1389| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1390| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1391| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1392| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1393| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1394| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1395| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + 1396| | JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + 1397| | #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + 1398| | #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) + 1399| |#elif \ + 1400| | JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + 1401| | JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + 1402| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1403| | #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + 1404| | #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) + 1405| |#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + 1406| | #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + 1407| | #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") + 1408| |#else + 1409| | #define JSON_HEDLEY_DEPRECATED(since) + 1410| | #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) + 1411| |#endif + 1412| | + 1413| |#if defined(JSON_HEDLEY_UNAVAILABLE) + 1414| | #undef JSON_HEDLEY_UNAVAILABLE + 1415| |#endif + 1416| |#if \ + 1417| | JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + 1418| | JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + 1419| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1420| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1421| | #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) + 1422| |#else + 1423| | #define JSON_HEDLEY_UNAVAILABLE(available_since) + 1424| |#endif + 1425| | + 1426| |#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + 1427| | #undef JSON_HEDLEY_WARN_UNUSED_RESULT + 1428| |#endif + 1429| |#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + 1430| | #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG + 1431| |#endif + 1432| |#if \ + 1433| | JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + 1434| | JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + 1435| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1436| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1437| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1438| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1439| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1440| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1441| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1442| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1443| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1444| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1445| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1446| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1447| | (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + 1448| | JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + 1449| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1450| | #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + 1451| | #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) + 1452| |#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + 1453| | #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + 1454| | #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) + 1455| |#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + 1456| | #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + 1457| | #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + 1458| |#elif defined(_Check_return_) /* SAL */ + 1459| | #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + 1460| | #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ + 1461| |#else + 1462| | #define JSON_HEDLEY_WARN_UNUSED_RESULT + 1463| | #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) + 1464| |#endif + 1465| | + 1466| |#if defined(JSON_HEDLEY_SENTINEL) + 1467| | #undef JSON_HEDLEY_SENTINEL + 1468| |#endif + 1469| |#if \ + 1470| | JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + 1471| | JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + 1472| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1473| | JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + 1474| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1475| | #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) + 1476| |#else + 1477| | #define JSON_HEDLEY_SENTINEL(position) + 1478| |#endif + 1479| | + 1480| |#if defined(JSON_HEDLEY_NO_RETURN) + 1481| | #undef JSON_HEDLEY_NO_RETURN + 1482| |#endif + 1483| |#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + 1484| | #define JSON_HEDLEY_NO_RETURN __noreturn + 1485| |#elif \ + 1486| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1487| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1488| | #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) + 1489| |#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + 1490| | #define JSON_HEDLEY_NO_RETURN _Noreturn + 1491| |#elif defined(__cplusplus) && (__cplusplus >= 201103L) + 1492| | #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) + 1493| |#elif \ + 1494| | JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + 1495| | JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + 1496| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + 1497| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1498| | JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + 1499| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1500| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1501| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1502| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1503| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1504| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1505| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1506| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1507| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1508| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1509| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1510| | JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + 1511| | #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) + 1512| |#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + 1513| | #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") + 1514| |#elif \ + 1515| | JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + 1516| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1517| | #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) + 1518| |#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + 1519| | #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") + 1520| |#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + 1521| | #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) + 1522| |#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + 1523| | #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) + 1524| |#else + 1525| | #define JSON_HEDLEY_NO_RETURN + 1526| |#endif + 1527| | + 1528| |#if defined(JSON_HEDLEY_NO_ESCAPE) + 1529| | #undef JSON_HEDLEY_NO_ESCAPE + 1530| |#endif + 1531| |#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + 1532| | #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) + 1533| |#else + 1534| | #define JSON_HEDLEY_NO_ESCAPE + 1535| |#endif + 1536| | + 1537| |#if defined(JSON_HEDLEY_UNREACHABLE) + 1538| | #undef JSON_HEDLEY_UNREACHABLE + 1539| |#endif + 1540| |#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + 1541| | #undef JSON_HEDLEY_UNREACHABLE_RETURN + 1542| |#endif + 1543| |#if defined(JSON_HEDLEY_ASSUME) + 1544| | #undef JSON_HEDLEY_ASSUME + 1545| |#endif + 1546| |#if \ + 1547| | JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + 1548| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1549| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1550| | #define JSON_HEDLEY_ASSUME(expr) __assume(expr) + 1551| |#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + 1552| | #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) + 1553| |#elif \ + 1554| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + 1555| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + 1556| | #if defined(__cplusplus) + 1557| | #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + 1558| | #else + 1559| | #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + 1560| | #endif + 1561| |#endif + 1562| |#if \ + 1563| | (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + 1564| | JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + 1565| | JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + 1566| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1567| | JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + 1568| | JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + 1569| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1570| | #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() + 1571| |#elif defined(JSON_HEDLEY_ASSUME) + 1572| | #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) + 1573| |#endif + 1574| |#if !defined(JSON_HEDLEY_ASSUME) + 1575| | #if defined(JSON_HEDLEY_UNREACHABLE) + 1576| | #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + 1577| | #else + 1578| | #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + 1579| | #endif + 1580| |#endif + 1581| |#if defined(JSON_HEDLEY_UNREACHABLE) + 1582| | #if \ + 1583| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + 1584| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + 1585| | #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + 1586| | #else + 1587| | #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + 1588| | #endif + 1589| |#else + 1590| | #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) + 1591| |#endif + 1592| |#if !defined(JSON_HEDLEY_UNREACHABLE) + 1593| | #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) + 1594| |#endif + 1595| | + 1596| |JSON_HEDLEY_DIAGNOSTIC_PUSH + 1597| |#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + 1598| | #pragma clang diagnostic ignored "-Wpedantic" + 1599| |#endif + 1600| |#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + 1601| | #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" + 1602| |#endif + 1603| |#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + 1604| | #if defined(__clang__) + 1605| | #pragma clang diagnostic ignored "-Wvariadic-macros" + 1606| | #elif defined(JSON_HEDLEY_GCC_VERSION) + 1607| | #pragma GCC diagnostic ignored "-Wvariadic-macros" + 1608| | #endif + 1609| |#endif + 1610| |#if defined(JSON_HEDLEY_NON_NULL) + 1611| | #undef JSON_HEDLEY_NON_NULL + 1612| |#endif + 1613| |#if \ + 1614| | JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + 1615| | JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + 1616| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1617| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + 1618| | #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) + 1619| |#else + 1620| | #define JSON_HEDLEY_NON_NULL(...) + 1621| |#endif + 1622| |JSON_HEDLEY_DIAGNOSTIC_POP + 1623| | + 1624| |#if defined(JSON_HEDLEY_PRINTF_FORMAT) + 1625| | #undef JSON_HEDLEY_PRINTF_FORMAT + 1626| |#endif + 1627| |#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + 1628| | #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) + 1629| |#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + 1630| | #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) + 1631| |#elif \ + 1632| | JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + 1633| | JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + 1634| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1635| | JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + 1636| | JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + 1637| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1638| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1639| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1640| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1641| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1642| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1643| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1644| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1645| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1646| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1647| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1648| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1649| | #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) + 1650| |#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + 1651| | #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) + 1652| |#else + 1653| | #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) + 1654| |#endif + 1655| | + 1656| |#if defined(JSON_HEDLEY_CONSTEXPR) + 1657| | #undef JSON_HEDLEY_CONSTEXPR + 1658| |#endif + 1659| |#if defined(__cplusplus) + 1660| | #if __cplusplus >= 201103L + 1661| | #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + 1662| | #endif + 1663| |#endif + 1664| |#if !defined(JSON_HEDLEY_CONSTEXPR) + 1665| | #define JSON_HEDLEY_CONSTEXPR + 1666| |#endif + 1667| | + 1668| |#if defined(JSON_HEDLEY_PREDICT) + 1669| | #undef JSON_HEDLEY_PREDICT + 1670| |#endif + 1671| |#if defined(JSON_HEDLEY_LIKELY) + 1672| | #undef JSON_HEDLEY_LIKELY + 1673| |#endif + 1674| |#if defined(JSON_HEDLEY_UNLIKELY) + 1675| | #undef JSON_HEDLEY_UNLIKELY + 1676| |#endif + 1677| |#if defined(JSON_HEDLEY_UNPREDICTABLE) + 1678| | #undef JSON_HEDLEY_UNPREDICTABLE + 1679| |#endif + 1680| |#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + 1681| | #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) + 1682| |#endif + 1683| |#if \ + 1684| | (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + 1685| | JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + 1686| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1687| |# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) + 1688| |# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) + 1689| |# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) + 1690| 0|# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) + 1691| 0|# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) + 1692| |#elif \ + 1693| | (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + 1694| | JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + 1695| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1696| | (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + 1697| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1698| | JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + 1699| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1700| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + 1701| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + 1702| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + 1703| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + 1704| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1705| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1706| | JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + 1707| | JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + 1708| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1709| |# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + 1710| | (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) + 1711| |# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + 1712| | (__extension__ ({ \ + 1713| | double hedley_probability_ = (probability); \ + 1714| | ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + 1715| | })) + 1716| |# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + 1717| | (__extension__ ({ \ + 1718| | double hedley_probability_ = (probability); \ + 1719| | ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + 1720| | })) + 1721| |# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) + 1722| |# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) + 1723| |#else + 1724| |# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) + 1725| |# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) + 1726| |# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) + 1727| |# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) + 1728| |# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) + 1729| |#endif + 1730| |#if !defined(JSON_HEDLEY_UNPREDICTABLE) + 1731| | #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) + 1732| |#endif + 1733| | + 1734| |#if defined(JSON_HEDLEY_MALLOC) + 1735| | #undef JSON_HEDLEY_MALLOC + 1736| |#endif + 1737| |#if \ + 1738| | JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + 1739| | JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + 1740| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1741| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + 1742| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1743| | JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + 1744| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1745| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1746| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1747| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1748| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1749| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1750| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1751| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1752| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1753| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1754| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1755| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1756| | #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) + 1757| |#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + 1758| | #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") + 1759| |#elif \ + 1760| | JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + 1761| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1762| | #define JSON_HEDLEY_MALLOC __declspec(restrict) + 1763| |#else + 1764| | #define JSON_HEDLEY_MALLOC + 1765| |#endif + 1766| | + 1767| |#if defined(JSON_HEDLEY_PURE) + 1768| | #undef JSON_HEDLEY_PURE + 1769| |#endif + 1770| |#if \ + 1771| | JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + 1772| | JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + 1773| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1774| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + 1775| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1776| | JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + 1777| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1778| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1779| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1780| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1781| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1782| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1783| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1784| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1785| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1786| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1787| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1788| | JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + 1789| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1790| |# define JSON_HEDLEY_PURE __attribute__((__pure__)) + 1791| |#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + 1792| |# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") + 1793| |#elif defined(__cplusplus) && \ + 1794| | ( \ + 1795| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + 1796| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + 1797| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + 1798| | ) + 1799| |# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") + 1800| |#else + 1801| |# define JSON_HEDLEY_PURE + 1802| |#endif + 1803| | + 1804| |#if defined(JSON_HEDLEY_CONST) + 1805| | #undef JSON_HEDLEY_CONST + 1806| |#endif + 1807| |#if \ + 1808| | JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + 1809| | JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + 1810| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1811| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + 1812| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1813| | JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + 1814| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1815| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1816| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1817| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1818| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1819| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1820| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1821| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1822| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1823| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1824| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1825| | JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + 1826| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1827| | #define JSON_HEDLEY_CONST __attribute__((__const__)) + 1828| |#elif \ + 1829| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + 1830| | #define JSON_HEDLEY_CONST _Pragma("no_side_effect") + 1831| |#else + 1832| | #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE + 1833| |#endif + 1834| | + 1835| |#if defined(JSON_HEDLEY_RESTRICT) + 1836| | #undef JSON_HEDLEY_RESTRICT + 1837| |#endif + 1838| |#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + 1839| | #define JSON_HEDLEY_RESTRICT restrict + 1840| |#elif \ + 1841| | JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + 1842| | JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + 1843| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1844| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + 1845| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1846| | JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + 1847| | JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + 1848| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1849| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + 1850| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + 1851| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1852| | (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + 1853| | JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + 1854| | defined(__clang__) || \ + 1855| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1856| | #define JSON_HEDLEY_RESTRICT __restrict + 1857| |#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + 1858| | #define JSON_HEDLEY_RESTRICT _Restrict + 1859| |#else + 1860| | #define JSON_HEDLEY_RESTRICT + 1861| |#endif + 1862| | + 1863| |#if defined(JSON_HEDLEY_INLINE) + 1864| | #undef JSON_HEDLEY_INLINE + 1865| |#endif + 1866| |#if \ + 1867| | (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + 1868| | (defined(__cplusplus) && (__cplusplus >= 199711L)) + 1869| | #define JSON_HEDLEY_INLINE inline + 1870| |#elif \ + 1871| | defined(JSON_HEDLEY_GCC_VERSION) || \ + 1872| | JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + 1873| | #define JSON_HEDLEY_INLINE __inline__ + 1874| |#elif \ + 1875| | JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + 1876| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + 1877| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1878| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + 1879| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + 1880| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + 1881| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + 1882| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1883| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1884| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 1885| | #define JSON_HEDLEY_INLINE __inline + 1886| |#else + 1887| | #define JSON_HEDLEY_INLINE + 1888| |#endif + 1889| | + 1890| |#if defined(JSON_HEDLEY_ALWAYS_INLINE) + 1891| | #undef JSON_HEDLEY_ALWAYS_INLINE + 1892| |#endif + 1893| |#if \ + 1894| | JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + 1895| | JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + 1896| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1897| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + 1898| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1899| | JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + 1900| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1901| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1902| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1903| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1904| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1905| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1906| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1907| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1908| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1909| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1910| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1911| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + 1912| | JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + 1913| |# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE + 1914| |#elif \ + 1915| | JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + 1916| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1917| |# define JSON_HEDLEY_ALWAYS_INLINE __forceinline + 1918| |#elif defined(__cplusplus) && \ + 1919| | ( \ + 1920| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1921| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1922| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1923| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + 1924| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1925| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + 1926| | ) + 1927| |# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") + 1928| |#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + 1929| |# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") + 1930| |#else + 1931| |# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE + 1932| |#endif + 1933| | + 1934| |#if defined(JSON_HEDLEY_NEVER_INLINE) + 1935| | #undef JSON_HEDLEY_NEVER_INLINE + 1936| |#endif + 1937| |#if \ + 1938| | JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + 1939| | JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + 1940| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1941| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + 1942| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1943| | JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + 1944| | JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + 1945| | (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1946| | JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + 1947| | (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1948| | JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + 1949| | (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1950| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + 1951| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 1952| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + 1953| | JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + 1954| | JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + 1955| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + 1956| | JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + 1957| | #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) + 1958| |#elif \ + 1959| | JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + 1960| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 1961| | #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) + 1962| |#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + 1963| | #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") + 1964| |#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + 1965| | #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") + 1966| |#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + 1967| | #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") + 1968| |#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + 1969| | #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) + 1970| |#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + 1971| | #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) + 1972| |#else + 1973| | #define JSON_HEDLEY_NEVER_INLINE + 1974| |#endif + 1975| | + 1976| |#if defined(JSON_HEDLEY_PRIVATE) + 1977| | #undef JSON_HEDLEY_PRIVATE + 1978| |#endif + 1979| |#if defined(JSON_HEDLEY_PUBLIC) + 1980| | #undef JSON_HEDLEY_PUBLIC + 1981| |#endif + 1982| |#if defined(JSON_HEDLEY_IMPORT) + 1983| | #undef JSON_HEDLEY_IMPORT + 1984| |#endif + 1985| |#if defined(_WIN32) || defined(__CYGWIN__) + 1986| |# define JSON_HEDLEY_PRIVATE + 1987| |# define JSON_HEDLEY_PUBLIC __declspec(dllexport) + 1988| |# define JSON_HEDLEY_IMPORT __declspec(dllimport) + 1989| |#else + 1990| |# if \ + 1991| | JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + 1992| | JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + 1993| | JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + 1994| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 1995| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 1996| | JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + 1997| | ( \ + 1998| | defined(__TI_EABI__) && \ + 1999| | ( \ + 2000| | (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + 2001| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + 2002| | ) \ + 2003| | ) || \ + 2004| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 2005| |# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) + 2006| |# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) + 2007| |# else + 2008| |# define JSON_HEDLEY_PRIVATE + 2009| |# define JSON_HEDLEY_PUBLIC + 2010| |# endif + 2011| |# define JSON_HEDLEY_IMPORT extern + 2012| |#endif + 2013| | + 2014| |#if defined(JSON_HEDLEY_NO_THROW) + 2015| | #undef JSON_HEDLEY_NO_THROW + 2016| |#endif + 2017| |#if \ + 2018| | JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + 2019| | JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + 2020| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 2021| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 2022| | #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) + 2023| |#elif \ + 2024| | JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + 2025| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + 2026| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + 2027| | #define JSON_HEDLEY_NO_THROW __declspec(nothrow) + 2028| |#else + 2029| | #define JSON_HEDLEY_NO_THROW + 2030| |#endif + 2031| | + 2032| |#if defined(JSON_HEDLEY_FALL_THROUGH) + 2033| | #undef JSON_HEDLEY_FALL_THROUGH + 2034| |#endif + 2035| |#if \ + 2036| | JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + 2037| | JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + 2038| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 2039| | #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) + 2040| |#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + 2041| | #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) + 2042| |#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + 2043| | #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) + 2044| |#elif defined(__fallthrough) /* SAL */ + 2045| | #define JSON_HEDLEY_FALL_THROUGH __fallthrough + 2046| |#else + 2047| | #define JSON_HEDLEY_FALL_THROUGH + 2048| |#endif + 2049| | + 2050| |#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + 2051| | #undef JSON_HEDLEY_RETURNS_NON_NULL + 2052| |#endif + 2053| |#if \ + 2054| | JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + 2055| | JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + 2056| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 2057| | #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) + 2058| |#elif defined(_Ret_notnull_) /* SAL */ + 2059| | #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ + 2060| |#else + 2061| | #define JSON_HEDLEY_RETURNS_NON_NULL + 2062| |#endif + 2063| | + 2064| |#if defined(JSON_HEDLEY_ARRAY_PARAM) + 2065| | #undef JSON_HEDLEY_ARRAY_PARAM + 2066| |#endif + 2067| |#if \ + 2068| | defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + 2069| | !defined(__STDC_NO_VLA__) && \ + 2070| | !defined(__cplusplus) && \ + 2071| | !defined(JSON_HEDLEY_PGI_VERSION) && \ + 2072| | !defined(JSON_HEDLEY_TINYC_VERSION) + 2073| | #define JSON_HEDLEY_ARRAY_PARAM(name) (name) + 2074| |#else + 2075| | #define JSON_HEDLEY_ARRAY_PARAM(name) + 2076| |#endif + 2077| | + 2078| |#if defined(JSON_HEDLEY_IS_CONSTANT) + 2079| | #undef JSON_HEDLEY_IS_CONSTANT + 2080| |#endif + 2081| |#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + 2082| | #undef JSON_HEDLEY_REQUIRE_CONSTEXPR + 2083| |#endif + 2084| |/* JSON_HEDLEY_IS_CONSTEXPR_ is for + 2085| | HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ + 2086| |#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + 2087| | #undef JSON_HEDLEY_IS_CONSTEXPR_ + 2088| |#endif + 2089| |#if \ + 2090| | JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + 2091| | JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + 2092| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 2093| | JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + 2094| | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + 2095| | JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + 2096| | JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + 2097| | (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + 2098| | JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + 2099| | JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + 2100| | #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) + 2101| |#endif + 2102| |#if !defined(__cplusplus) + 2103| |# if \ + 2104| | JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + 2105| | JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + 2106| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 2107| | JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + 2108| | JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + 2109| | JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + 2110| | JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) + 2111| |#if defined(__INTPTR_TYPE__) + 2112| | #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) + 2113| |#else + 2114| | #include + 2115| | #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) + 2116| |#endif + 2117| |# elif \ + 2118| | ( \ + 2119| | defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + 2120| | !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + 2121| | !defined(JSON_HEDLEY_PGI_VERSION) && \ + 2122| | !defined(JSON_HEDLEY_IAR_VERSION)) || \ + 2123| | (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + 2124| | JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + 2125| | JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + 2126| | JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + 2127| | JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) + 2128| |#if defined(__INTPTR_TYPE__) + 2129| | #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) + 2130| |#else + 2131| | #include + 2132| | #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) + 2133| |#endif + 2134| |# elif \ + 2135| | defined(JSON_HEDLEY_GCC_VERSION) || \ + 2136| | defined(JSON_HEDLEY_INTEL_VERSION) || \ + 2137| | defined(JSON_HEDLEY_TINYC_VERSION) || \ + 2138| | defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + 2139| | JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + 2140| | defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + 2141| | defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + 2142| | defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + 2143| | defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + 2144| | defined(__clang__) + 2145| |# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + 2146| | sizeof(void) != \ + 2147| | sizeof(*( \ + 2148| | 1 ? \ + 2149| | ((void*) ((expr) * 0L) ) : \ + 2150| |((struct { char v[sizeof(void) * 2]; } *) 1) \ + 2151| | ) \ + 2152| | ) \ + 2153| | ) + 2154| |# endif + 2155| |#endif + 2156| |#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + 2157| | #if !defined(JSON_HEDLEY_IS_CONSTANT) + 2158| | #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + 2159| | #endif + 2160| | #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) + 2161| |#else + 2162| | #if !defined(JSON_HEDLEY_IS_CONSTANT) + 2163| | #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + 2164| | #endif + 2165| | #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) + 2166| |#endif + 2167| | + 2168| |#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + 2169| | #undef JSON_HEDLEY_BEGIN_C_DECLS + 2170| |#endif + 2171| |#if defined(JSON_HEDLEY_END_C_DECLS) + 2172| | #undef JSON_HEDLEY_END_C_DECLS + 2173| |#endif + 2174| |#if defined(JSON_HEDLEY_C_DECL) + 2175| | #undef JSON_HEDLEY_C_DECL + 2176| |#endif + 2177| |#if defined(__cplusplus) + 2178| | #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + 2179| | #define JSON_HEDLEY_END_C_DECLS } + 2180| | #define JSON_HEDLEY_C_DECL extern "C" + 2181| |#else + 2182| | #define JSON_HEDLEY_BEGIN_C_DECLS + 2183| | #define JSON_HEDLEY_END_C_DECLS + 2184| | #define JSON_HEDLEY_C_DECL + 2185| |#endif + 2186| | + 2187| |#if defined(JSON_HEDLEY_STATIC_ASSERT) + 2188| | #undef JSON_HEDLEY_STATIC_ASSERT + 2189| |#endif + 2190| |#if \ + 2191| | !defined(__cplusplus) && ( \ + 2192| | (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + 2193| | (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + 2194| | JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + 2195| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + 2196| | defined(_Static_assert) \ + 2197| | ) + 2198| |# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) + 2199| |#elif \ + 2200| | (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + 2201| | JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + 2202| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 2203| |# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) + 2204| |#else + 2205| |# define JSON_HEDLEY_STATIC_ASSERT(expr, message) + 2206| |#endif + 2207| | + 2208| |#if defined(JSON_HEDLEY_NULL) + 2209| | #undef JSON_HEDLEY_NULL + 2210| |#endif + 2211| |#if defined(__cplusplus) + 2212| | #if __cplusplus >= 201103L + 2213| | #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + 2214| | #elif defined(NULL) + 2215| | #define JSON_HEDLEY_NULL NULL + 2216| | #else + 2217| | #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + 2218| | #endif + 2219| |#elif defined(NULL) + 2220| | #define JSON_HEDLEY_NULL NULL + 2221| |#else + 2222| | #define JSON_HEDLEY_NULL ((void*) 0) + 2223| |#endif + 2224| | + 2225| |#if defined(JSON_HEDLEY_MESSAGE) + 2226| | #undef JSON_HEDLEY_MESSAGE + 2227| |#endif + 2228| |#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + 2229| |# define JSON_HEDLEY_MESSAGE(msg) \ + 2230| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 2231| | JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + 2232| | JSON_HEDLEY_PRAGMA(message msg) \ + 2233| | JSON_HEDLEY_DIAGNOSTIC_POP + 2234| |#elif \ + 2235| | JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + 2236| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + 2237| |# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) + 2238| |#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) + 2239| |# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) + 2240| |#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + 2241| |# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) + 2242| |#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) + 2243| |# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) + 2244| |#else + 2245| |# define JSON_HEDLEY_MESSAGE(msg) + 2246| |#endif + 2247| | + 2248| |#if defined(JSON_HEDLEY_WARNING) + 2249| | #undef JSON_HEDLEY_WARNING + 2250| |#endif + 2251| |#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + 2252| |# define JSON_HEDLEY_WARNING(msg) \ + 2253| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 2254| | JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + 2255| | JSON_HEDLEY_PRAGMA(clang warning msg) \ + 2256| | JSON_HEDLEY_DIAGNOSTIC_POP + 2257| |#elif \ + 2258| | JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + 2259| | JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + 2260| | JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + 2261| |# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) + 2262| |#elif \ + 2263| | JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + 2264| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 2265| |# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) + 2266| |#else + 2267| |# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) + 2268| |#endif + 2269| | + 2270| |#if defined(JSON_HEDLEY_REQUIRE) + 2271| | #undef JSON_HEDLEY_REQUIRE + 2272| |#endif + 2273| |#if defined(JSON_HEDLEY_REQUIRE_MSG) + 2274| | #undef JSON_HEDLEY_REQUIRE_MSG + 2275| |#endif + 2276| |#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) + 2277| |# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") + 2278| |# define JSON_HEDLEY_REQUIRE(expr) \ + 2279| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 2280| | _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + 2281| | __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + 2282| | JSON_HEDLEY_DIAGNOSTIC_POP + 2283| |# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + 2284| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 2285| | _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + 2286| | __attribute__((diagnose_if(!(expr), msg, "error"))) \ + 2287| | JSON_HEDLEY_DIAGNOSTIC_POP + 2288| |# else + 2289| |# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) + 2290| |# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) + 2291| |# endif + 2292| |#else + 2293| |# define JSON_HEDLEY_REQUIRE(expr) + 2294| |# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) + 2295| |#endif + 2296| | + 2297| |#if defined(JSON_HEDLEY_FLAGS) + 2298| | #undef JSON_HEDLEY_FLAGS + 2299| |#endif + 2300| |#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) + 2301| | #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) + 2302| |#else + 2303| | #define JSON_HEDLEY_FLAGS + 2304| |#endif + 2305| | + 2306| |#if defined(JSON_HEDLEY_FLAGS_CAST) + 2307| | #undef JSON_HEDLEY_FLAGS_CAST + 2308| |#endif + 2309| |#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) + 2310| |# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + 2311| | JSON_HEDLEY_DIAGNOSTIC_PUSH \ + 2312| | _Pragma("warning(disable:188)") \ + 2313| | ((T) (expr)); \ + 2314| | JSON_HEDLEY_DIAGNOSTIC_POP \ + 2315| | })) + 2316| |#else + 2317| |# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) + 2318| |#endif + 2319| | + 2320| |#if defined(JSON_HEDLEY_EMPTY_BASES) + 2321| | #undef JSON_HEDLEY_EMPTY_BASES + 2322| |#endif + 2323| |#if \ + 2324| | (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + 2325| | JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + 2326| | #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) + 2327| |#else + 2328| | #define JSON_HEDLEY_EMPTY_BASES + 2329| |#endif + 2330| | + 2331| |/* Remaining macros are deprecated. */ + 2332| | + 2333| |#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + 2334| | #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK + 2335| |#endif + 2336| |#if defined(__clang__) + 2337| | #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) + 2338| |#else + 2339| | #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) + 2340| |#endif + 2341| | + 2342| |#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + 2343| | #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE + 2344| |#endif + 2345| |#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + 2346| | + 2347| |#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + 2348| | #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE + 2349| |#endif + 2350| |#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + 2351| | + 2352| |#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + 2353| | #undef JSON_HEDLEY_CLANG_HAS_BUILTIN + 2354| |#endif + 2355| |#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + 2356| | + 2357| |#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + 2358| | #undef JSON_HEDLEY_CLANG_HAS_FEATURE + 2359| |#endif + 2360| |#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + 2361| | + 2362| |#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + 2363| | #undef JSON_HEDLEY_CLANG_HAS_EXTENSION + 2364| |#endif + 2365| |#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + 2366| | + 2367| |#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + 2368| | #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE + 2369| |#endif + 2370| |#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + 2371| | + 2372| |#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + 2373| | #undef JSON_HEDLEY_CLANG_HAS_WARNING + 2374| |#endif + 2375| |#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + 2376| | + 2377| |#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + 2378| | + 2379| | + 2380| |// This file contains all internal macro definitions (except those affecting ABI) + 2381| |// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + 2382| | + 2383| |// #include + 2384| | + 2385| | + 2386| |// exclude unsupported compilers + 2387| |#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + 2388| | #if defined(__clang__) + 2389| | #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + 2390| | #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + 2391| | #endif + 2392| | #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + 2393| | #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + 2394| | #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + 2395| | #endif + 2396| | #endif + 2397| |#endif + 2398| | + 2399| |// C++ language standard detection + 2400| |// if the user manually specified the used c++ version this is skipped + 2401| |#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + 2402| | #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + 2403| | #define JSON_HAS_CPP_20 + 2404| | #define JSON_HAS_CPP_17 + 2405| | #define JSON_HAS_CPP_14 + 2406| | #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + 2407| | #define JSON_HAS_CPP_17 + 2408| | #define JSON_HAS_CPP_14 + 2409| | #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + 2410| | #define JSON_HAS_CPP_14 + 2411| | #endif + 2412| | // the cpp 11 flag is always specified because it is the minimal required version + 2413| | #define JSON_HAS_CPP_11 + 2414| |#endif + 2415| | + 2416| |#ifdef __has_include + 2417| | #if __has_include() + 2418| | #include + 2419| | #endif + 2420| |#endif + 2421| | + 2422| |#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + 2423| | #ifdef JSON_HAS_CPP_17 + 2424| | #if defined(__cpp_lib_filesystem) + 2425| | #define JSON_HAS_FILESYSTEM 1 + 2426| | #elif defined(__cpp_lib_experimental_filesystem) + 2427| | #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + 2428| | #elif !defined(__has_include) + 2429| | #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + 2430| | #elif __has_include() + 2431| | #define JSON_HAS_FILESYSTEM 1 + 2432| | #elif __has_include() + 2433| | #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + 2434| | #endif + 2435| | + 2436| | // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + 2437| | #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + 2438| | #undef JSON_HAS_FILESYSTEM + 2439| | #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + 2440| | #endif + 2441| | + 2442| | // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + 2443| | #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + 2444| | #undef JSON_HAS_FILESYSTEM + 2445| | #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + 2446| | #endif + 2447| | + 2448| | // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + 2449| | #if defined(__clang_major__) && __clang_major__ < 7 + 2450| | #undef JSON_HAS_FILESYSTEM + 2451| | #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + 2452| | #endif + 2453| | + 2454| | // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + 2455| | #if defined(_MSC_VER) && _MSC_VER < 1914 + 2456| | #undef JSON_HAS_FILESYSTEM + 2457| | #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + 2458| | #endif + 2459| | + 2460| | // no filesystem support before iOS 13 + 2461| | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + 2462| | #undef JSON_HAS_FILESYSTEM + 2463| | #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + 2464| | #endif + 2465| | + 2466| | // no filesystem support before macOS Catalina + 2467| | #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + 2468| | #undef JSON_HAS_FILESYSTEM + 2469| | #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + 2470| | #endif + 2471| | #endif + 2472| |#endif + 2473| | + 2474| |#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + 2475| | #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 + 2476| |#endif + 2477| | + 2478| |#ifndef JSON_HAS_FILESYSTEM + 2479| | #define JSON_HAS_FILESYSTEM 0 + 2480| |#endif + 2481| | + 2482| |#ifndef JSON_HAS_THREE_WAY_COMPARISON + 2483| | #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + 2484| | && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + 2485| | #define JSON_HAS_THREE_WAY_COMPARISON 1 + 2486| | #else + 2487| | #define JSON_HAS_THREE_WAY_COMPARISON 0 + 2488| | #endif + 2489| |#endif + 2490| | + 2491| |#ifndef JSON_HAS_RANGES + 2492| | // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + 2493| | #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + 2494| | #define JSON_HAS_RANGES 0 + 2495| | #elif defined(__cpp_lib_ranges) + 2496| | #define JSON_HAS_RANGES 1 + 2497| | #else + 2498| | #define JSON_HAS_RANGES 0 + 2499| | #endif + 2500| |#endif + 2501| | + 2502| |#ifndef JSON_HAS_STATIC_RTTI + 2503| | #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0 + 2504| | #define JSON_HAS_STATIC_RTTI 1 + 2505| | #else + 2506| | #define JSON_HAS_STATIC_RTTI 0 + 2507| | #endif + 2508| |#endif + 2509| | + 2510| |#ifdef JSON_HAS_CPP_17 + 2511| | #define JSON_INLINE_VARIABLE inline + 2512| |#else + 2513| | #define JSON_INLINE_VARIABLE + 2514| |#endif + 2515| | + 2516| |#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + 2517| | #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] + 2518| |#else + 2519| | #define JSON_NO_UNIQUE_ADDRESS + 2520| |#endif + 2521| | + 2522| |// disable documentation warnings on clang + 2523| |#if defined(__clang__) + 2524| | #pragma clang diagnostic push + 2525| | #pragma clang diagnostic ignored "-Wdocumentation" + 2526| | #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" + 2527| |#endif + 2528| | + 2529| |// allow disabling exceptions + 2530| |#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + 2531| 0| #define JSON_THROW(exception) throw exception + 2532| | #define JSON_TRY try + 2533| | #define JSON_CATCH(exception) catch(exception) + 2534| | #define JSON_INTERNAL_CATCH(exception) catch(exception) + 2535| |#else + 2536| | #include + 2537| | #define JSON_THROW(exception) std::abort() + 2538| | #define JSON_TRY if(true) + 2539| | #define JSON_CATCH(exception) if(false) + 2540| | #define JSON_INTERNAL_CATCH(exception) if(false) + 2541| |#endif + 2542| | + 2543| |// override exception macros + 2544| |#if defined(JSON_THROW_USER) + 2545| | #undef JSON_THROW + 2546| | #define JSON_THROW JSON_THROW_USER + 2547| |#endif + 2548| |#if defined(JSON_TRY_USER) + 2549| | #undef JSON_TRY + 2550| | #define JSON_TRY JSON_TRY_USER + 2551| |#endif + 2552| |#if defined(JSON_CATCH_USER) + 2553| | #undef JSON_CATCH + 2554| | #define JSON_CATCH JSON_CATCH_USER + 2555| | #undef JSON_INTERNAL_CATCH + 2556| | #define JSON_INTERNAL_CATCH JSON_CATCH_USER + 2557| |#endif + 2558| |#if defined(JSON_INTERNAL_CATCH_USER) + 2559| | #undef JSON_INTERNAL_CATCH + 2560| | #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER + 2561| |#endif + 2562| | + 2563| |// allow overriding assert + 2564| |#if !defined(JSON_ASSERT) + 2565| | #include // assert + 2566| 0| #define JSON_ASSERT(x) assert(x) + 2567| |#endif + 2568| | + 2569| |// allow to access some private functions (needed by the test suite) + 2570| |#if defined(JSON_TESTS_PRIVATE) + 2571| | #define JSON_PRIVATE_UNLESS_TESTED public + 2572| |#else + 2573| | #define JSON_PRIVATE_UNLESS_TESTED private + 2574| |#endif + 2575| | + 2576| |/*! + 2577| |@brief macro to briefly define a mapping between an enum and JSON + 2578| |@def NLOHMANN_JSON_SERIALIZE_ENUM + 2579| |@since version 3.4.0 + 2580| |*/ + 2581| |#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + 2582| | template \ + 2583| | inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + 2584| | { \ + 2585| | /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ + 2586| | static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + 2587| | /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ + 2588| | static const std::pair m[] = __VA_ARGS__; \ + 2589| | auto it = std::find_if(std::begin(m), std::end(m), \ + 2590| | [e](const std::pair& ej_pair) -> bool \ + 2591| | { \ + 2592| | return ej_pair.first == e; \ + 2593| | }); \ + 2594| | j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + 2595| | } \ + 2596| | template \ + 2597| | inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + 2598| | { \ + 2599| | /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */ \ + 2600| | static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + 2601| | /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on */ \ + 2602| | static const std::pair m[] = __VA_ARGS__; \ + 2603| | auto it = std::find_if(std::begin(m), std::end(m), \ + 2604| | [&j](const std::pair& ej_pair) -> bool \ + 2605| | { \ + 2606| | return ej_pair.second == j; \ + 2607| | }); \ + 2608| | e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + 2609| | } + 2610| | + 2611| |// Ugly macros to avoid uglier copy-paste when specializing basic_json. They + 2612| |// may be removed in the future once the class is split. + 2613| | + 2614| |#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + 2615| | template class ObjectType, \ + 2616| | template class ArrayType, \ + 2617| | class StringType, class BooleanType, class NumberIntegerType, \ + 2618| | class NumberUnsignedType, class NumberFloatType, \ + 2619| | template class AllocatorType, \ + 2620| | template class JSONSerializer, \ + 2621| | class BinaryType, \ + 2622| | class CustomBaseClass> + 2623| | + 2624| |#define NLOHMANN_BASIC_JSON_TPL \ + 2625| | basic_json + 2628| | + 2629| |// Macros to simplify conversion from/to types + 2630| | + 2631| 0|#define NLOHMANN_JSON_EXPAND( x ) x + 2632| |#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME + 2633| |#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + 2634| | NLOHMANN_JSON_PASTE64, \ + 2635| | NLOHMANN_JSON_PASTE63, \ + 2636| | NLOHMANN_JSON_PASTE62, \ + 2637| | NLOHMANN_JSON_PASTE61, \ + 2638| | NLOHMANN_JSON_PASTE60, \ + 2639| | NLOHMANN_JSON_PASTE59, \ + 2640| | NLOHMANN_JSON_PASTE58, \ + 2641| | NLOHMANN_JSON_PASTE57, \ + 2642| | NLOHMANN_JSON_PASTE56, \ + 2643| | NLOHMANN_JSON_PASTE55, \ + 2644| | NLOHMANN_JSON_PASTE54, \ + 2645| | NLOHMANN_JSON_PASTE53, \ + 2646| | NLOHMANN_JSON_PASTE52, \ + 2647| | NLOHMANN_JSON_PASTE51, \ + 2648| | NLOHMANN_JSON_PASTE50, \ + 2649| | NLOHMANN_JSON_PASTE49, \ + 2650| | NLOHMANN_JSON_PASTE48, \ + 2651| | NLOHMANN_JSON_PASTE47, \ + 2652| | NLOHMANN_JSON_PASTE46, \ + 2653| | NLOHMANN_JSON_PASTE45, \ + 2654| | NLOHMANN_JSON_PASTE44, \ + 2655| | NLOHMANN_JSON_PASTE43, \ + 2656| | NLOHMANN_JSON_PASTE42, \ + 2657| | NLOHMANN_JSON_PASTE41, \ + 2658| | NLOHMANN_JSON_PASTE40, \ + 2659| | NLOHMANN_JSON_PASTE39, \ + 2660| | NLOHMANN_JSON_PASTE38, \ + 2661| | NLOHMANN_JSON_PASTE37, \ + 2662| | NLOHMANN_JSON_PASTE36, \ + 2663| | NLOHMANN_JSON_PASTE35, \ + 2664| | NLOHMANN_JSON_PASTE34, \ + 2665| | NLOHMANN_JSON_PASTE33, \ + 2666| | NLOHMANN_JSON_PASTE32, \ + 2667| | NLOHMANN_JSON_PASTE31, \ + 2668| | NLOHMANN_JSON_PASTE30, \ + 2669| | NLOHMANN_JSON_PASTE29, \ + 2670| | NLOHMANN_JSON_PASTE28, \ + 2671| | NLOHMANN_JSON_PASTE27, \ + 2672| | NLOHMANN_JSON_PASTE26, \ + 2673| | NLOHMANN_JSON_PASTE25, \ + 2674| | NLOHMANN_JSON_PASTE24, \ + 2675| | NLOHMANN_JSON_PASTE23, \ + 2676| | NLOHMANN_JSON_PASTE22, \ + 2677| | NLOHMANN_JSON_PASTE21, \ + 2678| | NLOHMANN_JSON_PASTE20, \ + 2679| | NLOHMANN_JSON_PASTE19, \ + 2680| | NLOHMANN_JSON_PASTE18, \ + 2681| | NLOHMANN_JSON_PASTE17, \ + 2682| | NLOHMANN_JSON_PASTE16, \ + 2683| | NLOHMANN_JSON_PASTE15, \ + 2684| | NLOHMANN_JSON_PASTE14, \ + 2685| | NLOHMANN_JSON_PASTE13, \ + 2686| | NLOHMANN_JSON_PASTE12, \ + 2687| | NLOHMANN_JSON_PASTE11, \ + 2688| | NLOHMANN_JSON_PASTE10, \ + 2689| | NLOHMANN_JSON_PASTE9, \ + 2690| | NLOHMANN_JSON_PASTE8, \ + 2691| | NLOHMANN_JSON_PASTE7, \ + 2692| | NLOHMANN_JSON_PASTE6, \ + 2693| | NLOHMANN_JSON_PASTE5, \ + 2694| | NLOHMANN_JSON_PASTE4, \ + 2695| | NLOHMANN_JSON_PASTE3, \ + 2696| | NLOHMANN_JSON_PASTE2, \ + 2697| | NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) + 2698| |#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) + 2699| |#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) + 2700| |#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) + 2701| |#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) + 2702| |#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) + 2703| |#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) + 2704| |#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) + 2705| |#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) + 2706| |#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) + 2707| |#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) + 2708| |#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) + 2709| |#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) + 2710| |#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) + 2711| |#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) + 2712| |#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) + 2713| |#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) + 2714| |#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) + 2715| |#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) + 2716| |#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) + 2717| |#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) + 2718| |#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) + 2719| |#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) + 2720| |#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) + 2721| |#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) + 2722| |#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) + 2723| |#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) + 2724| |#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) + 2725| |#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) + 2726| |#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) + 2727| |#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) + 2728| |#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) + 2729| |#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) + 2730| |#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) + 2731| |#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) + 2732| |#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) + 2733| |#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) + 2734| |#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) + 2735| |#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) + 2736| |#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) + 2737| |#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) + 2738| |#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) + 2739| |#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) + 2740| |#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) + 2741| |#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) + 2742| |#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) + 2743| |#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) + 2744| |#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) + 2745| |#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) + 2746| |#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) + 2747| |#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) + 2748| |#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) + 2749| |#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) + 2750| |#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) + 2751| |#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) + 2752| |#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) + 2753| |#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) + 2754| |#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) + 2755| |#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) + 2756| |#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) + 2757| |#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) + 2758| |#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) + 2759| |#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) + 2760| |#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + 2761| | + 2762| |#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; + 2763| |#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); + 2764| |#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = !nlohmann_json_j.is_null() ? nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1) : nlohmann_json_default_obj.v1; + 2765| | + 2766| |/*! + 2767| |@brief macro + 2768| |@def NLOHMANN_DEFINE_TYPE_INTRUSIVE + 2769| |@since version 3.9.0 + 2770| |*/ + 2771| |#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + 2772| | friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + 2773| | friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + 2774| | + 2775| |/*! + 2776| |@brief macro + 2777| |@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT + 2778| |@since version 3.11.0 + 2779| |*/ + 2780| |#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + 2781| | friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + 2782| | friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + 2783| | + 2784| |/*! + 2785| |@brief macro + 2786| |@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE + 2787| |@since version 3.11.x + 2788| |*/ + 2789| |#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + 2790| | friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + 2791| | + 2792| |/*! + 2793| |@brief macro + 2794| |@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE + 2795| |@since version 3.9.0 + 2796| |*/ + 2797| |#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + 2798| 0| inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions7to_jsonERN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERKNS_16OHLCRSIVariablesE + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions7to_jsonERN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERKNS_13OHLCVariablesE + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions7to_jsonERN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERKNS_16TradingVariablesE + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions7to_jsonERN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERKNS_8StrategyE + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions7to_jsonERN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERKNS_13ConfigurationE + ------------------ + 2799| 0| inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions9from_jsonERKN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERNS_16OHLCRSIVariablesE + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions9from_jsonERKN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERNS_13ConfigurationE + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions9from_jsonERKN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERNS_8StrategyE + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions9from_jsonERKN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERNS_16TradingVariablesE + ------------------ + | Unexecuted instantiation: _ZN19trading_definitions9from_jsonERKN8nlohmann16json_abi_v3_11_310basic_jsonINSt3__13mapENS3_6vectorENS3_12basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEbxydS9_NS1_14adl_serializerENS5_IhNS9_IhEEEEvEERNS_13OHLCVariablesE + ------------------ + 2800| | + 2801| |/*! + 2802| |@brief macro + 2803| |@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT + 2804| |@since version 3.11.0 + 2805| |*/ + 2806| |#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + 2807| | inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + 2808| | inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + 2809| | + 2810| |/*! + 2811| |@brief macro + 2812| |@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE + 2813| |@since version 3.11.x + 2814| |*/ + 2815| |#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + 2816| | inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + 2817| | + 2818| |/*! + 2819| |@brief macro + 2820| |@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE + 2821| |@since version 3.11.x + 2822| |*/ + 2823| |#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(Type, BaseType, ...) \ + 2824| | friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + 2825| | friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + 2826| | + 2827| |#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + 2828| | friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + 2829| | friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + 2830| | + 2831| |#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + 2832| | friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + 2833| | + 2834| |/*! + 2835| |@brief macro + 2836| |@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE + 2837| |@since version 3.11.x + 2838| |*/ + 2839| |#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(Type, BaseType, ...) \ + 2840| | inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + 2841| | inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + 2842| | + 2843| |#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...) \ + 2844| | inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + 2845| | inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + 2846| | + 2847| |#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...) \ + 2848| | inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + 2849| | + 2850| |// inspired from https://stackoverflow.com/a/26745591 + 2851| |// allows to call any std function as if (e.g. with begin): + 2852| |// using std::begin; begin(x); + 2853| |// + 2854| |// it allows using the detected idiom to retrieve the return type + 2855| |// of such an expression + 2856| |#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + 2857| | namespace detail { \ + 2858| | using std::std_name; \ + 2859| | \ + 2860| | template \ + 2861| | using result_of_##std_name = decltype(std_name(std::declval()...)); \ + 2862| | } \ + 2863| | \ + 2864| | namespace detail2 { \ + 2865| | struct std_name##_tag \ + 2866| | { \ + 2867| | }; \ + 2868| | \ + 2869| | template \ + 2870| | std_name##_tag std_name(T&&...); \ + 2871| | \ + 2872| | template \ + 2873| | using result_of_##std_name = decltype(std_name(std::declval()...)); \ + 2874| | \ + 2875| | template \ + 2876| | struct would_call_std_##std_name \ + 2877| | { \ + 2878| | static constexpr auto const value = ::nlohmann::detail:: \ + 2879| | is_detected_exact::value; \ + 2880| | }; \ + 2881| | } /* namespace detail2 */ \ + 2882| | \ + 2883| | template \ + 2884| | struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + 2885| | { \ + 2886| | } + 2887| | + 2888| |#ifndef JSON_USE_IMPLICIT_CONVERSIONS + 2889| | #define JSON_USE_IMPLICIT_CONVERSIONS 1 + 2890| |#endif + 2891| | + 2892| |#if JSON_USE_IMPLICIT_CONVERSIONS + 2893| | #define JSON_EXPLICIT + 2894| |#else + 2895| | #define JSON_EXPLICIT explicit + 2896| |#endif + 2897| | + 2898| |#ifndef JSON_DISABLE_ENUM_SERIALIZATION + 2899| | #define JSON_DISABLE_ENUM_SERIALIZATION 0 + 2900| |#endif + 2901| | + 2902| |#ifndef JSON_USE_GLOBAL_UDLS + 2903| | #define JSON_USE_GLOBAL_UDLS 1 + 2904| |#endif + 2905| | + 2906| |#if JSON_HAS_THREE_WAY_COMPARISON + 2907| | #include // partial_ordering + 2908| |#endif + 2909| | + 2910| |NLOHMANN_JSON_NAMESPACE_BEGIN + 2911| |namespace detail + 2912| |{ + 2913| | + 2914| |/////////////////////////// + 2915| |// JSON type enumeration // + 2916| |/////////////////////////// + 2917| | + 2918| |/*! + 2919| |@brief the JSON type enumeration + 2920| | + 2921| |This enumeration collects the different JSON types. It is internally used to + 2922| |distinguish the stored values, and the functions @ref basic_json::is_null(), + 2923| |@ref basic_json::is_object(), @ref basic_json::is_array(), + 2924| |@ref basic_json::is_string(), @ref basic_json::is_boolean(), + 2925| |@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), + 2926| |@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), + 2927| |@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and + 2928| |@ref basic_json::is_structured() rely on it. + 2929| | + 2930| |@note There are three enumeration entries (number_integer, number_unsigned, and + 2931| |number_float), because the library distinguishes these three types for numbers: + 2932| |@ref basic_json::number_unsigned_t is used for unsigned integers, + 2933| |@ref basic_json::number_integer_t is used for signed integers, and + 2934| |@ref basic_json::number_float_t is used for floating-point numbers or to + 2935| |approximate integers which do not fit in the limits of their respective type. + 2936| | + 2937| |@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON + 2938| |value with the default value for a given type + 2939| | + 2940| |@since version 1.0.0 + 2941| |*/ + 2942| |enum class value_t : std::uint8_t + 2943| |{ + 2944| | null, ///< null value + 2945| | object, ///< object (unordered set of name/value pairs) + 2946| | array, ///< array (ordered collection of values) + 2947| | string, ///< string value + 2948| | boolean, ///< boolean value + 2949| | number_integer, ///< number value (signed integer) + 2950| | number_unsigned, ///< number value (unsigned integer) + 2951| | number_float, ///< number value (floating-point) + 2952| | binary, ///< binary array (ordered collection of bytes) + 2953| | discarded ///< discarded by the parser callback function + 2954| |}; + 2955| | + 2956| |/*! + 2957| |@brief comparison operator for JSON types + 2958| | + 2959| |Returns an ordering that is similar to Python: + 2960| |- order: null < boolean < number < object < array < string < binary + 2961| |- furthermore, each type is not smaller than itself + 2962| |- discarded values are not comparable + 2963| |- binary is represented as a b"" string in python and directly comparable to a + 2964| | string; however, making a binary array directly comparable with a string would + 2965| | be surprising behavior in a JSON file. + 2966| | + 2967| |@since version 1.0.0 + 2968| |*/ + 2969| |#if JSON_HAS_THREE_WAY_COMPARISON + 2970| | inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* + 2971| |#else + 2972| | inline bool operator<(const value_t lhs, const value_t rhs) noexcept + 2973| |#endif + 2974| 0|{ + 2975| 0| static constexpr std::array order = {{ + 2976| 0| 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 2977| 0| 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 2978| 0| 6 /* binary */ + 2979| 0| } + 2980| 0| }; + 2981| 0| + 2982| 0| const auto l_index = static_cast(lhs); + 2983| 0| const auto r_index = static_cast(rhs); + 2984| 0|#if JSON_HAS_THREE_WAY_COMPARISON + 2985| 0| if (l_index < order.size() && r_index < order.size()) + 2986| 0| { + 2987| 0| return order[l_index] <=> order[r_index]; // *NOPAD* + 2988| 0| } + 2989| 0| return std::partial_ordering::unordered; + 2990| 0|#else + 2991| 0| return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; + 2992| 0|#endif + 2993| 0|} + 2994| | + 2995| |// GCC selects the built-in operator< over an operator rewritten from + 2996| |// a user-defined spaceship operator + 2997| |// Clang, MSVC, and ICC select the rewritten candidate + 2998| |// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) + 2999| |#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) + 3000| |inline bool operator<(const value_t lhs, const value_t rhs) noexcept + 3001| |{ + 3002| | return std::is_lt(lhs <=> rhs); // *NOPAD* + 3003| |} + 3004| |#endif + 3005| | + 3006| |} // namespace detail + 3007| |NLOHMANN_JSON_NAMESPACE_END + 3008| | + 3009| |// #include + 3010| |// __ _____ _____ _____ + 3011| |// __| | __| | | | JSON for Modern C++ + 3012| |// | | |__ | | | | | | version 3.11.3 + 3013| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 3014| |// + 3015| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 3016| |// SPDX-License-Identifier: MIT + 3017| | + 3018| | + 3019| | + 3020| |// #include + 3021| | + 3022| | + 3023| |NLOHMANN_JSON_NAMESPACE_BEGIN + 3024| |namespace detail + 3025| |{ + 3026| | + 3027| |/*! + 3028| |@brief replace all occurrences of a substring by another string + 3029| | + 3030| |@param[in,out] s the string to manipulate; changed so that all + 3031| | occurrences of @a f are replaced with @a t + 3032| |@param[in] f the substring to replace with @a t + 3033| |@param[in] t the string to replace @a f + 3034| | + 3035| |@pre The search string @a f must not be empty. **This precondition is + 3036| |enforced with an assertion.** + 3037| | + 3038| |@since version 2.0.0 + 3039| |*/ + 3040| |template + 3041| |inline void replace_substring(StringType& s, const StringType& f, + 3042| | const StringType& t) + 3043| 0|{ + 3044| 0| JSON_ASSERT(!f.empty()); + 3045| 0| for (auto pos = s.find(f); // find first occurrence of f + 3046| 0| pos != StringType::npos; // make sure f was found + 3047| 0| s.replace(pos, f.size(), t), // replace with t, and + 3048| 0| pos = s.find(f, pos + t.size())) // find next occurrence of f + 3049| 0| {} + 3050| 0|} + 3051| | + 3052| |/*! + 3053| | * @brief string escaping as described in RFC 6901 (Sect. 4) + 3054| | * @param[in] s string to escape + 3055| | * @return escaped string + 3056| | * + 3057| | * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + 3058| | */ + 3059| |template + 3060| |inline StringType escape(StringType s) + 3061| |{ + 3062| | replace_substring(s, StringType{"~"}, StringType{"~0"}); + 3063| | replace_substring(s, StringType{"/"}, StringType{"~1"}); + 3064| | return s; + 3065| |} + 3066| | + 3067| |/*! + 3068| | * @brief string unescaping as described in RFC 6901 (Sect. 4) + 3069| | * @param[in] s string to unescape + 3070| | * @return unescaped string + 3071| | * + 3072| | * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + 3073| | */ + 3074| |template + 3075| |static void unescape(StringType& s) + 3076| 0|{ + 3077| 0| replace_substring(s, StringType{"~1"}, StringType{"/"}); + 3078| 0| replace_substring(s, StringType{"~0"}, StringType{"~"}); + 3079| 0|} + ------------------ + | Unexecuted instantiation: trading_definitions_json.cpp:_ZN8nlohmann16json_abi_v3_11_36detailL8unescapeINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvRT_ + ------------------ + | Unexecuted instantiation: main.cpp:_ZN8nlohmann16json_abi_v3_11_36detailL8unescapeINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvRT_ + ------------------ + 3080| | + 3081| |} // namespace detail + 3082| |NLOHMANN_JSON_NAMESPACE_END + 3083| | + 3084| |// #include + 3085| |// __ _____ _____ _____ + 3086| |// __| | __| | | | JSON for Modern C++ + 3087| |// | | |__ | | | | | | version 3.11.3 + 3088| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 3089| |// + 3090| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 3091| |// SPDX-License-Identifier: MIT + 3092| | + 3093| | + 3094| | + 3095| |#include // size_t + 3096| | + 3097| |// #include + 3098| | + 3099| | + 3100| |NLOHMANN_JSON_NAMESPACE_BEGIN + 3101| |namespace detail + 3102| |{ + 3103| | + 3104| |/// struct to capture the start position of the current token + 3105| |struct position_t + 3106| |{ + 3107| | /// the total number of characters read + 3108| | std::size_t chars_read_total = 0; + 3109| | /// the number of characters read in the current line + 3110| | std::size_t chars_read_current_line = 0; + 3111| | /// the number of lines read + 3112| | std::size_t lines_read = 0; + 3113| | + 3114| | /// conversion to size_t to preserve SAX interface + 3115| | constexpr operator size_t() const + 3116| 0| { + 3117| 0| return chars_read_total; + 3118| 0| } + 3119| |}; + 3120| | + 3121| |} // namespace detail + 3122| |NLOHMANN_JSON_NAMESPACE_END + 3123| | + 3124| |// #include + 3125| | + 3126| |// #include + 3127| |// __ _____ _____ _____ + 3128| |// __| | __| | | | JSON for Modern C++ + 3129| |// | | |__ | | | | | | version 3.11.3 + 3130| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 3131| |// + 3132| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 3133| |// SPDX-FileCopyrightText: 2018 The Abseil Authors + 3134| |// SPDX-License-Identifier: MIT + 3135| | + 3136| | + 3137| | + 3138| |#include // array + 3139| |#include // size_t + 3140| |#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + 3141| |#include // index_sequence, make_index_sequence, index_sequence_for + 3142| | + 3143| |// #include + 3144| | + 3145| | + 3146| |NLOHMANN_JSON_NAMESPACE_BEGIN + 3147| |namespace detail + 3148| |{ + 3149| | + 3150| |template + 3151| |using uncvref_t = typename std::remove_cv::type>::type; + 3152| | + 3153| |#ifdef JSON_HAS_CPP_14 + 3154| | + 3155| |// the following utilities are natively available in C++14 + 3156| |using std::enable_if_t; + 3157| |using std::index_sequence; + 3158| |using std::make_index_sequence; + 3159| |using std::index_sequence_for; + 3160| | + 3161| |#else + 3162| | + 3163| |// alias templates to reduce boilerplate + 3164| |template + 3165| |using enable_if_t = typename std::enable_if::type; + 3166| | + 3167| |// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h + 3168| |// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + 3169| | + 3170| |//// START OF CODE FROM GOOGLE ABSEIL + 3171| | + 3172| |// integer_sequence + 3173| |// + 3174| |// Class template representing a compile-time integer sequence. An instantiation + 3175| |// of `integer_sequence` has a sequence of integers encoded in its + 3176| |// type through its template arguments (which is a common need when + 3177| |// working with C++11 variadic templates). `absl::integer_sequence` is designed + 3178| |// to be a drop-in replacement for C++14's `std::integer_sequence`. + 3179| |// + 3180| |// Example: + 3181| |// + 3182| |// template< class T, T... Ints > + 3183| |// void user_function(integer_sequence); + 3184| |// + 3185| |// int main() + 3186| |// { + 3187| |// // user_function's `T` will be deduced to `int` and `Ints...` + 3188| |// // will be deduced to `0, 1, 2, 3, 4`. + 3189| |// user_function(make_integer_sequence()); + 3190| |// } + 3191| |template + 3192| |struct integer_sequence + 3193| |{ + 3194| | using value_type = T; + 3195| | static constexpr std::size_t size() noexcept + 3196| | { + 3197| | return sizeof...(Ints); + 3198| | } + 3199| |}; + 3200| | + 3201| |// index_sequence + 3202| |// + 3203| |// A helper template for an `integer_sequence` of `size_t`, + 3204| |// `absl::index_sequence` is designed to be a drop-in replacement for C++14's + 3205| |// `std::index_sequence`. + 3206| |template + 3207| |using index_sequence = integer_sequence; + 3208| | + 3209| |namespace utility_internal + 3210| |{ + 3211| | + 3212| |template + 3213| |struct Extend; + 3214| | + 3215| |// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. + 3216| |template + 3217| |struct Extend, SeqSize, 0> + 3218| |{ + 3219| | using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; + 3220| |}; + 3221| | + 3222| |template + 3223| |struct Extend, SeqSize, 1> + 3224| |{ + 3225| | using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; + 3226| |}; + 3227| | + 3228| |// Recursion helper for 'make_integer_sequence'. + 3229| |// 'Gen::type' is an alias for 'integer_sequence'. + 3230| |template + 3231| |struct Gen + 3232| |{ + 3233| | using type = + 3234| | typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; + 3235| |}; + 3236| | + 3237| |template + 3238| |struct Gen + 3239| |{ + 3240| | using type = integer_sequence; + 3241| |}; + 3242| | + 3243| |} // namespace utility_internal + 3244| | + 3245| |// Compile-time sequences of integers + 3246| | + 3247| |// make_integer_sequence + 3248| |// + 3249| |// This template alias is equivalent to + 3250| |// `integer_sequence`, and is designed to be a drop-in + 3251| |// replacement for C++14's `std::make_integer_sequence`. + 3252| |template + 3253| |using make_integer_sequence = typename utility_internal::Gen::type; + 3254| | + 3255| |// make_index_sequence + 3256| |// + 3257| |// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, + 3258| |// and is designed to be a drop-in replacement for C++14's + 3259| |// `std::make_index_sequence`. + 3260| |template + 3261| |using make_index_sequence = make_integer_sequence; + 3262| | + 3263| |// index_sequence_for + 3264| |// + 3265| |// Converts a typename pack into an index sequence of the same length, and + 3266| |// is designed to be a drop-in replacement for C++14's + 3267| |// `std::index_sequence_for()` + 3268| |template + 3269| |using index_sequence_for = make_index_sequence; + 3270| | + 3271| |//// END OF CODE FROM GOOGLE ABSEIL + 3272| | + 3273| |#endif + 3274| | + 3275| |// dispatch utility (taken from ranges-v3) + 3276| |template struct priority_tag : priority_tag < N - 1 > {}; + 3277| |template<> struct priority_tag<0> {}; + 3278| | + 3279| |// taken from ranges-v3 + 3280| |template + 3281| |struct static_const + 3282| |{ + 3283| | static JSON_INLINE_VARIABLE constexpr T value{}; + 3284| |}; + 3285| | + 3286| |#ifndef JSON_HAS_CPP_17 + 3287| | template + 3288| | constexpr T static_const::value; + 3289| |#endif + 3290| | + 3291| |template + 3292| |constexpr std::array make_array(Args&& ... args) + 3293| |{ + 3294| | return std::array {{static_cast(std::forward(args))...}}; + 3295| |} + 3296| | + 3297| |} // namespace detail + 3298| |NLOHMANN_JSON_NAMESPACE_END + 3299| | + 3300| |// #include + 3301| |// __ _____ _____ _____ + 3302| |// __| | __| | | | JSON for Modern C++ + 3303| |// | | |__ | | | | | | version 3.11.3 + 3304| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 3305| |// + 3306| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 3307| |// SPDX-License-Identifier: MIT + 3308| | + 3309| | + 3310| | + 3311| |#include // numeric_limits + 3312| |#include // char_traits + 3313| |#include // tuple + 3314| |#include // false_type, is_constructible, is_integral, is_same, true_type + 3315| |#include // declval + 3316| | + 3317| |// #include + 3318| |// __ _____ _____ _____ + 3319| |// __| | __| | | | JSON for Modern C++ + 3320| |// | | |__ | | | | | | version 3.11.3 + 3321| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 3322| |// + 3323| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 3324| |// SPDX-License-Identifier: MIT + 3325| | + 3326| | + 3327| | + 3328| |#include // random_access_iterator_tag + 3329| | + 3330| |// #include + 3331| | + 3332| |// #include + 3333| | + 3334| |// #include + 3335| | + 3336| | + 3337| |NLOHMANN_JSON_NAMESPACE_BEGIN + 3338| |namespace detail + 3339| |{ + 3340| | + 3341| |template + 3342| |struct iterator_types {}; + 3343| | + 3344| |template + 3345| |struct iterator_types < + 3346| | It, + 3347| | void_t> + 3349| |{ + 3350| | using difference_type = typename It::difference_type; + 3351| | using value_type = typename It::value_type; + 3352| | using pointer = typename It::pointer; + 3353| | using reference = typename It::reference; + 3354| | using iterator_category = typename It::iterator_category; + 3355| |}; + 3356| | + 3357| |// This is required as some compilers implement std::iterator_traits in a way that + 3358| |// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. + 3359| |template + 3360| |struct iterator_traits + 3361| |{ + 3362| |}; + 3363| | + 3364| |template + 3365| |struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + 3366| | : iterator_types + 3367| |{ + 3368| |}; + 3369| | + 3370| |template + 3371| |struct iterator_traits::value>> + 3372| |{ + 3373| | using iterator_category = std::random_access_iterator_tag; + 3374| | using value_type = T; + 3375| | using difference_type = ptrdiff_t; + 3376| | using pointer = T*; + 3377| | using reference = T&; + 3378| |}; + 3379| | + 3380| |} // namespace detail + 3381| |NLOHMANN_JSON_NAMESPACE_END + 3382| | + 3383| |// #include + 3384| | + 3385| |// #include + 3386| |// __ _____ _____ _____ + 3387| |// __| | __| | | | JSON for Modern C++ + 3388| |// | | |__ | | | | | | version 3.11.3 + 3389| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 3390| |// + 3391| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 3392| |// SPDX-License-Identifier: MIT + 3393| | + 3394| | + 3395| | + 3396| |// #include + 3397| | + 3398| | + 3399| |NLOHMANN_JSON_NAMESPACE_BEGIN + 3400| | + 3401| |NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + 3402| | + 3403| |NLOHMANN_JSON_NAMESPACE_END + 3404| | + 3405| |// #include + 3406| |// __ _____ _____ _____ + 3407| |// __| | __| | | | JSON for Modern C++ + 3408| |// | | |__ | | | | | | version 3.11.3 + 3409| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 3410| |// + 3411| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 3412| |// SPDX-License-Identifier: MIT + 3413| | + 3414| | + 3415| | + 3416| |// #include + 3417| | + 3418| | + 3419| |NLOHMANN_JSON_NAMESPACE_BEGIN + 3420| | + 3421| |NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + 3422| | + 3423| |NLOHMANN_JSON_NAMESPACE_END + 3424| | + 3425| |// #include + 3426| | + 3427| |// #include + 3428| | + 3429| |// #include + 3430| |// __ _____ _____ _____ + 3431| |// __| | __| | | | JSON for Modern C++ + 3432| |// | | |__ | | | | | | version 3.11.3 + 3433| |// |_____|_____|_____|_|___| https://github.com/nlohmann/json + 3434| |// + 3435| |// SPDX-FileCopyrightText: 2013 - 2024 Niels Lohmann + 3436| |// SPDX-License-Identifier: MIT + 3437| | + 3438| |#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ + 3439| | #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + 3440| | + 3441| | #include // int64_t, uint64_t + 3442| | #include // map + 3443| | #include // allocator + 3444| | #include // string + 3445| | #include // vector + 3446| | + 3447| | // #include + 3448| | + 3449| | + 3450| | /*! + 3451| | @brief namespace for Niels Lohmann + 3452| | @see https://github.com/nlohmann + 3453| | @since version 1.0.0 + 3454| | */ + 3455| | NLOHMANN_JSON_NAMESPACE_BEGIN + 3456| | + 3457| | /*! + 3458| | @brief default JSONSerializer template argument + 3459| | + 3460| | This serializer ignores the template arguments and uses ADL + 3461| | ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) + 3462| | for serialization. + 3463| | */ + 3464| | template + 3465| | struct adl_serializer; + 3466| | + 3467| | /// a class to store JSON values + 3468| | /// @sa https://json.nlohmann.me/api/basic_json/ + 3469| | template class ObjectType = + 3470| | std::map, + 3471| | template class ArrayType = std::vector, + 3472| | class StringType = std::string, class BooleanType = bool, + 3473| | class NumberIntegerType = std::int64_t, + 3474| | class NumberUnsignedType = std::uint64_t, + 3475| | class NumberFloatType = double, + 3476| | template class AllocatorType = std::allocator, + 3477| | template class JSONSerializer = + 3478| | adl_serializer, + 3479| | class BinaryType = std::vector, // cppcheck-suppress syntaxError + 3480| | class CustomBaseClass = void> + 3481| | class basic_json; + 3482| | + 3483| | /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document + 3484| | /// @sa https://json.nlohmann.me/api/json_pointer/ + 3485| | template + 3486| | class json_pointer; + 3487| | + 3488| | /*! + 3489| | @brief default specialization + 3490| | @sa https://json.nlohmann.me/api/json/ + 3491| | */ + 3492| | using json = basic_json<>; + 3493| | + 3494| | /// @brief a minimal map-like container that preserves insertion order + 3495| | /// @sa https://json.nlohmann.me/api/ordered_map/ + 3496| | template + 3497| | struct ordered_map; + 3498| | + 3499| | /// @brief specialization that maintains the insertion order of object keys + 3500| | /// @sa https://json.nlohmann.me/api/ordered_json/ + 3501| | using ordered_json = basic_json; + 3502| | + 3503| | NLOHMANN_JSON_NAMESPACE_END + 3504| | + 3505| |#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + 3506| | + 3507| | + 3508| |NLOHMANN_JSON_NAMESPACE_BEGIN + 3509| |/*! + 3510| |@brief detail namespace with internal helper functions + 3511| | + 3512| |This namespace collects functions that should not be exposed, + 3513| |implementations of some @ref basic_json methods, and meta-programming helpers. + 3514| | + 3515| |@since version 2.1.0 + 3516| |*/ + 3517| |namespace detail + 3518| |{ + 3519| | + 3520| |///////////// + 3521| |// helpers // + 3522| |///////////// + 3523| | + 3524| |// Note to maintainers: + 3525| |// + 3526| |// Every trait in this file expects a non CV-qualified type. + 3527| |// The only exceptions are in the 'aliases for detected' section + 3528| |// (i.e. those of the form: decltype(T::member_function(std::declval()))) + 3529| |// + 3530| |// In this case, T has to be properly CV-qualified to constraint the function arguments + 3531| |// (e.g. to_json(BasicJsonType&, const T&)) + 3532| | + 3533| |template struct is_basic_json : std::false_type {}; + 3534| | + 3535| |NLOHMANN_BASIC_JSON_TPL_DECLARATION + 3536| |struct is_basic_json : std::true_type {}; + 3537| | + 3538| |// used by exceptions create() member functions + 3539| |// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t + 3540| |// false_type otherwise + 3541| |template + 3542| |struct is_basic_json_context : + 3543| | std::integral_constant < bool, + 3544| | is_basic_json::type>::type>::value + 3545| | || std::is_same::value > + 3546| |{}; + 3547| | + 3548| |////////////////////// + 3549| |// json_ref helpers // + 3550| |////////////////////// + 3551| | + 3552| |template + 3553| |class json_ref; + 3554| | + 3555| |template + 3556| |struct is_json_ref : std::false_type {}; + 3557| | + 3558| |template + 3559| |struct is_json_ref> : std::true_type {}; + 3560| | + 3561| |////////////////////////// + 3562| |// aliases for detected // + 3563| |////////////////////////// + 3564| | + 3565| |template + 3566| |using mapped_type_t = typename T::mapped_type; + 3567| | + 3568| |template + 3569| |using key_type_t = typename T::key_type; + 3570| | + 3571| |template + 3572| |using value_type_t = typename T::value_type; + 3573| | + 3574| |template + 3575| |using difference_type_t = typename T::difference_type; + 3576| | + 3577| |template + 3578| |using pointer_t = typename T::pointer; + 3579| | + 3580| |template + 3581| |using reference_t = typename T::reference; + 3582| | + 3583| |template + 3584| |using iterator_category_t = typename T::iterator_category; + 3585| | + 3586| |template + 3587| |using to_json_function = decltype(T::to_json(std::declval()...)); + 3588| | + 3589| |template + 3590| |using from_json_function = decltype(T::from_json(std::declval()...)); + 3591| | + 3592| |template + 3593| |using get_template_function = decltype(std::declval().template get()); + 3594| | + 3595| |// trait checking if JSONSerializer::from_json(json const&, udt&) exists + 3596| |template + 3597| |struct has_from_json : std::false_type {}; + 3598| | + 3599| |// trait checking if j.get is valid + 3600| |// use this trait instead of std::is_constructible or std::is_convertible, + 3601| |// both rely on, or make use of implicit conversions, and thus fail when T + 3602| |// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) + 3603| |template + 3604| |struct is_getable + 3605| |{ + 3606| | static constexpr bool value = is_detected::value; + 3607| |}; + 3608| | + 3609| |template + 3610| |struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> + 3611| |{ + 3612| | using serializer = typename BasicJsonType::template json_serializer; + 3613| | + 3614| | static constexpr bool value = + 3615| | is_detected_exact::value; + 3617| |}; + 3618| | + 3619| |// This trait checks if JSONSerializer::from_json(json const&) exists + 3620| |// this overload is used for non-default-constructible user-defined-types + 3621| |template + 3622| |struct has_non_default_from_json : std::false_type {}; + 3623| | + 3624| |template + 3625| |struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> + 3626| |{ + 3627| | using serializer = typename BasicJsonType::template json_serializer; + 3628| | + 3629| | static constexpr bool value = + 3630| | is_detected_exact::value; + 3632| |}; + 3633| | + 3634| |// This trait checks if BasicJsonType::json_serializer::to_json exists + 3635| |// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. + 3636| |template + 3637| |struct has_to_json : std::false_type {}; + 3638| | + 3639| |template + 3640| |struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> + 3641| |{ + 3642| | using serializer = typename BasicJsonType::template json_serializer; + 3643| | + 3644| | static constexpr bool value = + 3645| | is_detected_exact::value; + 3647| |}; + 3648| | + 3649| |template + 3650| |using detect_key_compare = typename T::key_compare; + 3651| | + 3652| |template + 3653| |struct has_key_compare : std::integral_constant::value> {}; + 3654| | + 3655| |// obtains the actual object key comparator + 3656| |template + 3657| |struct actual_object_comparator + 3658| |{ + 3659| | using object_t = typename BasicJsonType::object_t; + 3660| | using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + 3661| | using type = typename std::conditional < has_key_compare::value, + 3662| | typename object_t::key_compare, object_comparator_t>::type; + 3663| |}; + 3664| | + 3665| |template + 3666| |using actual_object_comparator_t = typename actual_object_comparator::type; + 3667| | + 3668| |///////////////// + 3669| |// char_traits // + 3670| |///////////////// + 3671| | + 3672| |// Primary template of char_traits calls std char_traits + 3673| |template + 3674| |struct char_traits : std::char_traits + 3675| |{}; + 3676| | + 3677| |// Explicitly define char traits for unsigned char since it is not standard + 3678| |template<> + 3679| |struct char_traits : std::char_traits + 3680| |{ + 3681| | using char_type = unsigned char; + 3682| | using int_type = uint64_t; + 3683| | + 3684| | // Redefine to_int_type function + 3685| | static int_type to_int_type(char_type c) noexcept + 3686| 0| { + 3687| 0| return static_cast(c); + 3688| 0| } + 3689| | + 3690| | static char_type to_char_type(int_type i) noexcept + 3691| 0| { + 3692| 0| return static_cast(i); + 3693| 0| } + 3694| | + 3695| | static constexpr int_type eof() noexcept + 3696| 0| { + 3697| 0| return static_cast(std::char_traits::eof()); + 3698| 0| } + 3699| |}; + 3700| | + 3701| |// Explicitly define char traits for signed char since it is not standard + 3702| |template<> + 3703| |struct char_traits : std::char_traits + 3704| |{ + 3705| | using char_type = signed char; + 3706| | using int_type = uint64_t; + 3707| | + 3708| | // Redefine to_int_type function + 3709| | static int_type to_int_type(char_type c) noexcept + 3710| 0| { + 3711| 0| return static_cast(c); + 3712| 0| } + 3713| | + 3714| | static char_type to_char_type(int_type i) noexcept + 3715| 0| { + 3716| 0| return static_cast(i); + 3717| 0| } + 3718| | + 3719| | static constexpr int_type eof() noexcept + 3720| 0| { + 3721| 0| return static_cast(std::char_traits::eof()); + 3722| 0| } + 3723| |}; + 3724| | + 3725| |/////////////////// + 3726| |// is_ functions // + 3727| |/////////////////// + 3728| | + 3729| |// https://en.cppreference.com/w/cpp/types/conjunction + 3730| |template struct conjunction : std::true_type { }; + 3731| |template struct conjunction : B { }; + 3732| |template + 3733| |struct conjunction + 3734| |: std::conditional(B::value), conjunction, B>::type {}; + 3735| | + 3736| |// https://en.cppreference.com/w/cpp/types/negation + 3737| |template struct negation : std::integral_constant < bool, !B::value > { }; + 3738| | + 3739| |// Reimplementation of is_constructible and is_default_constructible, due to them being broken for + 3740| |// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). + 3741| |// This causes compile errors in e.g. clang 3.5 or gcc 4.9. + 3742| |template + 3743| |struct is_default_constructible : std::is_default_constructible {}; + 3744| | + 3745| |template + 3746| |struct is_default_constructible> + 3747| | : conjunction, is_default_constructible> {}; + 3748| | + 3749| |template + 3750| |struct is_default_constructible> + 3751| | : conjunction, is_default_constructible> {}; + 3752| | + 3753| |template + 3754| |struct is_default_constructible> + 3755| | : conjunction...> {}; + 3756| | + 3757| |template + 3758| |struct is_default_constructible> + 3759| | : conjunction...> {}; + 3760| | + 3761| |template + 3762| |struct is_constructible : std::is_constructible {}; + 3763| | + 3764| |template + 3765| |struct is_constructible> : is_default_constructible> {}; + 3766| | + 3767| |template + 3768| |struct is_constructible> : is_default_constructible> {}; + 3769| | + 3770| |template + 3771| |struct is_constructible> : is_default_constructible> {}; + 3772| | + 3773| |template + 3774| |struct is_constructible> : is_default_constructible> {}; + 3775| | + 3776| |template + 3777| |struct is_iterator_traits : std::false_type {}; + 3778| | + 3779| |template + 3780| |struct is_iterator_traits> + 3781| |{ + 3782| | private: + 3783| | using traits = iterator_traits; + 3784| | + 3785| | public: + 3786| | static constexpr auto value = + 3787| | is_detected::value && + 3788| | is_detected::value && + 3789| | is_detected::value && + 3790| | is_detected::value && + 3791| | is_detected::value; + 3792| |}; + 3793| | + 3794| |template + 3795| |struct is_range + 3796| |{ + 3797| | private: + 3798| | using t_ref = typename std::add_lvalue_reference::type; + 3799| | + 3800| | using iterator = detected_t; + 3801| | using sentinel = detected_t; + 3802| | + 3803| | // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + 3804| | // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + 3805| | // but reimplementing these would be too much work, as a lot of other concepts are used underneath + 3806| | static constexpr auto is_iterator_begin = + 3807| | is_iterator_traits>::value; + 3808| | + 3809| | public: + 3810| | static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; + 3811| |}; + 3812| | + 3813| |template + 3814| |using iterator_t = enable_if_t::value, result_of_begin())>>; + 3815| | + 3816| |template + 3817| |using range_value_t = value_type_t>>; + 3818| | + 3819| |// The following implementation of is_complete_type is taken from + 3820| |// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ + 3821| |// and is written by Xiang Fan who agreed to using it in this library. + 3822| | + 3823| |template + 3824| |struct is_complete_type : std::false_type {}; + 3825| | + 3826| |template + 3827| |struct is_complete_type : std::true_type {}; + 3828| | + 3829| |template + 3831| |struct is_compatible_object_type_impl : std::false_type {}; + 3832| | + 3833| |template + 3834| |struct is_compatible_object_type_impl < + 3835| | BasicJsonType, CompatibleObjectType, + 3836| | enable_if_t < is_detected::value&& + 3837| | is_detected::value >> + 3838| |{ + 3839| | using object_t = typename BasicJsonType::object_t; + 3840| | + 3841| | // macOS's is_constructible does not play well with nonesuch... + 3842| | static constexpr bool value = + 3843| | is_constructible::value && + 3845| | is_constructible::value; + 3847| |}; + 3848| | + 3849| |template + 3850| |struct is_compatible_object_type + 3851| | : is_compatible_object_type_impl {}; + 3852| | + 3853| |template + 3855| |struct is_constructible_object_type_impl : std::false_type {}; + 3856| | + 3857| |template + 3858| |struct is_constructible_object_type_impl < + 3859| | BasicJsonType, ConstructibleObjectType, + 3860| | enable_if_t < is_detected::value&& + 3861| | is_detected::value >> + 3862| |{ + 3863| | using object_t = typename BasicJsonType::object_t; + 3864| | + 3865| | static constexpr bool value = + 3866| | (is_default_constructible::value && + 3867| | (std::is_move_assignable::value || + 3868| | std::is_copy_assignable::value) && + 3869| | (is_constructible::value && + 3871| | std::is_same < + 3872| | typename object_t::mapped_type, + 3873| | typename ConstructibleObjectType::mapped_type >::value)) || + 3874| | (has_from_json::value || + 3876| | has_non_default_from_json < + 3877| | BasicJsonType, + 3878| | typename ConstructibleObjectType::mapped_type >::value); + 3879| |}; + 3880| | + 3881| |template + 3882| |struct is_constructible_object_type + 3883| | : is_constructible_object_type_impl {}; + 3885| | + 3886| |template + 3887| |struct is_compatible_string_type + 3888| |{ + 3889| | static constexpr auto value = + 3890| | is_constructible::value; + 3891| |}; + 3892| | + 3893| |template + 3894| |struct is_constructible_string_type + 3895| |{ + 3896| | // launder type through decltype() to fix compilation failure on ICPC + 3897| |#ifdef __INTEL_COMPILER + 3898| | using laundered_type = decltype(std::declval()); + 3899| |#else + 3900| | using laundered_type = ConstructibleStringType; + 3901| |#endif + 3902| | + 3903| | static constexpr auto value = + 3904| | conjunction < + 3905| | is_constructible, + 3906| | is_detected_exact>::value; + 3908| |}; + 3909| | + 3910| |template + 3911| |struct is_compatible_array_type_impl : std::false_type {}; + 3912| | + 3913| |template + 3914| |struct is_compatible_array_type_impl < + 3915| | BasicJsonType, CompatibleArrayType, + 3916| | enable_if_t < + 3917| | is_detected::value&& + 3918| | is_iterator_traits>>::value&& + 3919| |// special case for types like std::filesystem::path whose iterator's value_type are themselves + 3920| |// c.f. https://github.com/nlohmann/json/pull/3073 + 3921| | !std::is_same>::value >> + 3922| |{ + 3923| | static constexpr bool value = + 3924| | is_constructible>::value; + 3926| |}; + 3927| | + 3928| |template + 3929| |struct is_compatible_array_type + 3930| | : is_compatible_array_type_impl {}; + 3931| | + 3932| |template + 3933| |struct is_constructible_array_type_impl : std::false_type {}; + 3934| | + 3935| |template + 3936| |struct is_constructible_array_type_impl < + 3937| | BasicJsonType, ConstructibleArrayType, + 3938| | enable_if_t::value >> + 3940| | : std::true_type {}; + 3941| | + 3942| |template + 3943| |struct is_constructible_array_type_impl < + 3944| | BasicJsonType, ConstructibleArrayType, + 3945| | enable_if_t < !std::is_same::value&& + 3947| | !is_compatible_string_type::value&& + 3948| | is_default_constructible::value&& + 3949| |(std::is_move_assignable::value || + 3950| | std::is_copy_assignable::value)&& + 3951| |is_detected::value&& + 3952| |is_iterator_traits>>::value&& + 3953| |is_detected::value&& + 3954| |// special case for types like std::filesystem::path whose iterator's value_type are themselves + 3955| |// c.f. https://github.com/nlohmann/json/pull/3073 + 3956| |!std::is_same>::value&& + 3957| |is_complete_type < + 3958| |detected_t>::value >> + 3959| |{ + 3960| | using value_type = range_value_t; + 3961| | + 3962| | static constexpr bool value = + 3963| | std::is_same::value || + 3965| | has_from_json::value || + 3967| | has_non_default_from_json < + 3968| | BasicJsonType, + 3969| | value_type >::value; + 3970| |}; + 3971| | + 3972| |template + 3973| |struct is_constructible_array_type + 3974| | : is_constructible_array_type_impl {}; + 3975| | + 3976| |template + 3978| |struct is_compatible_integer_type_impl : std::false_type {}; + 3979| | + 3980| |template + 3981| |struct is_compatible_integer_type_impl < + 3982| | RealIntegerType, CompatibleNumberIntegerType, + 3983| | enable_if_t < std::is_integral::value&& + 3984| | std::is_integral::value&& + 3985| | !std::is_same::value >> + 3986| |{ + 3987| | // is there an assert somewhere on overflows? + 3988| | using RealLimits = std::numeric_limits; + 3989| | using CompatibleLimits = std::numeric_limits; + 3990| | + 3991| | static constexpr auto value = + 3992| | is_constructible::value && + 3994| | CompatibleLimits::is_integer && + 3995| | RealLimits::is_signed == CompatibleLimits::is_signed; + 3996| |}; + 3997| | + 3998| |template + 3999| |struct is_compatible_integer_type + 4000| | : is_compatible_integer_type_impl {}; + 4002| | + 4003| |template + 4004| |struct is_compatible_type_impl: std::false_type {}; + 4005| | + 4006| |template + 4007| |struct is_compatible_type_impl < + 4008| | BasicJsonType, CompatibleType, + 4009| | enable_if_t::value >> + 4010| |{ + 4011| | static constexpr bool value = + 4012| | has_to_json::value; + 4013| |}; + 4014| | + 4015| |template + 4016| |struct is_compatible_type + 4017| | : is_compatible_type_impl {}; + 4018| | + 4019| |template + 4020| |struct is_constructible_tuple : std::false_type {}; + 4021| | + 4022| |template + 4023| |struct is_constructible_tuple> : conjunction...> {}; + 4024| | + 4025| |template + 4026| |struct is_json_iterator_of : std::false_type {}; + 4027| | + 4028| |template + 4029| |struct is_json_iterator_of : std::true_type {}; + 4030| | + 4031| |template + 4032| |struct is_json_iterator_of : std::true_type + 4033| |{}; + 4034| | + 4035| |// checks if a given type T is a template specialization of Primary + 4036| |template