diff --git a/.github/workflows/cpp.yml b/.github/workflows/cpp.yml new file mode 100644 index 0000000..bcef4b5 --- /dev/null +++ b/.github/workflows/cpp.yml @@ -0,0 +1,81 @@ +name: cpp + +on: + push: + branches: main + paths: + - 'cpp/**' + - '.github/workflows/cpp.yml' + pull_request: + paths: + - 'cpp/**' + - '.github/workflows/cpp.yml' + +defaults: + run: + working-directory: cpp + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + compiler: [gcc-11, clang-12] + include: + - compiler: gcc-11 + cc: gcc-11 + cxx: g++-11 + - compiler: clang-12 + cc: clang-12 + cxx: clang++-12 + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake ninja-build + sudo apt-get install -y gcc-11 g++-11 clang-12 + + - name: Setup Conan + run: | + pip install conan==1.59.0 + conan profile new default --detect + conan profile update settings.compiler.libcxx=libstdc++11 default + conan remote add linksplatform https://linksplatform.jfrog.io/artifactory/api/conan/linksplatform || true + + - name: Create build directory + run: mkdir -p build + + - name: Install Conan dependencies + run: | + cd build + conan install .. --build=missing + env: + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + - name: Configure CMake + run: | + cd build + cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release + env: + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + - name: Build + run: | + cd build + ninja + env: + CC: ${{ matrix.cc }} + CXX: ${{ matrix.cxx }} + + - name: Test run (basic smoke test) + run: | + cd build + timeout 30s ./bin/Examples.Doublets.CRUD.Cpp || true + echo "Build completed successfully" \ No newline at end of file diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt new file mode 100644 index 0000000..27be7a0 --- /dev/null +++ b/cpp/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 3.13) + +project(Examples.Doublets.CRUD.Cpp CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Set output directory +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +# Add conan packages if available +if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/conanbuildinfo.cmake") + include(${CMAKE_CURRENT_BINARY_DIR}/conanbuildinfo.cmake) + conan_basic_setup() +endif() + +# Find required packages +find_package(Platform.Interfaces) +find_package(Platform.Collections.Methods) +find_package(Platform.Collections) +find_package(Platform.Numbers) +find_package(Platform.Memory) +find_package(Platform.Exceptions) +find_package(Platform.Data) +find_package(Platform.Setters) +find_package(Platform.Ranges) +find_package(mio) + +# Create the executable +add_executable(${PROJECT_NAME} main.cpp) + +# Set C++20 standard +set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20) + +# Link required libraries +target_link_libraries(${PROJECT_NAME} PRIVATE Platform.Interfaces::Platform.Interfaces) +target_link_libraries(${PROJECT_NAME} PRIVATE Platform.Collections.Methods::Platform.Collections.Methods) +target_link_libraries(${PROJECT_NAME} PRIVATE Platform.Collections::Platform.Collections) +target_link_libraries(${PROJECT_NAME} PRIVATE Platform.Numbers::Platform.Numbers) +target_link_libraries(${PROJECT_NAME} PRIVATE Platform.Memory::Platform.Memory) +target_link_libraries(${PROJECT_NAME} PRIVATE Platform.Exceptions::Platform.Exceptions) +target_link_libraries(${PROJECT_NAME} PRIVATE Platform.Data::Platform.Data) +target_link_libraries(${PROJECT_NAME} PRIVATE Platform.Setters::Platform.Setters) +target_link_libraries(${PROJECT_NAME} PRIVATE Platform.Ranges::Platform.Ranges) +target_link_libraries(${PROJECT_NAME} PRIVATE mio::mio) + +# Add additional linker libraries +target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_DL_LIBS}) + +# Include the Platform.Data.Doublets headers if available locally +# This assumes the Platform.Data.Doublets repository is available +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../Platform.Data.Doublets") + target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../Platform.Data.Doublets/cpp) +endif() \ No newline at end of file diff --git a/cpp/README.md b/cpp/README.md new file mode 100644 index 0000000..a69b61d --- /dev/null +++ b/cpp/README.md @@ -0,0 +1,121 @@ +[![Actions Status](https://github.com/linksplatform/Examples.Doublets.CRUD/workflows/CI/badge.svg)](https://github.com/linksplatform/Examples.Doublets.CRUD/actions?workflow=CI) + +# Examples.Doublets.CRUD.Cpp + +A quick start example that shows how to create, read, update and delete the first [link](https://github.com/Konard/LinksPlatform/wiki/FAQ#what-does-the-link-mean) using [Doublets](https://github.com/linksplatform/Data.Doublets) in C++. + +## Prerequisites +* Linux, macOS or Windows +* [CMake 3.13+](https://cmake.org/download/) +* C++20 compatible compiler (GCC 10+, Clang 10+, or MSVC 19.29+) +* [Conan package manager](https://conan.io/downloads.html) (optional but recommended) +* [Platform.Data.Doublets](https://github.com/linksplatform/Data.Doublets) library + +## Building + +### Using Conan (Recommended) + +```bash +mkdir build && cd build +conan install .. --build=missing +cmake .. +cmake --build . +``` + +### Using CMake directly + +If you have the Platform.Data.Doublets repository cloned locally: + +```bash +mkdir build && cd build +cmake .. +cmake --build . +``` + +## Running + +After building, run the executable: + +```bash +./bin/Examples.Doublets.CRUD.Cpp +``` + +## [The code](https://github.com/linksplatform/Examples.Doublets.CRUD/blob/main/cpp/main.cpp) + +```cpp +#include +#include +#include +#include + +using namespace Platform::Data::Doublets; +using namespace Platform::Data::Doublets::Memory::United::Generic; +using namespace Platform::Memory; +using namespace Platform::Interfaces; + +int main() { + try { + // A doublet links store is mapped to the "db.links" file: + using TLinkAddress = std::uint64_t; + using LinksOptionsType = LinksOptions; + + FileMappedResizableDirectMemory memory{"db.links"}; + UnitedMemoryLinks links{std::move(memory)}; + + // Creating a doublet link: + auto link = Create(links); + + // The link is updated to reference itself twice (as a source and as a target): + // The passed arguments are: an updated address, a new source, and a new target + link = Update(links, link, link, link); + + // Read operations: + std::cout << "The number of links in the data store is " << Count(links) << "." << std::endl; + std::cout << "Data store contents:" << std::endl; + + // Means any link address or that there is no restriction on link address + const auto any = links.Constants.Any; + + // The arguments of a query are restrictions: on address, on source, on target + typename UnitedMemoryLinks::LinkType query{any, any, any}; + + links.Each(query, [&links](const auto& foundLink) -> TLinkAddress { + std::cout << "(" << foundLink.Index << ": " << foundLink.Source << " " << foundLink.Target << ")" << std::endl; + return links.Constants.Continue; + }); + + // Cleaning (resetting) the contents of the link: + link = Update(links, link, TLinkAddress{0}, TLinkAddress{0}); + + // Removing the link + Delete(links, link); + + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } catch (...) { + std::cerr << "Unknown error occurred" << std::endl; + return 1; + } + + return 0; +} +``` + +The expected output is: + +``` +The number of links in the data store is 1. +Data store contents: +(1: 1 1) +``` + +Look at [Platform.Data.Doublets C++ documentation](https://github.com/linksplatform/Data.Doublets/tree/main/cpp) for more details. + +## Looking for something more interesting? +* [Comparison between SQLite and Doublets](https://github.com/linksplatform/Comparisons.SQLiteVSDoublets) +* [Search engine with its web crawler, that stores web-pages in the Doublets](https://github.com/linksplatform/Crawler) +* [GraphQL server that uses Doublets as the database behind the universal API](https://github.com/linksplatform/Data.Doublets.GraphQL) +* [GitHub bot that uses Doublets as the dababase for file templates](https://github.com/linksplatform/Bot) +* [JSON to Doublets importer and Doublets to JSON exporter](https://github.com/linksplatform/Data.Doublets.Json) +* [XML to Doublets importer and Doublets to XML exporter](https://github.com/linksplatform/Data.Doublets.Xml) \ No newline at end of file diff --git a/cpp/conanfile.txt b/cpp/conanfile.txt new file mode 100644 index 0000000..e1fb3b4 --- /dev/null +++ b/cpp/conanfile.txt @@ -0,0 +1,14 @@ +[requires] +platform.interfaces/0.3.7@linksplatform/stable +platform.collections.methods/0.1.5@linksplatform/stable +platform.collections/0.0.5@linksplatform/stable +platform.numbers/0.2.0@linksplatform/stable +platform.memory/0.5.2@linksplatform/stable +platform.exceptions/0.4.2@linksplatform/stable +platform.data/0.4.4@linksplatform/stable +platform.setters/0.0.4@linksplatform/stable +platform.ranges/0.1.3@linksplatform/stable +mio/0.0.1@linksplatform/stable + +[generators] +cmake \ No newline at end of file diff --git a/cpp/main.cpp b/cpp/main.cpp new file mode 100644 index 0000000..5e35d41 --- /dev/null +++ b/cpp/main.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +#include + +using namespace Platform::Data::Doublets; +using namespace Platform::Data::Doublets::Memory::United::Generic; +using namespace Platform::Memory; +using namespace Platform::Interfaces; + +int main() { + try { + // A doublet links store is mapped to the "db.links" file: + using TLinkAddress = std::uint64_t; + using LinksOptionsType = LinksOptions; + + FileMappedResizableDirectMemory memory{"db.links"}; + UnitedMemoryLinks links{std::move(memory)}; + + // Creating a doublet link: + auto link = Create(links); + + // The link is updated to reference itself twice (as a source and as a target): + // The passed arguments are: an updated address, a new source, and a new target + link = Update(links, link, link, link); + + // Read operations: + std::cout << "The number of links in the data store is " << Count(links) << "." << std::endl; + std::cout << "Data store contents:" << std::endl; + + // Means any link address or that there is no restriction on link address + const auto any = links.Constants.Any; + + // The arguments of a query are restrictions: on address, on source, on target + typename UnitedMemoryLinks::LinkType query{any, any, any}; + + links.Each(query, [&links](const auto& foundLink) -> TLinkAddress { + std::cout << "(" << foundLink.Index << ": " << foundLink.Source << " " << foundLink.Target << ")" << std::endl; + return links.Constants.Continue; + }); + + // Cleaning (resetting) the contents of the link: + link = Update(links, link, TLinkAddress{0}, TLinkAddress{0}); + + // Removing the link + Delete(links, link); + + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } catch (...) { + std::cerr << "Unknown error occurred" << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file