├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE │ └── pull_request_template.md └── workflows │ ├── detect-pobr-diff.yml │ ├── publish-conan-branch-package.yml │ ├── publish-release.yml │ ├── reusable_packaging_and_deployment.yml │ ├── reusable_run_test_and_examples.yml │ ├── reusable_run_test_and_examples_by_linking_type.yml │ ├── run_test_and_examples.yml │ ├── run_test_for_coverage.yml │ ├── sonarqube.yml │ └── test_packaging_and_deployment.yml ├── .gitignore ├── .readthedocs.yaml ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Doxyfile ├── LICENSE ├── README.md ├── cmake ├── boilerplate_init.cmake ├── conan_cmake.cmake ├── install_library.cmake ├── lib-config.cmake.in └── version.hpp.in ├── conanfile.py ├── docs ├── Makefile ├── requirements.txt └── source │ ├── conf.py │ ├── examples.rst │ ├── getting_started.rst │ ├── index.rst │ ├── t_NodeBackendHandle.rst │ ├── t_datatype_registry.rst │ ├── t_node_storage.rst │ ├── t_node_storage_view.rst │ ├── t_storage.rst │ ├── technical.rst │ └── users_guide.rst ├── examples ├── CMakeLists.txt ├── RDFFileParser_example.cpp ├── RDFFileParser_simple.ttl ├── blank_node_management.cpp ├── getting_started.cpp ├── graphs_and_datasets.cpp ├── literal_datatypes.cpp ├── namespaces.cpp ├── rdf_format_checker.cpp └── rdf_nodes.cpp ├── private └── rdf4cpp │ ├── parser │ ├── IStreamQuadIteratorSerdImpl.cpp │ └── IStreamQuadIteratorSerdImpl.hpp │ ├── regex │ ├── RegexImpl.cpp │ ├── RegexImpl.hpp │ ├── RegexReplacerImpl.cpp │ └── RegexReplacerImpl.hpp │ └── writer │ ├── OutputFormat.hpp │ ├── Prefixes.hpp │ ├── TryWrite.hpp │ └── WriteQuad.hpp ├── sonar-project.properties ├── src ├── rdf4cpp.hpp └── rdf4cpp │ ├── BigDecimal.hpp │ ├── BlankNode.cpp │ ├── BlankNode.hpp │ ├── ClosedNamespace.cpp │ ├── ClosedNamespace.hpp │ ├── CowString.hpp │ ├── Dataset.cpp │ ├── Dataset.hpp │ ├── Expected.hpp │ ├── Graph.cpp │ ├── Graph.hpp │ ├── IRI.cpp │ ├── IRI.hpp │ ├── IRIFactory.cpp │ ├── IRIFactory.hpp │ ├── IRIView.cpp │ ├── IRIView.hpp │ ├── InvalidNode.hpp │ ├── Literal.cpp │ ├── Literal.hpp │ ├── Namespace.cpp │ ├── Namespace.hpp │ ├── Node.cpp │ ├── Node.hpp │ ├── Quad.cpp │ ├── Quad.hpp │ ├── Statement.cpp │ ├── Statement.hpp │ ├── Timezone.hpp │ ├── TriBool.hpp │ ├── bnode_mngt │ ├── NodeGenerator.hpp │ ├── NodeScope.hpp │ ├── NodeScopeManager.hpp │ └── reference_backends │ │ ├── generator │ │ ├── IncreasingIdGenerator.cpp │ │ ├── IncreasingIdGenerator.hpp │ │ ├── RandomIdGenerator.cpp │ │ └── RandomIdGenerator.hpp │ │ ├── scope │ │ └── ReferenceNodeScope.hpp │ │ └── scope_manager │ │ ├── MergeNodeScopeManager.hpp │ │ └── UnionNodeScopeManager.hpp │ ├── datatypes │ ├── LiteralDatatype.hpp │ ├── owl.hpp │ ├── owl │ │ ├── Rational.cpp │ │ ├── Rational.hpp │ │ ├── Real.cpp │ │ └── Real.hpp │ ├── rdf.hpp │ ├── rdf │ │ ├── LangString.cpp │ │ └── LangString.hpp │ ├── registry │ │ ├── DatatypeConversion.hpp │ │ ├── DatatypeConversionTyping.hpp │ │ ├── DatatypeID.hpp │ │ ├── DatatypeMapping.hpp │ │ ├── DatatypeRegistry.cpp │ │ ├── DatatypeRegistry.hpp │ │ ├── FixedIdMappings.hpp │ │ ├── LiteralDatatypeImpl.hpp │ │ ├── README.md │ │ └── util │ │ │ ├── CharConvExt.hpp │ │ │ ├── ConstexprString.hpp │ │ │ ├── DateTimeUtils.hpp │ │ │ ├── Inlining.hpp │ │ │ ├── StaticFlatMap.hpp │ │ │ ├── TypeList.hpp │ │ │ └── mz │ │ │ ├── LICENSE │ │ │ └── type_list.hpp │ ├── xsd.hpp │ └── xsd │ │ ├── AnyURI.cpp │ │ ├── AnyURI.hpp │ │ ├── Base64Binary.cpp │ │ ├── Base64Binary.hpp │ │ ├── Boolean.cpp │ │ ├── Boolean.hpp │ │ ├── Decimal.cpp │ │ ├── Decimal.hpp │ │ ├── Double.cpp │ │ ├── Double.hpp │ │ ├── Float.cpp │ │ ├── Float.hpp │ │ ├── HexBinary.cpp │ │ ├── HexBinary.hpp │ │ ├── String.cpp │ │ ├── String.hpp │ │ ├── integers │ │ ├── non_negative │ │ │ ├── NonNegativeInteger.cpp │ │ │ ├── NonNegativeInteger.hpp │ │ │ ├── PositiveInteger.cpp │ │ │ ├── PositiveInteger.hpp │ │ │ ├── UnsignedByte.cpp │ │ │ ├── UnsignedByte.hpp │ │ │ ├── UnsignedInt.cpp │ │ │ ├── UnsignedInt.hpp │ │ │ ├── UnsignedLong.cpp │ │ │ ├── UnsignedLong.hpp │ │ │ ├── UnsignedShort.cpp │ │ │ └── UnsignedShort.hpp │ │ ├── non_positive │ │ │ ├── NegativeInteger.cpp │ │ │ ├── NegativeInteger.hpp │ │ │ ├── NonPositiveInteger.cpp │ │ │ └── NonPositiveInteger.hpp │ │ └── signed │ │ │ ├── Byte.cpp │ │ │ ├── Byte.hpp │ │ │ ├── Int.cpp │ │ │ ├── Int.hpp │ │ │ ├── Integer.cpp │ │ │ ├── Integer.hpp │ │ │ ├── Long.cpp │ │ │ ├── Long.hpp │ │ │ ├── Short.cpp │ │ │ └── Short.hpp │ │ └── time │ │ ├── Date.cpp │ │ ├── Date.hpp │ │ ├── DateTime.cpp │ │ ├── DateTime.hpp │ │ ├── DateTimeStamp.cpp │ │ ├── DateTimeStamp.hpp │ │ ├── Day.cpp │ │ ├── Day.hpp │ │ ├── DayTimeDuration.cpp │ │ ├── DayTimeDuration.hpp │ │ ├── Duration.cpp │ │ ├── Duration.hpp │ │ ├── Month.cpp │ │ ├── Month.hpp │ │ ├── MonthDay.cpp │ │ ├── MonthDay.hpp │ │ ├── Time.cpp │ │ ├── Time.hpp │ │ ├── Year.cpp │ │ ├── Year.hpp │ │ ├── YearMonth.cpp │ │ ├── YearMonth.hpp │ │ ├── YearMonthDuration.cpp │ │ └── YearMonthDuration.hpp │ ├── namespaces.hpp │ ├── namespaces │ ├── BFLC.hpp │ ├── FOAF.hpp │ ├── MADSRDF.hpp │ ├── OWL.hpp │ ├── PREMIS3.hpp │ ├── RDF.cpp │ ├── RDF.hpp │ ├── RDFS.hpp │ └── XSD.hpp │ ├── parser │ ├── IStreamQuadIterator.cpp │ ├── IStreamQuadIterator.hpp │ ├── ParsingError.hpp │ ├── ParsingFlags.hpp │ ├── ParsingState.hpp │ ├── RDFFileParser.cpp │ └── RDFFileParser.hpp │ ├── query │ ├── QuadPattern.cpp │ ├── QuadPattern.hpp │ ├── Solution.cpp │ ├── Solution.hpp │ ├── TriplePattern.cpp │ ├── TriplePattern.hpp │ ├── Variable.cpp │ └── Variable.hpp │ ├── regex │ ├── Regex.cpp │ ├── Regex.hpp │ ├── RegexError.hpp │ ├── RegexFlags.hpp │ ├── RegexReplacer.cpp │ └── RegexReplacer.hpp │ ├── storage │ ├── NodeStorage.cpp │ ├── NodeStorage.hpp │ ├── README.md │ ├── identifier │ │ ├── LiteralID.hpp │ │ ├── LiteralType.hpp │ │ ├── NodeBackendHandle.hpp │ │ ├── NodeBackendID.hpp │ │ ├── NodeID.hpp │ │ ├── RDFNodeType.hpp │ │ └── README.md │ ├── reference_node_storage │ │ ├── BNodeBackend.hpp │ │ ├── FallbackLiteralBackend.hpp │ │ ├── IRIBackend.hpp │ │ ├── SpecializedLiteralBackend.hpp │ │ ├── SyncReferenceNodeStorage.cpp │ │ ├── SyncReferenceNodeStorage.hpp │ │ ├── UnsyncReferenceNodeStorage.cpp │ │ ├── UnsyncReferenceNodeStorage.hpp │ │ ├── VariableBackend.hpp │ │ └── detail │ │ │ ├── BiDirFlatMap.hpp │ │ │ ├── IndexFreeList.hpp │ │ │ ├── SpecializationDetail.hpp │ │ │ ├── SyncNodeTypeStorage.hpp │ │ │ └── UnsyncNodeTypeStorage.hpp │ └── view │ │ ├── BNodeBackendView.cpp │ │ ├── BNodeBackendView.hpp │ │ ├── IRIBackendView.cpp │ │ ├── IRIBackendView.hpp │ │ ├── LiteralBackendView.cpp │ │ ├── LiteralBackendView.hpp │ │ ├── README.md │ │ ├── VariableBackendView.cpp │ │ └── VariableBackendView.hpp │ ├── util │ ├── CaseInsensitiveCharTraits.hpp │ ├── CharMatcher.cpp │ ├── CharMatcher.hpp │ └── CheckedInt.hpp │ └── writer │ ├── BufWriter.hpp │ ├── SerializationState.cpp │ └── SerializationState.hpp ├── test_FetchContent ├── CMakeLists.txt └── src │ └── test_FetchContent.cpp ├── test_package ├── CMakeLists.txt ├── conanfile.py └── example.cpp └── tests ├── CMakeLists.txt ├── bench_SerDe.cpp ├── datatype ├── tests_AnyURI.cpp ├── tests_Base64Binary.cpp ├── tests_Boolean.cpp ├── tests_Byte.cpp ├── tests_Decimal.cpp ├── tests_Double.cpp ├── tests_Float.cpp ├── tests_HexBinary.cpp ├── tests_Int.cpp ├── tests_Integer.cpp ├── tests_LangString.cpp ├── tests_Long.cpp ├── tests_NegativeInteger.cpp ├── tests_NonNegativeInteger.cpp ├── tests_NonPositiveInteger.cpp ├── tests_NumOpResults.cpp ├── tests_PositiveInteger.cpp ├── tests_Short.cpp ├── tests_String.cpp ├── tests_UnsignedByte.cpp ├── tests_UnsignedInt.cpp ├── tests_UnsignedLong.cpp ├── tests_UnsignedShort.cpp ├── tests_owl_Rational.cpp └── tests_time_types.cpp ├── graph ├── tests_dataset.cpp ├── tests_loading.cpp └── tests_loading_simple.trig ├── namespaces └── tests_Namespace.cpp ├── nodes ├── tests_DBpediaMode.cpp ├── tests_IRIFactory.cpp ├── tests_Literal.cpp ├── tests_Literal_ops.cpp ├── tests_Node.cpp ├── tests_NodeStorage_helper_types.cpp ├── tests_NodeStorage_ids.cpp └── tests_NodeStorage_specialization.cpp ├── parser ├── tests_IStreamQuadIterator.cpp ├── tests_RDFFileParser.cpp └── tests_RDFFileParser_simple.ttl ├── query ├── tests_QuadPattern.cpp ├── tests_TriplePattern.cpp └── tests_Variable.cpp ├── serializer ├── tests_Serialization.cpp └── tests_Serialize.cpp └── util ├── tests_BigDecimal.cpp ├── tests_BlankNodeIdManagement.cpp ├── tests_CowString.cpp ├── tests_Inlining.cpp ├── tests_Regex.cpp └── tests_TriBool.cpp /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | 16 | # How Has This Been Tested? 17 | 18 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration 19 | 20 | - [ ] Test A 21 | - [ ] Test B 22 | 23 | **Test Configuration**: 24 | * Firmware version: 25 | * Hardware: 26 | * Toolchain: 27 | * SDK: 28 | 29 | # Checklist: 30 | 31 | - [ ] My code follows the style guidelines of this project 32 | - [ ] I have performed a self-review of my own code 33 | - [ ] I have commented my code, particularly in hard-to-understand areas 34 | - [ ] I have made corresponding changes to the documentation 35 | - [ ] My changes generate no new warnings 36 | - [ ] I have added tests that prove my fix is effective or that my feature works 37 | - [ ] New and existing unit tests pass locally with my changes 38 | - [ ] Any dependent changes have been merged and published in downstream modules 39 | 40 | 41 | 42 | # Credits 43 | 44 | This template is based on https://github.com/embeddedartistry/templates/blob/master/oss_docs/PULL_REQUEST_TEMPLATE.md 45 | -------------------------------------------------------------------------------- /.github/workflows/detect-pobr-diff.yml: -------------------------------------------------------------------------------- 1 | name: Detect POBR diff 2 | 3 | on: [ pull_request ] 4 | 5 | concurrency: 6 | group: detect-pobr-diff-${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | jobs: 10 | detect-pobr-diff: 11 | uses: dice-group/cpp-conan-release-reusable-workflow/.github/workflows/abi-diff.yml@main 12 | with: 13 | os: ubuntu-24.04 14 | compiler: clang-20 15 | cmake-version: 3.24.0 16 | conan-version: 2.17.0 17 | base-branch: ${{ github.base_ref }} 18 | search-path: > 19 | src/rdf4cpp/storage/identifier 20 | src/rdf4cpp/storage/view 21 | src/rdf4cpp/storage/reference_node_storage/detail/BiDirFlatMap.hpp 22 | src/rdf4cpp/storage/reference_node_storage/detail/ConstString.hpp 23 | src/rdf4cpp/storage/reference_node_storage/detail/IndexFreeList.hpp 24 | abi-version-header: src/rdf4cpp/version.hpp 25 | abi-version-const: rdf4cpp::pobr_version 26 | secrets: 27 | CONAN_USER: ${{ secrets.CONAN_USER }} 28 | CONAN_PW: ${{ secrets.CONAN_PW }} 29 | -------------------------------------------------------------------------------- /.github/workflows/publish-conan-branch-package.yml: -------------------------------------------------------------------------------- 1 | name: Publish Conan branch package 2 | on: [ push ] 3 | 4 | concurrency: 5 | group: publish-conan-branch-package-${{ github.workflow }}-${{ github.ref }} 6 | cancel-in-progress: true 7 | 8 | jobs: 9 | publish-release: 10 | uses: dice-group/cpp-conan-release-reusable-workflow/.github/workflows/publish-conan-branch-package.yml@main 11 | with: 12 | public_artifactory: true 13 | os: ubuntu-24.04 14 | compiler: clang-20 15 | cmake-version: 3.24.0 16 | conan-version: 2.17.0 17 | conan-options: -o boost/*:header_only=True 18 | secrets: 19 | CONAN_USER: ${{ secrets.CONAN_USER }} 20 | CONAN_PW: ${{ secrets.CONAN_PW }} 21 | -------------------------------------------------------------------------------- /.github/workflows/publish-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish Release 2 | on: 3 | create: 4 | 5 | concurrency: 6 | group: publish-release-${{ github.workflow }}-${{ github.ref }} 7 | 8 | jobs: 9 | publish-conan-branch-package: 10 | if: ${{ startsWith(github.ref, 'refs/tags/v') }} 11 | uses: dice-group/cpp-conan-release-reusable-workflow/.github/workflows/publish-release.yml@main 12 | with: 13 | public_artifactory: true 14 | os: ubuntu-24.04 15 | compiler: clang-20 16 | cmake-version: 3.24.0 17 | conan-version: 2.17.0 18 | use-tag: true 19 | conan-options: -o boost/*:header_only=True 20 | secrets: 21 | CONAN_USER: ${{ secrets.CONAN_USER }} 22 | CONAN_PW: ${{ secrets.CONAN_PW }} 23 | -------------------------------------------------------------------------------- /.github/workflows/reusable_packaging_and_deployment.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | os: 5 | required: true 6 | type: string 7 | compiler: 8 | required: true 9 | type: string 10 | cmake-version: 11 | required: true 12 | type: string 13 | conan-version: 14 | required: true 15 | type: string 16 | 17 | jobs: 18 | build-and-test-conan-package: 19 | name: Build and test conan package 20 | runs-on: ${{ inputs.os }} 21 | defaults: 22 | run: 23 | shell: bash 24 | 25 | steps: 26 | - name: Add compiler repos 27 | uses: dice-group/cpp-conan-release-reusable-workflow/.github/actions/setup_apt@main 28 | 29 | - name: Get minimum cmake version 30 | uses: lukka/get-cmake@v3.29.3 31 | with: 32 | cmakeVersion: ${{ inputs.cmake-version }} 33 | 34 | - name: Install compiler 35 | id: install_cc 36 | uses: rlalik/setup-cpp-compiler@v1.2 37 | with: 38 | compiler: ${{ inputs.compiler }} 39 | 40 | - name: use mold as default linker 41 | uses: rui314/setup-mold@v1 42 | 43 | - name: Configure conan 44 | uses: dice-group/cpp-conan-release-reusable-workflow/.github/actions/configure_conan@main 45 | with: 46 | conan-version: ${{ inputs.conan-version }} 47 | 48 | - name: add conan user 49 | run: | 50 | conan remote add -f dice-group https://conan.dice-research.org/artifactory/api/conan/tentris 51 | 52 | - name: Cache conan data 53 | id: cache-conan 54 | uses: actions/cache@v4 55 | with: 56 | path: ~/.conan2/p 57 | key: ${{ inputs.os }}-${{ inputs.compiler }}-conan2 58 | 59 | - name: Check out sources 60 | uses: actions/checkout@v3 61 | 62 | - name: Test conan package 63 | env: 64 | CC: ${{ steps.install_cc.outputs.cc }} 65 | CXX: ${{ steps.install_cc.outputs.cxx }} 66 | run: | 67 | # build and test package 68 | pkg_name=$(conan inspect --format json . | jq -r '.name') 69 | pkg_ver=$(conan inspect --format json . | jq -r '.version') 70 | 71 | conan create . --name "${pkg_name}" --version "${pkg_ver}" --user ci --channel testing -pr:b=default --build missing -o boost/*:header_only=True 72 | conan remove -c "${pkg_name}/*" 73 | -------------------------------------------------------------------------------- /.github/workflows/reusable_run_test_and_examples.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | os: 5 | required: true 6 | type: string 7 | compiler: 8 | required: true 9 | type: string 10 | cmake-version: 11 | required: true 12 | type: string 13 | conan-version: 14 | required: true 15 | type: string 16 | with-coverage: 17 | type: boolean 18 | with-sanitizer: 19 | type: boolean 20 | secrets: 21 | coverall-token: 22 | description: 'Access token for coverall. Required if inputs.with-coverage' 23 | required: false 24 | 25 | jobs: 26 | test-and-examples-static: 27 | uses: ./.github/workflows/reusable_run_test_and_examples_by_linking_type.yml 28 | with: 29 | os: ${{ inputs.os }} 30 | compiler: ${{ inputs.compiler }} 31 | cmake-version: ${{ inputs.cmake-version }} 32 | conan-version: ${{ inputs.conan-version }} 33 | build-shared-libs: false 34 | with-sanitizer: ${{ inputs.with-sanitizer }} 35 | 36 | test-and-examples-shared: 37 | uses: ./.github/workflows/reusable_run_test_and_examples_by_linking_type.yml 38 | with: 39 | os: ${{ inputs.os }} 40 | compiler: ${{ inputs.compiler }} 41 | cmake-version: ${{ inputs.cmake-version }} 42 | conan-version: ${{ inputs.conan-version }} 43 | build-shared-libs: true 44 | with-coverage: ${{ inputs.with-coverage }} 45 | secrets: 46 | coverall-token: ${{ secrets.coverall-token }} 47 | -------------------------------------------------------------------------------- /.github/workflows/run_test_and_examples.yml: -------------------------------------------------------------------------------- 1 | name: Run unit tests and examples 2 | on: [ 'pull_request' ] 3 | jobs: 4 | tests_and_example_matrix: 5 | strategy: 6 | matrix: 7 | config: 8 | - os: ubuntu-24.04 9 | compiler: gcc-14 10 | - os: ubuntu-24.04 11 | compiler: clang-19 12 | - os: ubuntu-24.04 13 | compiler: clang-20 14 | 15 | - os: ubuntu-24.04-arm 16 | compiler: gcc-14 17 | - os: ubuntu-24.04-arm 18 | compiler: clang-19 19 | - os: ubuntu-24.04-arm 20 | compiler: clang-20 21 | 22 | - os: macos-15 23 | compiler: gcc-14 24 | 25 | fail-fast: false 26 | name: ${{ matrix.config.compiler }}, ${{ matrix.config.os }} 27 | uses: ./.github/workflows/reusable_run_test_and_examples.yml 28 | with: 29 | os: ${{ matrix.config.os }} 30 | compiler: ${{ matrix.config.compiler }} 31 | cmake-version: 3.24.0 32 | conan-version: 2.17.0 33 | with-coverage: false 34 | with-sanitizer: ${{ matrix.config.compiler == 'clang-20' }} 35 | -------------------------------------------------------------------------------- /.github/workflows/run_test_for_coverage.yml: -------------------------------------------------------------------------------- 1 | name: Run unit tests and examples 2 | on: [ 'pull_request' ] 3 | 4 | 5 | jobs: 6 | tests_and_example_matrix: 7 | strategy: 8 | matrix: 9 | config: 10 | - os: ubuntu-22.04 11 | compiler: gcc-13 12 | fail-fast: false 13 | name: ${{ matrix.config.compiler }}, ${{ matrix.config.os }} 14 | uses: ./.github/workflows/reusable_run_test_and_examples_by_linking_type.yml 15 | with: 16 | os: ${{ matrix.config.os }} 17 | compiler: ${{ matrix.config.compiler }} 18 | cmake-version: 3.24.0 19 | conan-version: 2.17.0 20 | with-coverage: true 21 | with-sanitizer: false 22 | build-shared-libs: true 23 | secrets: 24 | coverall-token: ${{ secrets.COVERALLS_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/test_packaging_and_deployment.yml: -------------------------------------------------------------------------------- 1 | name: Packaging and deployment tests 2 | on: [ 'pull_request' ] 3 | jobs: 4 | packaging-and-deployment-tests-clang: 5 | name: Packaging and deployment tests clang-20 6 | uses: ./.github/workflows/reusable_packaging_and_deployment.yml 7 | with: 8 | os: ubuntu-24.04 9 | compiler: clang-20 10 | cmake-version: 3.24.0 11 | conan-version: 2.17.0 12 | 13 | packaging-and-deployment-tests-gcc: 14 | name: Packaging and deployment tests gcc-14 15 | uses: ./.github/workflows/reusable_packaging_and_deployment.yml 16 | with: 17 | os: ubuntu-24.04 18 | compiler: gcc-14 19 | cmake-version: 3.24.0 20 | conan-version: 2.17.0 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | src/rdf4cpp/version.hpp 2 | 3 | docs/doxygen_output/* 4 | docs/build/* 5 | docs/source/api/* 6 | 7 | .clang-format 8 | .clang-tidy 9 | 10 | # Based on https://www.toptal.com/developers/gitignore/api/c++,conan,ninja,cmake,clion+all 11 | 12 | ### C++ ### 13 | # Prerequisites 14 | *.d 15 | 16 | # Compiled Object files 17 | *.slo 18 | *.lo 19 | *.o 20 | *.obj 21 | 22 | # Precompiled Headers 23 | *.gch 24 | *.pch 25 | 26 | # Compiled Dynamic libraries 27 | *.so 28 | *.dylib 29 | *.dll 30 | 31 | # Fortran module files 32 | *.mod 33 | *.smod 34 | 35 | # Compiled Static libraries 36 | *.lai 37 | *.la 38 | *.a 39 | *.lib 40 | 41 | # Executables 42 | *.exe 43 | *.out 44 | *.app 45 | 46 | ### CLion+all ### 47 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 48 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 49 | 50 | # CLion 51 | .idea/ 52 | 53 | # CMake 54 | cmake-build-*/ 55 | 56 | # Mongo Explorer plugin 57 | .idea/**/mongoSettings.xml 58 | 59 | # File-based project format 60 | *.iws 61 | 62 | # IntelliJ 63 | out/ 64 | 65 | # mpeltonen/sbt-idea plugin 66 | .idea_modules/ 67 | 68 | # JIRA plugin 69 | atlassian-ide-plugin.xml 70 | 71 | # Crashlytics plugin (for Android Studio and IntelliJ) 72 | com_crashlytics_export_strings.xml 73 | crashlytics.properties 74 | crashlytics-build.properties 75 | fabric.properties 76 | 77 | ### CMake ### 78 | CMakeLists.txt.user 79 | CMakeCache.txt 80 | CMakeFiles 81 | CMakeScripts 82 | Testing 83 | Makefile 84 | cmake_install.cmake 85 | install_manifest.txt 86 | compile_commands.json 87 | CTestTestfile.cmake 88 | _deps 89 | 90 | ### CMake Patch ### 91 | # External projects 92 | *-prefix/ 93 | 94 | ### Conan ### 95 | # Conan build information 96 | conan.lock 97 | conanbuildinfo.* 98 | conaninfo.txt 99 | graph_info.json 100 | 101 | # Conan test_package 102 | test_package/CMakeUserPresets.json 103 | test_package/build/ 104 | 105 | ## Various built-in generators 106 | # cmake_find_package generator https://docs.conan.io/en/latest/reference/generators/cmake_find_package.html 107 | Find*.cmake 108 | 109 | # cmake_paths generator https://docs.conan.io/en/1.4/integrations/cmake/cmake_paths_generator.html 110 | conan_paths.* 111 | 112 | # Environment activation scripts produced by https://docs.conan.io/en/latest/mastering/virtualenv.html#virtualenv-generator 113 | activate_run.ps1 114 | activate_run.sh 115 | deactivate_run.ps1 116 | deactivate_run.sh 117 | environment_run.ps1.env 118 | environment_run.sh.env 119 | 120 | ### Ninja ### 121 | .ninja_deps 122 | .ninja_log 123 | 124 | # End of https://www.toptal.com/developers/gitignore/api/c++,conan,ninja,cmake,clion+all 125 | /CMakeUserPresets.json 126 | /conan_provider.cmake 127 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.11" 7 | apt_packages: 8 | - doxygen 9 | 10 | sphinx: 11 | configuration: docs/source/conf.py 12 | builder: "html" 13 | 14 | python: 15 | install: 16 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute to RDF4CPP 2 | 3 | Be aware of our Code of Conduct - we do not tolerate any discrimantive behaviour such as sexism, racism, antisemitism, ableism, homomysia ("phobia"), transmysia ("phobia"), or any other kind of harassment. 4 | 5 | ## Found a Bug? 6 | 7 | * First things first: Is the bug already reported? If so and you got new information, please add them to the existing issue 8 | * Otherwise use the Issues Bug report on Github and try to be as specific as possible, following the Bug report template 9 | * Be sure to be specific even in the title, making it easier to search for your bug if other people encountered it. 10 | * If you found a security issue, please let us know immedietly. 11 | 12 | ## Wrote a Patch for a Bug? 13 | 14 | * Create a Pull Request from your fork to `develop` 15 | * Be very specific what your solution does and what it fixes 16 | 17 | ## Did you fix something purely cosmetic (such as formatting)? 18 | 19 | * Purely cosmetic code fixes won't be allowed. 20 | 21 | ## Want a new Feature? 22 | 23 | * First things first: Is the feature already requested? If so and you got additionaly stuff, please add them to the existing issue 24 | * Otherwise use the Issues Feature report on Github and try to be as specific as possible, following the Feature report template 25 | * Be sure to be specific even in the title, making it easier to search for your feature if other people encountered it. 26 | 27 | ## Wrote a new Feature? 28 | 29 | * Create a Feature Issue on Github first if one doesn't already exists 30 | * Create a Pull Request from your fork to `develop` 31 | * Be very specific what your solution does and what it trys to implement. 32 | 33 | 34 | rdf4cpp is an Open Source Project under the MIT License and thus we welcome any contribution. 35 | That said feel free to code with us :) 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Tentris GmbH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cmake/boilerplate_init.cmake: -------------------------------------------------------------------------------- 1 | macro(boilerplate_init) 2 | ## enforce standard compliance 3 | set(CMAKE_CXX_STANDARD_REQUIRED True) 4 | set(CMAKE_CXX_EXTENSIONS OFF) 5 | 6 | ## C++ compiler flags 7 | if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Wall") 9 | else () 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wold-style-cast -Wcast-qual") 11 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0") 12 | 13 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 14 | # -Wdangling-reference seems to have false positives atm 15 | # We run sanitizers in the CI anyway, so should be fine 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-dangling-reference") 17 | endif () 18 | endif () 19 | 20 | ## C++ language visibility configuration 21 | if (NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET AND 22 | NOT DEFINED CMAKE_VISIBILITY_INLINES_HIDDEN) 23 | set(CMAKE_CXX_VISIBILITY_PRESET default) 24 | set(CMAKE_VISIBILITY_INLINES_HIDDEN NO) 25 | endif () 26 | 27 | # conan requires cmake build type to be specified and it is generally a good idea 28 | if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/CMakeCache.txt) 29 | if (NOT CMAKE_BUILD_TYPE) 30 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) 31 | endif () 32 | endif () 33 | endmacro() 34 | -------------------------------------------------------------------------------- /cmake/conan_cmake.cmake: -------------------------------------------------------------------------------- 1 | macro(install_packages_via_conan conanfile conan_options) 2 | 3 | list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) 4 | list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}) 5 | 6 | 7 | if (NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake") 8 | message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan") 9 | file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/0.18.1/conan.cmake" 10 | "${CMAKE_BINARY_DIR}/conan.cmake" 11 | TLS_VERIFY ON) 12 | endif () 13 | include(${CMAKE_BINARY_DIR}/conan.cmake) 14 | 15 | conan_cmake_autodetect(settings) 16 | conan_check(VERSION 1 DETECT_QUIET) 17 | if (CONAN_CMD) 18 | conan_cmake_install(PATH_OR_REFERENCE ${conanfile} 19 | BUILD missing 20 | SETTINGS ${settings} 21 | OPTIONS "${conan_options}" 22 | ENV_HOST "CC=${CMAKE_C_COMPILER};CXX=${CMAKE_CXX_COMPILER}") 23 | else () 24 | message(WARNING "No conan executable was found. Dependency retrieval via conan is disabled. System dependencies will be used if available.") 25 | endif () 26 | endmacro() -------------------------------------------------------------------------------- /cmake/install_library.cmake: -------------------------------------------------------------------------------- 1 | include(GNUInstallDirs) 2 | include(CMakePackageConfigHelpers) 3 | 4 | function(install_cpp_library TARGET_NAME INCLUDE_PATH) 5 | if (NOT ${ARGC} GREATER_EQUAL 2) 6 | message( 7 | FATAL_ERROR 8 | "you did not specify the target and the include path in the parameter!") 9 | endif () 10 | 11 | target_include_directories( 12 | ${TARGET_NAME} PUBLIC $) 13 | 14 | install(TARGETS ${TARGET_NAME} ${ARGN} 15 | EXPORT ${TARGET_NAME}-targets 16 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 17 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 18 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 19 | INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 20 | ) 21 | 22 | write_basic_package_version_file("${TARGET_NAME}-config-version.cmake" 23 | VERSION ${PROJECT_VERSION} 24 | COMPATIBILITY ExactVersion) 25 | 26 | configure_package_config_file( 27 | "${PROJECT_SOURCE_DIR}/cmake/lib-config.cmake.in" 28 | "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" 29 | INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) 30 | # here we have two possibilities: either CMAKE_INSTALL_DATAROOTDIR (share) or CMAKE_INSTALL_LIBDIR (lib/lib64) 31 | # we just have to be consistent for one target 32 | 33 | install( 34 | EXPORT ${PROJECT_NAME}-targets 35 | FILE ${PROJECT_NAME}-targets.cmake 36 | NAMESPACE ${PROJECT_NAME}:: 37 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) 38 | 39 | install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" 40 | "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake" 41 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake) 42 | 43 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_PATH}/ 44 | DESTINATION include 45 | FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h") 46 | endfunction() 47 | -------------------------------------------------------------------------------- /cmake/lib-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake") 4 | check_required_components("@PROJECT_NAME@") 5 | -------------------------------------------------------------------------------- /cmake/version.hpp.in: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_VERSION_H 2 | #define RDF4CPP_VERSION_H 3 | 4 | #include 5 | 6 | namespace rdf4cpp { 7 | inline constexpr const char name[] = "rdf4cpp"; 8 | inline constexpr const char version[] = "@PROJECT_VERSION@"; 9 | inline constexpr std::array version_tuple = {@PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@}; 10 | inline constexpr int pobr_version = @POBR_VERSION@; ///< persisted object binary representation version 11 | }// namespace rdf4cpp 12 | 13 | #endif//RDF4CPP_VERSION_H 14 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==8.2.3 2 | breathe==4.36.0 3 | exhale==0.3.7 4 | furo -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | import subprocess, re 7 | 8 | # remove anything from the previous build 9 | # if this is not done, sphinx throws random errors 10 | subprocess.call('cd ../../; rm -r docs/build/', shell=True) 11 | subprocess.call('cd ../../; rm -r docs/doxygen_output/', shell=True) 12 | subprocess.call('cd ../../; rm -r docs/source/api/', shell=True) 13 | 14 | # generate doxygen xml output 15 | subprocess.call('cd ../../; doxygen', shell=True) 16 | 17 | # -- Project information ----------------------------------------------------- 18 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 19 | 20 | project = 'rdf4cpp' 21 | copyright = '2023, DICE Group' 22 | author = 'DICE Group' 23 | 24 | # get release version from cmake 25 | release = '0.0.0' 26 | with open("../../CMakeLists.txt", "r") as file: 27 | for line in file: 28 | m = re.match(r"project\(rdf4cpp VERSION ([0-9.]+)\)", line) 29 | if m is not None: 30 | release = m.group(1) 31 | break 32 | 33 | version = release 34 | 35 | # -- General configuration --------------------------------------------------- 36 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 37 | 38 | extensions = ["breathe", "exhale"] 39 | 40 | templates_path = ['_templates'] 41 | exclude_patterns = [] 42 | 43 | 44 | 45 | # -- Options for HTML output ------------------------------------------------- 46 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 47 | 48 | html_theme = 'furo' 49 | html_static_path = ['_static'] 50 | 51 | breathe_projects = { 52 | "rdf4cpp": "../doxygen_output/xml/", 53 | } 54 | breathe_default_project = "rdf4cpp" 55 | 56 | # Setup the exhale extension 57 | exhale_args = { 58 | # These arguments are required 59 | "containmentFolder": "./api", 60 | "rootFileName": "library_root.rst", 61 | "doxygenStripFromPath": "..", 62 | # Heavily encouraged optional argument (see docs) 63 | "rootFileTitle": "rdf4cpp API", 64 | # Suggested optional arguments 65 | "createTreeView": True, 66 | # TIP: if using the sphinx-bootstrap-theme, you need 67 | # "treeViewIsBootstrap": True, 68 | "exhaleExecutesDoxygen": False, 69 | "listingExclude": ["mz*"], 70 | "fullToctreeMaxDepth": 2, 71 | "contentsDirectives": False, 72 | } 73 | 74 | # Tell sphinx what the primary language being documented is. 75 | primary_domain = 'cpp' 76 | 77 | # Tell sphinx what the pygments highlight language should be. 78 | highlight_language = 'cpp' 79 | -------------------------------------------------------------------------------- /docs/source/examples.rst: -------------------------------------------------------------------------------- 1 | Examples 2 | ######## 3 | 4 | rdf Nodes 5 | ------------------- 6 | 7 | How to use the different Node Types: 8 | 9 | .. literalinclude:: ../../examples/rdf_nodes.cpp 10 | :language: cpp 11 | 12 | Literal Datatypes 13 | ----------------- 14 | 15 | How to use Literals and work with different Datatypes: 16 | 17 | .. literalinclude:: ../../examples/literal_datatypes.cpp 18 | :language: cpp 19 | 20 | Graphs and Datasets 21 | ------------------- 22 | 23 | How to build a Graph and perform some simple Queries on it: 24 | 25 | .. literalinclude:: ../../examples/graphs_and_datasets.cpp 26 | :language: cpp 27 | 28 | Namespaces 29 | ---------- 30 | 31 | How to use Namespaces to shorten IRIs: 32 | 33 | .. literalinclude:: ../../examples/namespaces.cpp 34 | :language: cpp 35 | 36 | RDFFileParser 37 | ------------------- 38 | 39 | How to parse Turtle files: 40 | 41 | .. literalinclude:: ../../examples/RDFFileParser_example.cpp 42 | :language: cpp 43 | -------------------------------------------------------------------------------- /docs/source/getting_started.rst: -------------------------------------------------------------------------------- 1 | Getting Started 2 | =============== 3 | 4 | .. highlight:: bash 5 | 6 | Usage 7 | ----- 8 | 9 | .. literalinclude:: ../../examples/getting_started.cpp 10 | :language: cpp 11 | 12 | Installation 13 | ------------ 14 | Until its first stable release, rdf4cpp will not be available via Conan Center. Instead, it is available via the artifactory of the `DICE Research Group `_. 15 | 16 | You need the package manager `Conan `_ version 1 installed and set up. You can add the DICE artifactory with: :: 17 | 18 | conan remote add dice-group https://conan.dice-research.org/artifactory/api/conan/tentris 19 | 20 | 21 | To use rdf4cpp, add it to your :code:`conanfile.txt`: 22 | 23 | .. parsed-literal:: 24 | 25 | [requires] 26 | rdf4cpp/\ |release| 27 | 28 | .. note:: 29 | 30 | If you want to include rdf4cpp without using conan, make sure you also include its dependencies exposed via the rdf4cpp API. 31 | 32 | Build 33 | ----- 34 | 35 | Requirements 36 | ____________ 37 | 38 | Currently, rdf4cpp builds only on linux with a C++20 compatible compiler. 39 | CI builds and tests rdf4cpp with gcc-{13}, clang-{15,16} with libstdc++-13 on ubuntu 22.04. 40 | 41 | Dependencies 42 | ____________ 43 | 44 | It is recommended to include build dependencies via conan. Set up Conan as follows on Ubuntu 22.04+: :: 45 | 46 | sudo apt install python3-pip 47 | pip3 install --user "conan<2" 48 | conan user 49 | conan profile new --detect default 50 | conan profile update settings.compiler.libcxx=libstdc++13 default 51 | conan remote add dice-group https://conan.dice-research.org/artifactory/api/conan/tentris 52 | 53 | 54 | Compile 55 | _______ 56 | 57 | rdf4cpp uses CMake. To build it, run: :: 58 | 59 | cmake -B build_dir # configure and generate 60 | cmake --build build_dir # compile 61 | 62 | 63 | To install it to your system, run afterward: :: 64 | 65 | sudo make install 66 | 67 | 68 | Additional CMake config options: 69 | ________________________________ 70 | 71 | * :code:`-DBUILD_EXAMPLES=ON/OFF [default: OFF]`: Build the examples. 72 | * :code:`-DBUILD_TESTING=ON/OFF [default: OFF]`: Build the tests. 73 | * :code:`-DBUILD_SHARED_LIBS=ON/OFF [default: OFF]`: Build a shared library instead of a static one. 74 | * :code:`-DUSE_CONAN=ON/OFF [default: ON]`: If available, use Conan to retrieve dependencies. 75 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to rdf4cpp's documentation! 2 | =================================== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | getting_started 8 | users_guide 9 | examples 10 | api/library_root 11 | technical 12 | 13 | rdf4cpp aims to be a stable, modern RDF library for C++. 14 | 15 | This page was build for rdf4cpp |release|. 16 | -------------------------------------------------------------------------------- /docs/source/t_node_storage.rst: -------------------------------------------------------------------------------- 1 | Node Storage 2 | ############ 3 | 4 | - `NodeStorage` is the central concept that defines what a node storage must be able to do. 5 | - `NodeStorageVTable` is a vtable for a NodeStorage. It can be generated from any class that is a `NodeStorage`. 6 | - `DynNodeStoragePtr` is a non-owning pointer to any `NodeStorage`, it stores an instance-pointer and a vtable-pointer. 7 | - Identifiers for Nodes and their properties are found in :doc:`t_NodeBackendHandle` 8 | - A reference implementation of a thread-safe node storage backend based on `tsl::sparse_map` is provided 9 | at :class:`rdf4cpp::storage::reference_node_storage::ReferenceNodeStorageBackend` 10 | - :doc:`t_node_storage_view` contains proxy classes to access information about a node stored in an implementation-specific 11 | backend. 12 | 13 | 14 | Requirements for `NodeStorage` Implementations 15 | _______________________________________________ 16 | - Implementations must not assume that all nodes are stored in the node storage, 17 | in fact small `Literal`\s that can fit in 42 bits (e.g. values of `xsd:int`) are usually *not* stored there 18 | - `IRI`\s, `BlankNode`\s and `Variable`\s should usually be stored 19 | as their string representations 20 | - `Literal`\s can be stored either as their canonical lexical form or as values 21 | - when trying to store `Literal`\s as values the implementation is 22 | required to accurately report which `Literal` types can be stored as 23 | values via :func:`rdf4cpp::storage::NodeStorage::has_specialized_storage_for`. **Inaccurate 24 | reporting will result in undefined behaviour.** 25 | - Warning: `Literals` that have value storage are assumed to never need escaping when converting them to their 26 | n-triples string representation. I.e. the output of their corresponding `to_string` function will be used 27 | without escaping it. 28 | - see :class:`rdf4cpp::storage::reference_node_storage::SyncReferenceNodeStorage` for details 29 | - Some `IRI`\s are reserved by default (see :var:`rdf4cpp::datatypes::registry::reserved_datatype_ids`) 30 | these `IRI`\s *must always* be present in the `NodeStorage` 31 | and assigned the given `NodeID`. **Not upholding this invariant results in undefined behaviour. 32 | See :class:`rdf4cpp::storage::reference_node_storage::SyncReferenceNodeStorage` 33 | for the expected usage.** 34 | 35 | General Notes for Implementors 36 | ______________________________ 37 | 38 | - **Passing a `Literal` that is supposed to be stored in lexical storage (as required by the `NodeStorage` implementation) 39 | as a value view results in undefined behaviour.** 40 | - **Passing a `Literal` that is supposed to be stored in value storage (as required by the `NodeStorage` implementation) 41 | as a lexical view results in undefined behaviour.** 42 | -------------------------------------------------------------------------------- /docs/source/t_node_storage_view.rst: -------------------------------------------------------------------------------- 1 | Backend Views 2 | ############# 3 | 4 | `BNodeBackendView`, `IRIBackendView`, `LiteralBackendView` and `VariableBackendView` act as messenger objects between 5 | the `Node` types `BlankNode`, `IRI`, `Literal` and `Variable` and there implementation specific storage in the backend. -------------------------------------------------------------------------------- /docs/source/t_storage.rst: -------------------------------------------------------------------------------- 1 | Storage 2 | ======= 3 | 4 | .. toctree:: 5 | 6 | t_node_storage 7 | t_NodeBackendHandle 8 | t_node_storage_view 9 | 10 | In rdf4cpp, we try our best to spare the user the details of how graphs and RDF nodes are actually stored in the backend. 11 | So if you just want to use rdf4cpp, you most probably do not need to go down this rabbit hole. You can just use the defaults. 12 | 13 | Storage is split up into two parts, :doc:`t_node_storage` and *tuple storage (DatasetStorage)*. 14 | For both storage parts, reference implementations are provided and used as a sensible default. 15 | 16 | NodeStorage 17 | ___________ 18 | 19 | `NodeStorage`\s store information about RDF `Node`\s. By default, there is only one default NodeStorage which is automatically used 20 | (it lives at `rdf4cpp::storage::default_node_storage`). 21 | The constructors of `BlankNode`, `IRI`, `Literal` and `Variable` optionally allow to use another `NodeStorage`. 22 | The `SyncReferenceNodeStorage` implementation of the `NodeStorage` concept, which is used by default, is thread-safe. 23 | Whereas the `UnsyncReferenceNodeStorage` implementation is not. 24 | For more details, consult :doc:`t_node_storage`. 25 | -------------------------------------------------------------------------------- /docs/source/technical.rst: -------------------------------------------------------------------------------- 1 | Technical Documentatation 2 | ========================= 3 | 4 | .. toctree:: 5 | 6 | t_datatype_registry 7 | t_storage 8 | 9 | In depth technical documentation of certain important parts of rdf4cpp are found here. Not useful for the average user, 10 | but very useful for developers and the rare case someone wants to build a full DBMS on top of rdf4cpp. 11 | -------------------------------------------------------------------------------- /docs/source/users_guide.rst: -------------------------------------------------------------------------------- 1 | Users Guide 2 | =========== 3 | 4 | Terms and Definitions 5 | --------------------- 6 | We use the official definitions of ``_. 7 | 8 | Framework Basics 9 | ---------------- 10 | 11 | The main types of rdf4cpp: 12 | 13 | * :class:`rdf4cpp::Node`: Base class of Literal, IRI and BlankNode 14 | * :class:`rdf4cpp::IRI`: An IRI. 15 | * :class:`rdf4cpp::Literal`: A Literal containing some data. 16 | * :class:`rdf4cpp::BlankNode`: A Blank Node used to connect other Nodes. 17 | * :class:`rdf4cpp::Statement`: A basic rdf statement consisting of Subject, Predicate and Object. 18 | * :class:`rdf4cpp::Quad`: A Statement with added Graph. 19 | * :class:`rdf4cpp::Graph`: A Collection of Statements, with the ability to execute simple Queries. 20 | * :class:`rdf4cpp::Dataset`: A Collection of Quads, with the ability to execute simple Queries. 21 | * :class:`rdf4cpp::Namespace`: A namespace that makes constructing IRIs with common prefix easier. 22 | * :class:`rdf4cpp::query::Variable`: A Variable used in Queries. 23 | * :class:`rdf4cpp::query::TriplePattern`: A Query patterns of Subject, Predicate and Object. 24 | * :class:`rdf4cpp::query::QuadPattern`: A Query of Graph, Subject, Predicate and Object. 25 | * :class:`rdf4cpp::query::Solution`: A single matched Solution, with all Variables bound. 26 | 27 | Datatypes 28 | --------- 29 | 30 | Literal supports common rdf Datatypes and operations on them (as defined in ``_), 31 | as well as conversions between Literal Datatypes. 32 | 33 | You can find all supported Datatypes here: 34 | 35 | * :ref:`namespace_rdf4cpp__datatypes__xsd`: XSD datatypes. 36 | * :ref:`namespace_rdf4cpp__datatypes__rdf`: RDF datatypes (LangString). 37 | * :ref:`namespace_rdf4cpp__datatypes__owl`: OWL datatypes. 38 | 39 | Parsing Files 40 | ------------- 41 | 42 | The class :class:`rdf4cpp::parser::RDFFileParser` allows reading files containing rdf Statements and iterate over them. 43 | Supported Formats: Turtle, TriG, N-Triples and N-Quads. 44 | :class:`rdf4cpp::parser::IStreamQuadIterator` allows doing the same over arbitrary data streams. 45 | 46 | Relaxed Parsing Mode 47 | -------------------- 48 | 49 | The setting :var:`rdf4cpp::datatypes::registry::relaxed_parsing_mode` disables IRI validity checks and allows rdf4cpp to automatically try to correct some faulty Literals. 50 | See the linked relaxed_parsing_mode for a full list of changes. 51 | Currently aimed at reducing loading errors with DBPedia, more might be added in future versions. 52 | 53 | (since rdf4cpp v0.0.24) 54 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_STANDARD 20) 2 | 3 | add_executable(graphs_and_datasets_example graphs_and_datasets.cpp) 4 | target_link_libraries(graphs_and_datasets_example PRIVATE 5 | rdf4cpp::rdf4cpp 6 | ) 7 | 8 | add_executable(literal_datatypes_example literal_datatypes.cpp) 9 | target_link_libraries(literal_datatypes_example PRIVATE 10 | rdf4cpp::rdf4cpp 11 | ) 12 | 13 | add_executable(rdf_nodes_example rdf_nodes.cpp) 14 | target_link_libraries(rdf_nodes_example PRIVATE 15 | rdf4cpp::rdf4cpp 16 | ) 17 | 18 | add_executable(namespaces_example namespaces.cpp) 19 | target_link_libraries(namespaces_example PRIVATE 20 | rdf4cpp::rdf4cpp 21 | ) 22 | 23 | add_executable(blank_node_example blank_node_management.cpp) 24 | target_link_libraries(blank_node_example PRIVATE 25 | rdf4cpp::rdf4cpp 26 | ) 27 | 28 | add_executable(RDFFileParser_example RDFFileParser_example.cpp) 29 | target_link_libraries(RDFFileParser_example PRIVATE 30 | rdf4cpp::rdf4cpp 31 | ) 32 | file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/RDFFileParser_simple.ttl" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") 33 | 34 | add_executable(getting_started getting_started.cpp) 35 | target_link_libraries(getting_started PRIVATE 36 | rdf4cpp::rdf4cpp 37 | ) 38 | 39 | add_executable(rdf_format_checker rdf_format_checker.cpp) 40 | target_link_libraries(rdf_format_checker PRIVATE 41 | rdf4cpp::rdf4cpp 42 | ) 43 | -------------------------------------------------------------------------------- /examples/RDFFileParser_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | // read file 6 | for (const auto &v : rdf4cpp::parser::RDFFileParser{"./RDFFileParser_simple.ttl"}) { 7 | if (v.has_value()) // check if parser returns a successful read value 8 | std::cout << v.value() << "\n"; 9 | else // or an error 10 | std::cerr << v.error() << "\n"; 11 | } 12 | return 0; 13 | } -------------------------------------------------------------------------------- /examples/RDFFileParser_simple.ttl: -------------------------------------------------------------------------------- 1 | "search" . 2 | . 3 | "web applications" . -------------------------------------------------------------------------------- /examples/getting_started.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | using namespace rdf4cpp; 5 | Literal a = Literal::make_typed_from_value(1.2); 6 | Literal b = Literal::make_typed("1.1", IRI{"http://www.w3.org/2001/XMLSchema#float"}); 7 | Literal r = a + b; 8 | std::cout << r.lexical_form(); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /examples/graphs_and_datasets.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | using namespace rdf4cpp; 8 | 9 | Dataset dataset; 10 | auto &g = dataset.graph(IRI{"http://named_graph.com"}); 11 | 12 | g.add({IRI{"http://example.com"}, IRI{"http://example.com"}, Literal::make_lang_tagged("text", "en")}); 13 | g.add({IRI{"http://example.com"}, IRI{"http://example.com"}, Literal::make_lang_tagged("text", "fr")}); 14 | g.add({IRI{"http://example.com"}, IRI{"http://example.com"}, Literal::make_simple("txt")}); 15 | g.add({IRI{"http://example.com"}, IRI{"http://example.com"}, Literal::make_simple("text")}); 16 | 17 | dataset.add({IRI{"http://named_graph.com"}, IRI{"http://example.com"}, IRI{"http://example.com"}, Literal::make_simple("text")}); 18 | 19 | query::TriplePattern triple_pattern{query::Variable("x"), IRI{"http://example.com"}, query::Variable{"z"}}; 20 | std::cout << triple_pattern.subject() << std::endl; 21 | std::cout << triple_pattern.predicate() << std::endl; 22 | std::cout << triple_pattern.object() << std::endl; 23 | 24 | std::cout << "g size " << g.size() << std::endl; 25 | 26 | Graph::solution_sequence solutions = g.match(triple_pattern); 27 | for (const auto &solution : solutions) { 28 | std::cout << "bound variables: " << solution.bound_count() << std::endl; 29 | 30 | for (size_t i = 0; i < solution.bound_count(); ++i) { 31 | std::cout << solution.variable(i) << " -> " << solution[i] << std::endl; 32 | } 33 | } 34 | 35 | if (argc > 1) { 36 | Dataset ds2; 37 | std::ifstream ifs{argv[1]}; 38 | if (!ifs.is_open()) { 39 | std::cout << "could not open test file." << std::endl; 40 | return 1; 41 | } 42 | 43 | ds2.load_rdf_data(ifs); 44 | 45 | std::cout << "ds2 from " << argv[1] << ":" << std::endl; 46 | std::cout << ds2 << std::endl; 47 | } else { 48 | std::cout << "no test file provided." << std::endl; 49 | } 50 | } -------------------------------------------------------------------------------- /examples/literal_datatypes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace rdf4cpp; 5 | 6 | void value_construction() { 7 | // runtime construction 8 | [[maybe_unused]] Literal float_1 = Literal::make_typed("1.1", IRI{"http://www.w3.org/2001/XMLSchema#float"}); 9 | 10 | // using compile time knowledge 11 | [[maybe_unused]] Literal double_1 = Literal::make_typed_from_value(1.2); 12 | 13 | // simplification: using user-defined-literal function 14 | [[maybe_unused]] Literal int_1 = 1_xsd_int; 15 | } 16 | 17 | void lexical_access() { 18 | Literal double_1 = 1.8_xsd_double; 19 | assert(double_1.lexical_form() == "1.8E0"); 20 | assert(std::string{double_1} == R"#("1.8E0"^^)#"); 21 | 22 | Literal lang_string = Literal::make_lang_tagged("Hello", "en-US"); 23 | assert(lang_string.lexical_form() == "Hello"); 24 | assert(lang_string.language_tag() == "en-us"); 25 | assert(lang_string.language_tag_matches_range("*")); 26 | assert(lang_string.language_tag_matches_range("en")); 27 | assert(std::string{lang_string} == R"#("Hello"@en-us)#"); 28 | } 29 | 30 | void direct_value_access() { 31 | Literal lit = 1.1_xsd_float; 32 | 33 | std::any rt_value = lit.value(); 34 | assert(any_cast(rt_value) == 1.1f); 35 | 36 | float ct_value = lit.value(); 37 | assert(ct_value == 1.1f); 38 | 39 | try { 40 | // invalid access 41 | lit.value(); 42 | assert(false); 43 | } catch (std::runtime_error const &) { 44 | } 45 | } 46 | 47 | void value_transformations() { 48 | Literal lit = 42.0_xsd_float; 49 | assert(lit.value() == 42.f); 50 | 51 | lit = lit * -1.5_xsd_float; 52 | assert(lit.value() == -63.f); 53 | 54 | lit = lit.abs(); 55 | assert(lit.value() == 63.f); 56 | 57 | lit = lit.cast(); 58 | assert(lit.value() == "63"); 59 | 60 | lit = lit.as_ebv(); 61 | assert(lit.value() == true); 62 | } 63 | 64 | void comparisons() { 65 | Literal lit1 = 42.0_xsd_float; 66 | Literal lit2 = 89_xsd_int; 67 | Literal lit3 = 42_xsd_integer; 68 | 69 | assert(lit1 < lit2); 70 | assert(lit1 == lit3); 71 | assert(lit2 > lit3); 72 | assert(lit1.order(lit3) == std::partial_ordering::less); 73 | } 74 | 75 | int main() { 76 | value_construction(); 77 | lexical_access(); 78 | direct_value_access(); 79 | value_transformations(); 80 | comparisons(); 81 | } 82 | -------------------------------------------------------------------------------- /examples/namespaces.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main() { 6 | using namespace rdf4cpp; 7 | 8 | Namespace ex("http://example.com/"); 9 | 10 | IRI ex_A = ex + "A"; 11 | std::cout << ex_A << std::endl; 12 | assert(ex_A.identifier() == "http://example.com/A"); 13 | 14 | ex.clear(); 15 | ex_A = ex + "A"; 16 | std::cout << ex_A << std::endl; 17 | assert(ex_A.identifier() == "http://example.com/A"); 18 | 19 | auto rdf = namespaces::RDF(); 20 | auto rdf_Property = rdf + "Property"; 21 | std::cout << rdf_Property << std::endl; 22 | assert(rdf_Property.identifier() == "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"); 23 | 24 | auto rdf_15 = rdf + "_15"; 25 | std::cout << rdf_15 << std::endl; 26 | assert(rdf_15.identifier() == "http://www.w3.org/1999/02/22-rdf-syntax-ns#_15"); 27 | try { 28 | [[maybe_unused]] auto random = rdf + "random"; 29 | } catch (std::runtime_error const &ex) { 30 | std::cerr << ex.what() << std::endl; 31 | } 32 | } -------------------------------------------------------------------------------- /examples/rdf_format_checker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | 9 | int main(int argc, char *argv[]) { 10 | using namespace rdf4cpp; 11 | using namespace parser; 12 | if (argc != 2) { 13 | std::cerr << "usage: pass file to be checked as only parameter, found errors are written to stdout"; 14 | return 1; 15 | } 16 | 17 | rdf4cpp::datatypes::registry::relaxed_parsing_mode = true; 18 | 19 | std::ifstream in{argv[1]}; 20 | storage::reference_node_storage::UnsyncReferenceNodeStorage nst; 21 | int c = 0; 22 | 23 | IStreamQuadIterator::state_type state{.node_storage = nst}; 24 | IStreamQuadIterator i{in, ParsingFlag::NTriples, &state}; 25 | while (i != std::default_sentinel) { 26 | if (!i->has_value()) { 27 | std::cout << i->error() << '\n'; 28 | } 29 | ++i; 30 | ++c; 31 | if (c >= 1000) { 32 | nst.clear(); 33 | state.node_storage = nst; 34 | c = 0; 35 | } 36 | } 37 | 38 | std::cout << "done"; 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /examples/rdf_nodes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #include 5 | 6 | int main() { 7 | using namespace rdf4cpp; 8 | 9 | query::Variable variable("x"); 10 | std::cout << variable << std::endl; 11 | 12 | query::Variable variable2("x1", true); 13 | std::cout << "variable2 =" << variable2 << std::endl; 14 | 15 | query::Variable variable3{"x1", true}; 16 | std::cout << "variable3 =" << variable2 << std::endl; 17 | std::cout << "(variable 2 == variable3) = " << (variable2 == variable3) << std::endl; 18 | 19 | BlankNode blankNode("x1"); 20 | std::cout << "blankNode =" << blankNode << std::endl; 21 | 22 | std::cout << "(variable2 != blankNode) = " << (variable2 != blankNode) << std::endl; 23 | 24 | IRI iri = IRI("http://example.com/"); 25 | std::cout << iri << std::endl; 26 | 27 | IRI iri_pred("http://example.com/pred"); 28 | std::cout << iri_pred << std::endl; 29 | 30 | auto print_literal_info = [](Literal lit) { 31 | std::cout << "---" << std::endl; 32 | std::cout << "operator<<: " << lit << std::endl; 33 | std::cout << "lexical_form: " << lit.lexical_form() << std::endl; 34 | std::cout << "datatype: " << lit.datatype() << std::endl; 35 | std::cout << "language_tag: " << lit.language_tag() << std::endl; 36 | std::cout << "---" << std::endl; 37 | }; 38 | 39 | auto lit1 = Literal::make_simple("xxxx"); 40 | auto lit2 = Literal::make_typed("xxxx", iri_pred); 41 | auto lit3 = Literal::make_typed("xxxx", IRI("http://example.com/pred2")); 42 | auto lit4 = Literal::make_lang_tagged("xxxx", "de"); 43 | auto lit5 = Literal::make_lang_tagged("xxxx", "de"); 44 | 45 | print_literal_info(lit1); 46 | print_literal_info(lit2); 47 | print_literal_info(lit3); 48 | print_literal_info(lit4); 49 | print_literal_info(lit5); 50 | 51 | std::vector nodes{}; 52 | nodes.push_back(variable); 53 | nodes.push_back(variable2); 54 | nodes.push_back(blankNode); 55 | nodes.push_back(iri_pred); 56 | nodes.push_back(lit1); 57 | nodes.push_back(lit2); 58 | nodes.push_back(lit3); 59 | nodes.push_back(lit4); 60 | nodes.push_back(lit5); 61 | nodes.push_back(lit4.datatype()); 62 | 63 | std::sort(nodes.begin(), nodes.end()); 64 | std::cout << "sorted:" << std::endl; 65 | for (const auto &item : nodes) { 66 | std::cout << item << std::endl; 67 | } 68 | 69 | if (nodes[1].is_variable()) { 70 | auto v = nodes[1].as_variable(); 71 | std::cout << v << std::endl; 72 | } 73 | } -------------------------------------------------------------------------------- /private/rdf4cpp/regex/RegexImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "RegexImpl.hpp" 2 | 3 | namespace rdf4cpp::regex { 4 | 5 | namespace detail { 6 | 7 | /** 8 | * Translates the regex flags of rdf4cpp's public interface to RE2 Options. 9 | * 10 | * @param flags the rdf4cpp flags to translate 11 | * @return the translated RE2 Options 12 | */ 13 | static re2::RE2::Options translate_flags(Regex::flag_type const flags) { 14 | re2::RE2::Options o; 15 | o.set_log_errors(false); 16 | o.set_dot_nl(flags.contains(RegexFlag::DotAll)); 17 | o.set_case_sensitive(!flags.contains(RegexFlag::CaseInsensitive)); 18 | o.set_literal(flags.contains(RegexFlag::Literal)); 19 | 20 | return o; 21 | } 22 | 23 | static re2::RE2 build_regex(std::string_view regex, Regex::flag_type flags) { 24 | auto opt = translate_flags(flags); 25 | if (!flags.contains(RegexFlag::Multiline) && !flags.contains(RegexFlag::RemoveWhitespace)) { 26 | return {regex, opt}; 27 | } 28 | // https://www.w3.org/TR/xpath-functions/#flags 29 | // re2 does not support x 30 | // and m needs to be passed as re2 flag (Options::set_one_line is ignored, if Options::posix_syntax == false) 31 | std::string x{}; 32 | x.reserve(regex.size()+4); 33 | if (flags.contains(RegexFlag::Multiline)) { 34 | x.append("(?m)"); 35 | } 36 | if (flags.contains(RegexFlag::RemoveWhitespace)) { 37 | uint64_t classes = 0; 38 | char prev = '\0'; 39 | for (char const c : regex) { 40 | if (c == '[' && prev != '\\') { 41 | ++classes; 42 | } else if (c == ']' && prev != '\\') { 43 | --classes; 44 | } else if (classes == 0 && (c == '\t' || c == '\r' || c == '\n' || c == ' ')) { 45 | continue; 46 | } 47 | x.append(1, c); 48 | prev = c; 49 | } 50 | } else { 51 | x.append(regex); 52 | } 53 | return {x, opt}; 54 | } 55 | 56 | } // namespace detail 57 | 58 | Regex::Impl::Impl(std::string_view const regex, Regex::flag_type const flags) : regex{detail::build_regex(regex, flags)}, flags{flags} { 59 | if (!this->regex.ok()) { 60 | throw RegexError{"Failed to compile regex: " + this->regex.error()}; 61 | } 62 | } 63 | 64 | bool Regex::Impl::regex_match(std::string_view const str) const noexcept { 65 | return RE2::FullMatch(str, this->regex); 66 | } 67 | 68 | bool Regex::Impl::regex_search(std::string_view const str) const noexcept { 69 | return RE2::PartialMatch(str, this->regex); 70 | } 71 | 72 | } //namespace rdf4cpp::regex 73 | -------------------------------------------------------------------------------- /private/rdf4cpp/regex/RegexImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_UTIL_PRIVATE_REGEX_IMPL_HPP 2 | #define RDF4CPP_RDF_UTIL_PRIVATE_REGEX_IMPL_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace rdf4cpp::regex { 9 | 10 | struct Regex::Impl { 11 | re2::RE2 regex; 12 | Regex::flag_type flags; 13 | 14 | Impl(std::string_view regex, Regex::flag_type flags); 15 | [[nodiscard]] bool regex_match(std::string_view str) const noexcept; 16 | [[nodiscard]] bool regex_search(std::string_view str) const noexcept; 17 | }; 18 | 19 | } //namespace rdf4cpp::regex 20 | 21 | #endif //RDF4CPP_RDF_UTIL_PRIVATE_REGEX_IMPL_HPP 22 | -------------------------------------------------------------------------------- /private/rdf4cpp/regex/RegexReplacerImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_UTIL_PRIVATE_REGEXREPLACER_IMPL_HPP 2 | #define RDF4CPP_RDF_UTIL_PRIVATE_REGEXREPLACER_IMPL_HPP 3 | 4 | #include 5 | #include "RegexImpl.hpp" 6 | 7 | namespace rdf4cpp::regex { 8 | 9 | struct RegexReplacer::Impl { 10 | Regex::Impl const *regex; 11 | std::string rewrite; 12 | 13 | Impl(Regex::Impl const ®ex, std::string_view rewrite); 14 | void regex_replace(std::string &str) const noexcept; 15 | }; 16 | 17 | } //namespace rdf4cpp::regex 18 | 19 | #endif //RDF4CPP_RDF_UTIL_PRIVATE_REGEXREPLACER_IMPL_HPP 20 | -------------------------------------------------------------------------------- /private/rdf4cpp/writer/OutputFormat.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_PRIVATE_OUTPUTFORMAT_HPP 2 | #define RDF4CPP_PRIVATE_OUTPUTFORMAT_HPP 3 | 4 | namespace rdf4cpp::writer { 5 | 6 | enum struct OutputFormat { 7 | NTriples, 8 | Turtle, 9 | NQuads, 10 | TriG 11 | }; 12 | 13 | template 14 | concept format_has_graph = (F == OutputFormat::NQuads || F == OutputFormat::TriG); 15 | 16 | template 17 | concept format_has_prefix = (F == OutputFormat::Turtle || F == OutputFormat::TriG); 18 | 19 | } // namespace rdf4cpp::writer 20 | 21 | #endif // RDF4CPP_PRIVATE_OUTPUTFORMAT_HPP 22 | -------------------------------------------------------------------------------- /private/rdf4cpp/writer/Prefixes.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_PRIVATE_PREFIXES_HPP 2 | #define RDF4CPP_PRIVATE_PREFIXES_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::writer { 8 | 9 | struct TypeIRIPrefix { 10 | std::string_view prefix; 11 | std::string_view shorthand; 12 | }; 13 | 14 | inline constexpr std::array iri_prefixes{ 15 | TypeIRIPrefix{"http://www.w3.org/2001/XMLSchema#", "xsd"}, 16 | TypeIRIPrefix{"http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf"}, 17 | }; 18 | 19 | static consteval typename decltype(iri_prefixes)::const_iterator find_prefix(std::string_view name) { 20 | return std::ranges::find_if(iri_prefixes, [&](auto const &pre) { 21 | return name.starts_with(pre.prefix); 22 | }); 23 | } 24 | 25 | namespace detail { 26 | 27 | template 28 | static consteval std::array make_type_iri_buf(std::array ret = {}) { 29 | using namespace datatypes::registry; 30 | using namespace datatypes::registry::util; 31 | 32 | if constexpr (Ix >= Len) { 33 | return ret; 34 | } else { 35 | if constexpr (constexpr auto it = find_prefix(reserved_datatype_ids.storage[Ix].first); it != writer::iri_prefixes.end()) { 36 | constexpr auto without_prefix = reserved_datatype_ids.storage[Ix].first.substr(it->prefix.size()); 37 | 38 | using concat = ConstexprStringHoldershorthand.size() + 1>{it->shorthand} 39 | + ConstexprString{":"} 40 | + ConstexprString{without_prefix}>; 41 | 42 | ret[static_cast(reserved_datatype_ids.storage[Ix].second.to_underlying())] = concat::value; 43 | } 44 | 45 | return make_type_iri_buf(ret); 46 | } 47 | } 48 | 49 | static constexpr auto type_iri_buffer = make_type_iri_buf<1 << storage::identifier::LiteralType::width, 0, datatypes::registry::reserved_datatype_ids.size()>(); 50 | 51 | } // namespace detail 52 | 53 | // will only get called with fixed ids 54 | inline bool write_fixed_type_iri(datatypes::registry::LiteralType t, BufWriterParts const writer, bool use_prefixes) noexcept { 55 | assert(t.is_fixed()); 56 | 57 | if (use_prefixes) { 58 | auto const &p = detail::type_iri_buffer[t.to_underlying()]; 59 | if (!p.empty()) { 60 | return write_str(p, writer); 61 | } 62 | } 63 | 64 | RDF4CPP_DETAIL_TRY_WRITE_STR("<"); 65 | RDF4CPP_DETAIL_TRY_WRITE_STR(datatypes::registry::DatatypeRegistry::get_entry(t)->datatype_iri); 66 | return write_str(">", writer); 67 | } 68 | 69 | } // namespace rdf4cpp::writer 70 | 71 | #endif // RDF4CPP_PRIVATE_PREFIXES_HPP 72 | -------------------------------------------------------------------------------- /private/rdf4cpp/writer/TryWrite.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_PRIVATE_TRY_SERIALIZE_HPP 2 | #define RDF4CPP_PRIVATE_TRY_SERIALIZE_HPP 3 | 4 | #include 5 | 6 | #define RDF4CPP_DETAIL_TRY_WRITE_STR(...) \ 7 | if (!::rdf4cpp::writer::write_str({__VA_ARGS__}, writer)) { \ 8 | return false; \ 9 | } 10 | 11 | #endif // RDF4CPP_PRIVATE_TRY_SERIALIZE_HPP 12 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=rdf4cpp_rdf4cpp 2 | sonar.organization=rdf4cpp 3 | 4 | 5 | # This is the name and version displayed in the SonarCloud UI. 6 | #sonar.projectName=rdf4cpp_testing_sonarqube 7 | #sonar.projectVersion=1.0 8 | 9 | 10 | # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. 11 | #sonar.sources=. 12 | 13 | # Encoding of the source code. Default is default system encoding 14 | #sonar.sourceEncoding=UTF-8 15 | -------------------------------------------------------------------------------- /src/rdf4cpp.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF4CPP_HPP 2 | #define RDF4CPP_RDF4CPP_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | /** 20 | * In this namespace the implementations of core RDF Concepts are defined. Class names are equal to terms defined in RDF 1.1 Concepts and Abstract Syntax". 21 | */ 22 | namespace rdf4cpp { 23 | } 24 | 25 | #endif //RDF4CPP_RDF4CPP_HPP 26 | -------------------------------------------------------------------------------- /src/rdf4cpp/ClosedNamespace.cpp: -------------------------------------------------------------------------------- 1 | #include "ClosedNamespace.hpp" 2 | 3 | namespace rdf4cpp { 4 | 5 | IRI ClosedNamespace::operator+(std::string_view suffix) const { 6 | if (auto found = cache_.find(suffix); found != cache_.end()) { 7 | return IRI{storage::identifier::NodeBackendHandle{found->second, node_storage_}}; 8 | } else { 9 | std::ostringstream oss; 10 | oss << "Resource " << suffix << " does not exist within the vocabulary " << namespace_iri_ << '.'; 11 | throw std::runtime_error{oss.str()}; 12 | } 13 | } 14 | 15 | void ClosedNamespace::clear() const { 16 | // this should not be cleared 17 | } 18 | 19 | } // namespace rdf4cpp 20 | -------------------------------------------------------------------------------- /src/rdf4cpp/ClosedNamespace.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_CLOSEDNAMESPACE_HPP 2 | #define RDF4CPP_CLOSEDNAMESPACE_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp { 7 | 8 | /** 9 | * A ClosedNamespace can not be extended to more IRIs after construction. 10 | */ 11 | struct ClosedNamespace : Namespace { 12 | /** 13 | * Constructs the ClosedNamespace with the fixed set of possible suffixes. 14 | * @tparam Suffixes Some range that has values convertible to std::string. 15 | * @param namespace_iri namespace IRI string. This will be used as prefix. IRI must not be encapsulated in <..>. 16 | * @param all_suffixes A range with all possible suffixes for this ClosedNamespace. 17 | * @param node_storage where the IRIs will live 18 | */ 19 | template 20 | requires std::convertible_to, std::string_view> 21 | ClosedNamespace(std::string_view namespace_iri, Suffixes all_suffixes, storage::DynNodeStoragePtr node_storage) 22 | : Namespace(namespace_iri, node_storage) { 23 | 24 | for (auto const &suffix : all_suffixes) { 25 | IRI iri{namespace_iri_ + std::string{suffix}, node_storage}; 26 | this->cache_.emplace(suffix, iri.backend_handle().id()); 27 | } 28 | } 29 | 30 | /** 31 | * Create an IRI with the suffix added to the ClosedNamespace. 32 | * @param suffix suffix that is appended 33 | * @return the constructed IRI 34 | * @throws std::runtime_exception if a suffix is available within the namespace 35 | */ 36 | IRI operator+(std::string_view suffix) const override; 37 | 38 | /** 39 | * Clear has no effect on a ClosedNamespace. 40 | */ 41 | void clear() const override; 42 | }; 43 | 44 | } // namespace rdf4cpp 45 | 46 | #endif //RDF4CPP_CLOSEDNAMESPACE_HPP 47 | -------------------------------------------------------------------------------- /src/rdf4cpp/Expected.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_EXPECTED_HPP 2 | #define RDF4CPP_EXPECTED_HPP 3 | 4 | /** 5 | * Workaround for buggy std::expected detection logic in 6 | * (std::expected does not work on clang yet, nonstd/expected.hpp does not honor feature test macro) 7 | * 8 | * Additionally the API of std::expected is different from nonstd::expected so it is not a drop in replacement. 9 | */ 10 | 11 | #define nsel_CONFIG_SELECT_EXPECTED 1 // do not attempt to use std::expected 12 | #include 13 | 14 | #endif // RDF4CPP_EXPECTED_HPP 15 | -------------------------------------------------------------------------------- /src/rdf4cpp/InvalidNode.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_INVALIDNODE_HPP 2 | #define RDF4CPP_INVALIDNODE_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp { 7 | struct InvalidNode : std::runtime_error { 8 | explicit InvalidNode(std::string const &msg) 9 | : runtime_error(msg) { 10 | } 11 | explicit InvalidNode(char const *msg) 12 | : runtime_error(msg) { 13 | } 14 | }; 15 | } // namespace rdf4cpp 16 | 17 | #endif //RDF4CPP_INVALIDNODE_HPP 18 | -------------------------------------------------------------------------------- /src/rdf4cpp/Namespace.cpp: -------------------------------------------------------------------------------- 1 | #include "Namespace.hpp" 2 | 3 | namespace rdf4cpp { 4 | 5 | Namespace::Namespace(std::string_view namespace_iri, storage::DynNodeStoragePtr node_storage) 6 | : namespace_iri_{namespace_iri}, node_storage_{node_storage} { 7 | } 8 | 9 | std::string_view Namespace::name_space() const noexcept { 10 | return namespace_iri_; 11 | } 12 | 13 | storage::DynNodeStoragePtr Namespace::node_storage() const { 14 | return node_storage_; 15 | } 16 | 17 | IRI Namespace::operator+(std::string_view suffix) const { 18 | if (auto found = cache_.find(suffix); found != cache_.end()) { 19 | return IRI{storage::identifier::NodeBackendHandle{found->second, node_storage_}}; 20 | } else { 21 | std::string namespace_iri{namespace_iri_}; 22 | namespace_iri.append(suffix); 23 | 24 | IRI iri{namespace_iri, node_storage_}; 25 | cache_.emplace(suffix, iri.backend_handle().id()); 26 | return iri; 27 | } 28 | } 29 | 30 | void Namespace::clear() const { 31 | cache_.clear(); 32 | cache_.rehash(0); 33 | } 34 | 35 | } // namespace rdf4cpp 36 | -------------------------------------------------------------------------------- /src/rdf4cpp/Namespace.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_NAMESPACE_HPP 2 | #define RDF4CPP_NAMESPACE_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace rdf4cpp { 13 | 14 | /** 15 | * Namespace provides a simple tool to create IRIs from a certain namespace and vocabulary. Each Namespace instance maintains an internal cache to save roundtrip to storage::NodeStorage.
16 | * Example: 17 | * @code 18 | * Namespace ex("http://example.com/); 19 | * IRI me = ex + "me"; 20 | * @endcode 21 | */ 22 | struct Namespace { 23 | protected: 24 | /** 25 | * The IRI string of the namespace. 26 | */ 27 | std::string namespace_iri_; 28 | 29 | /** 30 | * NodeStorage from which IRI objects are created. 31 | */ 32 | storage::DynNodeStoragePtr node_storage_; 33 | 34 | // TODO: a faster, less memory efficient map would be better. 35 | /** 36 | * Cache storing the
NodeBackendHandle
for prefixes. This saves roundtrips to NodeStorage. 37 | */ 38 | mutable dice::sparse_map::sparse_map, std::equal_to<>> cache_; 40 | 41 | public: 42 | /** 43 | * Namespace Constructor 44 | * @param namespace_iri namespace IRI string. This will be used as prefix. IRI must not be encapsulated in <..>. 45 | * @param node_storage where the IRIs will live 46 | */ 47 | explicit Namespace(std::string_view namespace_iri, 48 | storage::DynNodeStoragePtr node_storage = storage::default_node_storage); 49 | 50 | /** 51 | * @return IRI string of the Namespace 52 | */ 53 | std::string_view name_space() const noexcept; 54 | 55 | /** 56 | * @return NodeStorage used to create
IRI
s from this Namespace. 57 | */ 58 | storage::DynNodeStoragePtr node_storage() const; 59 | 60 | /** 61 | * Create an IRI with the suffix added to the Namespace. 62 | * @param suffix suffix that is appended 63 | * @return the constructed IRI 64 | */ 65 | virtual IRI operator+(std::string_view suffix) const; 66 | 67 | /** 68 | * Clears the cache. 69 | */ 70 | virtual void clear() const; 71 | }; 72 | } // namespace rdf4cpp 73 | 74 | #endif //RDF4CPP_NAMESPACE_HPP 75 | -------------------------------------------------------------------------------- /src/rdf4cpp/Statement.cpp: -------------------------------------------------------------------------------- 1 | #include "Statement.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp { 6 | 7 | Statement::Statement(Node subject, Node predicate, Node object) noexcept : query::TriplePattern{subject, predicate, object} { 8 | } 9 | 10 | bool Statement::valid() const noexcept { 11 | return ((subject().is_iri() || subject().is_blank_node()) 12 | && (predicate().is_iri()) 13 | && (object().is_iri() || object().is_literal() || object().is_blank_node())); 14 | } 15 | 16 | [[nodiscard]] Statement Statement::to_node_storage(storage::DynNodeStoragePtr node_storage) const { 17 | Statement st; 18 | auto it = st.begin(); 19 | for (auto const &item : *this) { 20 | *(it++) = item.to_node_storage(node_storage); 21 | } 22 | return st; 23 | } 24 | 25 | [[nodiscard]] Statement Statement::try_get_in_node_storage(storage::DynNodeStoragePtr node_storage) const noexcept { 26 | Statement st; 27 | auto it = st.begin(); 28 | for (auto const &item : *this) { 29 | *(it++) = item.try_get_in_node_storage(node_storage); 30 | } 31 | return st; 32 | } 33 | 34 | bool Statement::serialize_ntriples(writer::BufWriterParts writer) const noexcept { 35 | return writer::write_quad(*this, writer, nullptr); 36 | } 37 | 38 | bool Statement::serialize_turtle(writer::SerializationState &state, writer::BufWriterParts writer) const noexcept { 39 | return writer::write_quad(*this, writer, &state); 40 | } 41 | 42 | } // namespace rdf4cpp 43 | -------------------------------------------------------------------------------- /src/rdf4cpp/Statement.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_STATEMENT_HPP 2 | #define RDF4CPP_STATEMENT_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp { 7 | 8 | struct Statement : query::TriplePattern { 9 | // TODO: adjust API to Quad 10 | 11 | Statement() noexcept = default; 12 | Statement(Node subject, Node predicate, Node object) noexcept; 13 | 14 | [[nodiscard]] bool valid() const noexcept; 15 | 16 | [[nodiscard]] Statement to_node_storage(storage::DynNodeStoragePtr node_storage) const; 17 | [[nodiscard]] Statement try_get_in_node_storage(storage::DynNodeStoragePtr node_storage) const noexcept; 18 | 19 | bool serialize_ntriples(writer::BufWriterParts writer) const noexcept; 20 | bool serialize_turtle(writer::SerializationState &state, writer::BufWriterParts writer) const noexcept; 21 | }; 22 | } // namespace rdf4cpp 23 | #endif //RDF4CPP_STATEMENT_HPP 24 | -------------------------------------------------------------------------------- /src/rdf4cpp/bnode_mngt/NodeGenerator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_UTIL_IBLANKNODEIDGENERATORBACKEND 2 | #define RDF4CPP_RDF_UTIL_IBLANKNODEIDGENERATORBACKEND 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::bnode_mngt { 8 | 9 | template 10 | concept NodeGenerator = requires (G &g, storage::DynNodeStoragePtr node_storage) { 11 | /** 12 | * Generate a new node 13 | */ 14 | { g.generate(node_storage) } -> std::convertible_to; 15 | }; 16 | 17 | 18 | } // namespace rdf4cpp::bnode_mngt 19 | 20 | #endif //RDF4CPP_RDF_UTIL_IBLANKNODEIDGENERATORBACKEND 21 | -------------------------------------------------------------------------------- /src/rdf4cpp/bnode_mngt/NodeScope.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_NODESCOPE_HPP 2 | #define RDF4CPP_NODESCOPE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace rdf4cpp::bnode_mngt { 10 | 11 | template 12 | concept NodeScope = requires (S &s, std::string_view label, storage::DynNodeStoragePtr node_storage) { 13 | /** 14 | * Retrieve the node for the given label 15 | * or generate a new one based on the label. 16 | */ 17 | { s.get_or_generate_node(label, node_storage) } -> std::convertible_to; 18 | }; 19 | 20 | struct DynNodeScopePtr { 21 | private: 22 | struct VTable { 23 | Node (*get_or_generate_node)(void *self, std::string_view label, storage::DynNodeStoragePtr node_storage); 24 | 25 | template 26 | static VTable const *make() { 27 | static constexpr VTable vtable{ 28 | .get_or_generate_node = [](void *self, std::string_view label, storage::DynNodeStoragePtr node_storage) -> Node { 29 | return static_cast(self)->get_or_generate_node(label, node_storage); 30 | }}; 31 | 32 | return &vtable; 33 | } 34 | }; 35 | 36 | void *instance_; 37 | VTable const *vtable_; 38 | 39 | public: 40 | DynNodeScopePtr() noexcept : DynNodeScopePtr{nullptr} { 41 | } 42 | 43 | DynNodeScopePtr(std::nullptr_t) noexcept : instance_{nullptr}, vtable_{nullptr} { 44 | } 45 | 46 | template 47 | DynNodeScopePtr(S &scope) noexcept : instance_{&scope}, vtable_{VTable::make()} { 48 | } 49 | 50 | template 51 | DynNodeScopePtr(S *scope) noexcept : instance_{scope}, vtable_{VTable::make()} { 52 | } 53 | 54 | [[nodiscard]] Node get_or_generate_node(std::string_view label, storage::DynNodeStoragePtr node_storage) const { 55 | return vtable_->get_or_generate_node(instance_, label, node_storage); 56 | } 57 | 58 | friend bool operator==(DynNodeScopePtr const &self, std::nullptr_t) noexcept { 59 | return self.instance_ == nullptr; 60 | } 61 | }; 62 | static_assert(NodeScope); 63 | 64 | } //namespace rdf4cpp::bnode_mngt 65 | 66 | #endif //RDF4CPP_NODESCOPE_HPP 67 | -------------------------------------------------------------------------------- /src/rdf4cpp/bnode_mngt/NodeScopeManager.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_NODESCOPEMANAGER_HPP 2 | #define RDF4CPP_NODESCOPEMANAGER_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::bnode_mngt { 8 | 9 | /** 10 | * Manages a set of scopes, by name. 11 | * I.e. you call subscope with a given name, if there is no scope 12 | * referring to that name a new one is created. Otherwise you get the previously created scope. 13 | * 14 | * You can think of this as a map. 15 | */ 16 | template 17 | concept NodeScopeManager = requires (M &m, std::string_view scope_name) { 18 | /** 19 | * Get the scope for the given name. 20 | * The name might be a graph or filename. 21 | */ 22 | { m.scope(scope_name) } -> NodeScope; 23 | }; 24 | 25 | struct DynNodeScopeManagerPtr { 26 | private: 27 | struct VTable { 28 | DynNodeScopePtr (*scope)(void *self, std::string_view); 29 | 30 | template 31 | static VTable const *make() { 32 | static constexpr VTable vtable{ 33 | .scope = [](void *self, std::string_view label) -> DynNodeScopePtr { 34 | return static_cast(self)->scope(label); 35 | }}; 36 | 37 | return &vtable; 38 | } 39 | }; 40 | 41 | void *instance_; 42 | VTable const *vtable_; 43 | 44 | public: 45 | DynNodeScopeManagerPtr() noexcept : DynNodeScopeManagerPtr{nullptr} { 46 | } 47 | 48 | DynNodeScopeManagerPtr(std::nullptr_t) noexcept : instance_{nullptr}, vtable_{nullptr} { 49 | } 50 | 51 | template 52 | DynNodeScopeManagerPtr(M &manager) noexcept : instance_{&manager}, vtable_{VTable::make()} { 53 | } 54 | 55 | template 56 | DynNodeScopeManagerPtr(M *manager) noexcept : instance_{manager}, vtable_{VTable::make()} { 57 | } 58 | 59 | [[nodiscard]] DynNodeScopePtr scope(std::string_view label) { 60 | return vtable_->scope(instance_, label); 61 | } 62 | 63 | friend bool operator==(DynNodeScopeManagerPtr const &self, std::nullptr_t) noexcept { 64 | return self.instance_ == nullptr; 65 | } 66 | }; 67 | static_assert(NodeScopeManager); 68 | 69 | } // namespace rdf4cpp::bnode_mngt 70 | 71 | #endif //RDF4CPP_NODESCOPEMANAGER_HPP 72 | -------------------------------------------------------------------------------- /src/rdf4cpp/bnode_mngt/reference_backends/generator/IncreasingIdGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace rdf4cpp::bnode_mngt { 9 | 10 | namespace generator_detail { 11 | static constexpr size_t max_generated_id_size = std::numeric_limits::digits10; 12 | } //namespace generator_detail 13 | 14 | IncreasingIdGenerator::IncreasingIdGenerator(std::string prefix, size_t const initial_value) noexcept : prefix_{std::move(prefix)}, 15 | counter_{initial_value} { 16 | BlankNode::validate(prefix_); // throws if invalid 17 | } 18 | 19 | BlankNode IncreasingIdGenerator::generate(storage::DynNodeStoragePtr node_storage) noexcept { 20 | static thread_local std::string buf; 21 | 22 | buf.clear(); 23 | buf.resize(prefix_.size() + generator_detail::max_generated_id_size); 24 | 25 | auto write_it = std::copy(prefix_.begin(), prefix_.end(), buf.data()); 26 | std::to_chars_result const res = std::to_chars(write_it, write_it + generator_detail::max_generated_id_size, counter_.fetch_add(1, std::memory_order_relaxed)); 27 | assert(res.ec == std::errc{}); 28 | 29 | // checked in constructor, can use make_unchecked 30 | return BlankNode::make_unchecked(std::string_view{buf.data(), static_cast(res.ptr - buf.data())}, node_storage); 31 | } 32 | 33 | } //namespace rdf4cpp::bnode_mngt 34 | -------------------------------------------------------------------------------- /src/rdf4cpp/bnode_mngt/reference_backends/generator/IncreasingIdGenerator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_UTIL_REFERENCEBACKENDS_INCREASINGBLANKNODEIDGENERATOR_HPP 2 | #define RDF4CPP_RDF_UTIL_REFERENCEBACKENDS_INCREASINGBLANKNODEIDGENERATOR_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace rdf4cpp::bnode_mngt { 10 | 11 | /** 12 | * Generates identifiers consisting of a optional prefix and an integer in increasing value. 13 | */ 14 | struct IncreasingIdGenerator { 15 | private: 16 | std::string prefix_; 17 | std::atomic counter_; 18 | 19 | public: 20 | /** 21 | * Creates a generator from a given start value and a prefix 22 | * 23 | * @param prefix prefix for the generated ids 24 | * @param initial_value initial value of the counter 25 | * @throws ParsingError if the prefix is not a valid blank node identifier 26 | */ 27 | explicit IncreasingIdGenerator(std::string prefix = "", size_t initial_value = 0) noexcept; 28 | 29 | BlankNode generate(storage::DynNodeStoragePtr node_storage) noexcept; 30 | }; 31 | static_assert(NodeGenerator); 32 | 33 | } //namespace rdf4cpp::bnode_mngt 34 | 35 | #endif //RDF4CPP_RDF_UTIL_REFERENCEBACKENDS_INCREASINGBLANKNODEIDGENERATOR_HPP 36 | -------------------------------------------------------------------------------- /src/rdf4cpp/bnode_mngt/reference_backends/generator/RandomIdGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace rdf4cpp::bnode_mngt { 7 | 8 | namespace generator_detail { 9 | 10 | static constexpr std::array bnode_id_valid_chars{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 11 | 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 12 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', 13 | '7', '8', '9'}; 14 | 15 | static constexpr size_t generated_id_size = 32; 16 | 17 | } //namespace generator_detail 18 | 19 | RandomIdGenerator::RandomIdGenerator() : RandomIdGenerator{std::random_device{}()} { 20 | } 21 | 22 | RandomIdGenerator::RandomIdGenerator(uint64_t const seed) : rng_{seed}, 23 | dist_{0, generator_detail::bnode_id_valid_chars.size() - 1} { 24 | } 25 | 26 | BlankNode RandomIdGenerator::generate(storage::DynNodeStoragePtr node_storage) noexcept { 27 | std::array buf; 28 | 29 | { 30 | std::unique_lock lock{mutex_}; 31 | std::ranges::generate(buf, [this]() { return this->next_char(); }); 32 | } 33 | 34 | return BlankNode::make_unchecked(std::string_view{buf.data(), buf.size()}, node_storage); 35 | } 36 | 37 | char RandomIdGenerator::next_char() { 38 | return generator_detail::bnode_id_valid_chars[dist_(rng_)]; 39 | } 40 | 41 | } //namespace rdf4cpp::bnode_mngt 42 | -------------------------------------------------------------------------------- /src/rdf4cpp/bnode_mngt/reference_backends/generator/RandomIdGenerator.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_UTIL_REFERENCEBACKENDS_RANDOMBLANKNODEIDGENERATOR_HPP 2 | #define RDF4CPP_RDF_UTIL_REFERENCEBACKENDS_RANDOMBLANKNODEIDGENERATOR_HPP 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace rdf4cpp::bnode_mngt { 10 | 11 | /** 12 | * Generates 32-char long random ids consisting of [0-9a-z] 13 | */ 14 | struct RandomIdGenerator { 15 | private: 16 | std::mutex mutable mutex_; 17 | std::mt19937_64 rng_; 18 | std::uniform_int_distribution dist_; 19 | 20 | char next_char(); 21 | public: 22 | /** 23 | * Creates a generator by seeding it with os entropy 24 | */ 25 | RandomIdGenerator(); 26 | 27 | /** 28 | * Creates a generator by seeding it with the given seed 29 | * @param seed seed for the random generator 30 | */ 31 | explicit RandomIdGenerator(uint64_t seed); 32 | 33 | BlankNode generate(storage::DynNodeStoragePtr node_storage = storage::default_node_storage) noexcept; 34 | }; 35 | static_assert(NodeGenerator); 36 | 37 | } //namespace rdf4cpp::bnode_mngt 38 | 39 | #endif //RDF4CPP_RDF_UTIL_REFERENCEBACKENDS_RANDOMBLANKNODEIDGENERATOR_HPP 40 | -------------------------------------------------------------------------------- /src/rdf4cpp/bnode_mngt/reference_backends/scope_manager/MergeNodeScopeManager.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_REFERENCENODESCOPEMANAGER_HPP 2 | #define RDF4CPP_REFERENCENODESCOPEMANAGER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace rdf4cpp::bnode_mngt { 11 | 12 | template> requires std::is_default_constructible_v 13 | struct MergeNodeScopeManager { 14 | using node_scope_storage_type = dice::sparse_map::sparse_map< 15 | std::string, 16 | std::unique_ptr, 17 | dice::hash::DiceHashwyhash, 18 | std::equal_to<>>; 19 | 20 | node_scope_storage_type scopes; 21 | 22 | S &scope(std::string_view name) noexcept { 23 | if (auto it = scopes.find(name); it != scopes.end()) { 24 | return *it->second; 25 | } 26 | 27 | auto [it, inserted] = scopes.emplace(name, std::make_unique()); 28 | assert(inserted); 29 | return *it->second; 30 | } 31 | }; 32 | static_assert(NodeScopeManager>); 33 | 34 | } // namespace rdf4cpp::bnode_mngt 35 | 36 | #endif //RDF4CPP_REFERENCENODESCOPEMANAGER_HPP 37 | -------------------------------------------------------------------------------- /src/rdf4cpp/bnode_mngt/reference_backends/scope_manager/UnionNodeScopeManager.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_SINGLESCOPEMANAGER_HPP 2 | #define RDF4CPP_SINGLESCOPEMANAGER_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::bnode_mngt { 7 | 8 | /** 9 | * A scope manager that always gives you the same scope. 10 | * Primarily useful for using union-semantics during parsing. 11 | */ 12 | template> requires std::is_default_constructible_v 13 | struct UnionNodeScopeManager { 14 | S scope_; 15 | 16 | S &scope([[maybe_unused]] std::string_view name) noexcept { 17 | return scope_; 18 | } 19 | }; 20 | static_assert(NodeScopeManager>); 21 | 22 | } // namespace rdf4cpp::bnode_mngt 23 | 24 | #endif //RDF4CPP_SINGLESCOPEMANAGER_HPP 25 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/owl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_DATATYPES_OWL_HPP 2 | #define RDF4CPP_DATATYPES_OWL_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::datatypes::owl { 8 | } 9 | 10 | #endif //RDF4CPP_DATATYPES_OWL_HPP 11 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/owl/Real.cpp: -------------------------------------------------------------------------------- 1 | #include "Real.hpp" 2 | #include 3 | 4 | namespace rdf4cpp::datatypes::registry { 5 | 6 | #ifndef DOXYGEN_PARSER 7 | template<> 8 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 9 | try { 10 | return cpp_type{s}; 11 | } catch (std::runtime_error const &e) { 12 | throw InvalidNode{std::format("{} parsing error: {}", identifier, e.what())}; 13 | } 14 | } 15 | 16 | template<> 17 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 18 | return value != 0; 19 | } 20 | 21 | template<> 22 | std::partial_ordering capabilities::Comparable::compare(cpp_type const &lhs, cpp_type const &rhs) noexcept { 23 | if (lhs < rhs) { 24 | return std::partial_ordering::less; 25 | } else if (rhs < lhs) { 26 | return std::partial_ordering::greater; 27 | } else { 28 | return std::partial_ordering::equivalent; 29 | } 30 | } 31 | 32 | template<> 33 | nonstd::expected::abs_result_cpp_type, DynamicError> capabilities::Numeric::abs(cpp_type const &operand) noexcept { 34 | return boost::multiprecision::abs(operand); 35 | } 36 | 37 | template<> 38 | nonstd::expected::round_result_cpp_type, DynamicError> capabilities::Numeric::round(cpp_type const &operand) noexcept { 39 | return boost::multiprecision::round(operand); 40 | } 41 | 42 | template<> 43 | nonstd::expected::floor_result_cpp_type, DynamicError> capabilities::Numeric::floor(cpp_type const &operand) noexcept { 44 | return boost::multiprecision::floor(operand); 45 | } 46 | 47 | template<> 48 | nonstd::expected::ceil_result_cpp_type, DynamicError> capabilities::Numeric::ceil(cpp_type const &operand) noexcept { 49 | return boost::multiprecision::ceil(operand); 50 | } 51 | #endif 52 | 53 | template struct LiteralDatatypeImpl; 57 | 58 | } // rdf4cpp::datatypes::registry 59 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/owl/Real.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_OWL_REAL_HPP 2 | #define RDF4CPP_OWL_REAL_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace rdf4cpp::datatypes::registry { 10 | 11 | inline constexpr util::ConstexprString owl_real{"http://www.w3.org/2002/07/owl#real"}; 12 | 13 | #ifndef DOXYGEN_PARSER 14 | template<> 15 | struct DatatypeMapping { 16 | using cpp_datatype = boost::multiprecision::cpp_bin_float_quad; // IEEE quad float 17 | }; 18 | 19 | template<> 20 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s); 21 | 22 | template<> 23 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept; 24 | 25 | template<> 26 | std::partial_ordering capabilities::Comparable::compare(cpp_type const &lhs, cpp_type const &rhs) noexcept; 27 | 28 | template<> 29 | nonstd::expected::abs_result_cpp_type, DynamicError> capabilities::Numeric::abs(cpp_type const &operand) noexcept; 30 | 31 | template<> 32 | nonstd::expected::round_result_cpp_type, DynamicError> capabilities::Numeric::round(cpp_type const &operand) noexcept; 33 | 34 | template<> 35 | nonstd::expected::floor_result_cpp_type, DynamicError> capabilities::Numeric::floor(cpp_type const &operand) noexcept; 36 | 37 | template<> 38 | nonstd::expected::ceil_result_cpp_type, DynamicError> capabilities::Numeric::ceil(cpp_type const &operand) noexcept; 39 | #endif 40 | 41 | extern template struct LiteralDatatypeImpl; 45 | 46 | } // rdf4cpp::datatypes::registry 47 | 48 | 49 | namespace rdf4cpp::datatypes::owl { 50 | 51 | struct Real : registry::LiteralDatatypeImpl {}; 55 | 56 | } // rdf4cpp::datatypes::owl 57 | 58 | 59 | namespace rdf4cpp::datatypes::registry::instantiation_detail { 60 | 61 | [[maybe_unused]] inline owl::Real const owl_real_instance; 62 | 63 | } // namespace rdf4cpp::datatypes::registry::instantiation_detail 64 | 65 | #endif //RDF4CPP_OWL_REAL_HPP 66 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/rdf.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_DATATYPES_RDF_HPP 2 | #define RDF4CPP_DATATYPES_RDF_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::datatypes::rdf { 7 | } 8 | 9 | #endif // RDF4CPP_DATATYPES_RDF_HPP 10 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/rdf/LangString.cpp: -------------------------------------------------------------------------------- 1 | #include "LangString.hpp" 2 | 3 | namespace rdf4cpp::datatypes::registry { 4 | 5 | template struct LiteralDatatypeImpl; 8 | 9 | } // namespace rdf4cpp::datatypes::registry 10 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/registry/util/mz/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Mark Gillard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_DATATYPES_XSD_HPP 2 | #define RDF4CPP_DATATYPES_XSD_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | 43 | /** 44 | * Namespace where datatypes from XSD are implemented. 45 | * @see https://www.w3.org/TR/xmlschema-2/#built-in-datatypes 46 | */ 47 | namespace rdf4cpp::datatypes::xsd { 48 | // 49 | } 50 | 51 | #endif //RDF4CPP_DATATYPES_XSD_HPP 52 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/AnyURI.cpp: -------------------------------------------------------------------------------- 1 | #include "AnyURI.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace rdf4cpp::datatypes::registry { 10 | 11 | #ifndef DOXYGEN_PARSER 12 | template<> 13 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 14 | auto e = IRIView{s}.quick_validate(true); 15 | if (e != IRIFactoryError::Ok) { 16 | throw InvalidNode(std::format("http://www.w3.org/2001/XMLSchema#anyURI parsing error: invalid IRI: {}", e)); 17 | } 18 | return cpp_type{s}; 19 | } 20 | 21 | template<> 22 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 23 | return writer::write_str(value, writer); 24 | } 25 | 26 | template<> 27 | bool capabilities::Default::serialize_simplified_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 28 | return writer::write_str(value, writer); 29 | } 30 | 31 | template<> 32 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 33 | return !value.empty(); 34 | } 35 | 36 | template<> 37 | std::partial_ordering capabilities::Comparable::compare(cpp_type const &lhs, cpp_type const &rhs) noexcept { 38 | return lhs <=> rhs; 39 | } 40 | #endif 41 | 42 | template struct LiteralDatatypeImpl; 46 | 47 | } // namespace rdf4cpp::datatypes::registry 48 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/AnyURI.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_XSD_ANYURI_HPP 2 | #define RDF4CPP_XSD_ANYURI_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace rdf4cpp::datatypes::registry { 12 | 13 | #ifndef DOXYGEN_PARSER 14 | template<> 15 | struct DatatypeMapping { 16 | using cpp_datatype = std::string; 17 | }; 18 | 19 | template<> 20 | struct DatatypePromotionMapping { 21 | using promoted = xsd::String; 22 | }; 23 | 24 | template<> 25 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s); 26 | 27 | template<> 28 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept; 29 | 30 | template<> 31 | bool capabilities::Default::serialize_simplified_string(cpp_type const &value, writer::BufWriterParts writer) noexcept; 32 | 33 | template<> 34 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept; 35 | 36 | #endif 37 | 38 | extern template struct LiteralDatatypeImpl; 42 | 43 | } // namespace rdf4cpp::datatypes::registry 44 | 45 | 46 | namespace rdf4cpp::datatypes::xsd { 47 | 48 | struct AnyURI : registry::LiteralDatatypeImpl {}; 53 | 54 | } // namespace rdf4cpp::datatypes::xsd 55 | 56 | 57 | namespace rdf4cpp::datatypes::registry::instantiation_detail { 58 | 59 | [[maybe_unused]] inline xsd::AnyURI const xsd_any_uri_instance; 60 | 61 | } // namespace rdf4cpp::datatypes::registry::instantiation_detail 62 | 63 | #endif //RDF4CPP_XSD_ANYURI_HPP 64 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/Boolean.cpp: -------------------------------------------------------------------------------- 1 | #include "Boolean.hpp" 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace rdf4cpp::datatypes::registry { 8 | 9 | #ifndef DOXYGEN_PARSER 10 | template<> 11 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 12 | if (s == "true" || s == "1") { 13 | return true; 14 | } else if (s == "false" || s == "0") { 15 | return false; 16 | } else { 17 | throw InvalidNode{std::format("{} Parsing Error: found {}, expected true/false", identifier, s)}; 18 | } 19 | } 20 | 21 | template<> 22 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 23 | static constexpr std::array lut{"false", "true"}; 24 | return writer::write_str(lut[static_cast(value)], writer); 25 | } 26 | 27 | template<> 28 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 29 | return value; 30 | } 31 | 32 | template<> 33 | std::optional capabilities::Inlineable::try_into_inlined(cpp_type const &value) noexcept { 34 | return util::pack(value); 35 | } 36 | 37 | template<> 38 | capabilities::Inlineable::cpp_type capabilities::Inlineable::from_inlined(storage::identifier::LiteralID inlined) noexcept { 39 | return util::unpack(inlined); 40 | } 41 | #endif 42 | 43 | template struct LiteralDatatypeImpl; 48 | 49 | } // namespace rdf4cpp::datatypes::registry 50 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/Boolean.hpp: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @file 4 | * Registers xsd:boolean with DatatypeRegistry 5 | */ 6 | 7 | #ifndef RDF4CPP_XSD_BOOLEAN_HPP 8 | #define RDF4CPP_XSD_BOOLEAN_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace rdf4cpp::datatypes::registry { 15 | 16 | #ifndef DOXYGEN_PARSER 17 | template<> 18 | struct DatatypeMapping { 19 | using cpp_datatype = bool; 20 | }; 21 | 22 | template<> 23 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s); 24 | 25 | template<> 26 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept; 27 | 28 | template<> 29 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept; 30 | 31 | template<> 32 | std::optional capabilities::Inlineable::try_into_inlined(cpp_type const &value) noexcept; 33 | 34 | template<> 35 | capabilities::Inlineable::cpp_type capabilities::Inlineable::from_inlined(storage::identifier::LiteralID inlined) noexcept; 36 | #endif 37 | 38 | extern template struct LiteralDatatypeImpl; 43 | 44 | } // namespace rdf4cpp::datatypes::registry 45 | 46 | 47 | namespace rdf4cpp::datatypes::xsd { 48 | 49 | struct Boolean : registry::LiteralDatatypeImpl {}; 54 | 55 | } // namespace rdf4cpp::datatypes::xsd 56 | 57 | 58 | namespace rdf4cpp::datatypes::registry::instantiation_detail { 59 | 60 | [[maybe_unused]] inline xsd::Boolean const xsd_boolean_instance; 61 | 62 | } // namespace rdf4cpp::datatypes::registry::instantiation_detail 63 | 64 | #endif //RDF4CPP_XSD_BOOLEAN_HPP 65 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/String.cpp: -------------------------------------------------------------------------------- 1 | #include "String.hpp" 2 | 3 | namespace rdf4cpp::datatypes::registry { 4 | 5 | #ifndef DOXYGEN_PARSER 6 | template<> 7 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 8 | return !value.empty(); 9 | } 10 | #endif 11 | 12 | template struct LiteralDatatypeImpl; 16 | 17 | } // namespace rdf4cpp::datatypes::registry 18 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/String.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_XSD_STRING_HPP 2 | #define RDF4CPP_XSD_STRING_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace rdf4cpp::datatypes::registry { 9 | 10 | #ifndef DOXYGEN_PARSER 11 | template<> 12 | struct DatatypeMapping { 13 | using cpp_datatype = std::string_view; 14 | }; 15 | 16 | template<> 17 | inline capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view) { 18 | // dummy implementation, actual implementation in Literal 19 | assert(false); 20 | __builtin_unreachable(); 21 | } 22 | 23 | template<> 24 | inline bool capabilities::Default::serialize_canonical_string(cpp_type const &, writer::BufWriterParts) noexcept { 25 | // dummy implementation, actual implementation in Literal 26 | assert(false); 27 | __builtin_unreachable(); 28 | } 29 | 30 | template<> 31 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept; 32 | #endif 33 | 34 | extern template struct LiteralDatatypeImpl; 38 | 39 | } // namespace rdf4cpp::datatypes::registry 40 | 41 | 42 | namespace rdf4cpp::datatypes::xsd { 43 | 44 | struct String : registry::LiteralDatatypeImpl {}; 48 | 49 | } // namespace rdf4cpp::datatypes::xsd 50 | 51 | 52 | namespace rdf4cpp::datatypes::registry::instantiation_detail { 53 | 54 | [[maybe_unused]] inline xsd::String const xsd_string_instance; 55 | 56 | } // namespace rdf4cpp::datatypes::registry::instantiation_detail 57 | 58 | #endif //RDF4CPP_XSD_STRING_HPP 59 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/non_negative/UnsignedByte.cpp: -------------------------------------------------------------------------------- 1 | #include "UnsignedByte.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::datatypes::registry { 6 | 7 | #ifndef DOXYGEN_PARSER 8 | template<> 9 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 10 | return util::from_chars(s); 11 | } 12 | 13 | template<> 14 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 15 | return util::to_chars_canonical(value, writer); 16 | } 17 | 18 | 19 | template<> 20 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 21 | return value != 0; 22 | } 23 | #endif 24 | 25 | template struct LiteralDatatypeImpl; 32 | 33 | } // namespace rdf4cpp::datatypes::registry 34 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/non_negative/UnsignedInt.cpp: -------------------------------------------------------------------------------- 1 | #include "UnsignedInt.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::datatypes::registry { 6 | 7 | #ifndef DOXYGEN_PARSER 8 | template<> 9 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 10 | return util::from_chars(s); 11 | } 12 | 13 | template<> 14 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 15 | return util::to_chars_canonical(value, writer); 16 | } 17 | 18 | template<> 19 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 20 | return value != 0; 21 | } 22 | #endif 23 | 24 | template struct LiteralDatatypeImpl; 31 | 32 | } // namespace rdf4cpp::datatypes::registry 33 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/non_negative/UnsignedLong.cpp: -------------------------------------------------------------------------------- 1 | #include "UnsignedLong.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::datatypes::registry { 6 | 7 | #ifndef DOXYGEN_PARSER 8 | template<> 9 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 10 | return util::from_chars(s); 11 | } 12 | 13 | template<> 14 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 15 | return util::to_chars_canonical(value, writer); 16 | } 17 | 18 | template<> 19 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 20 | return value != 0; 21 | } 22 | 23 | template<> 24 | template<> 25 | nonstd::expected::cpp_type, DynamicError> capabilities::Subtype::from_supertype<0>(super_cpp_type<0> const &value) noexcept { 26 | if (value > std::numeric_limits::max() || value < std::numeric_limits::min()) { 27 | return nonstd::make_unexpected(DynamicError::InvalidValueForCast); 28 | } 29 | 30 | return static_cast(value); 31 | } 32 | #endif 33 | 34 | template struct LiteralDatatypeImpl; 41 | 42 | } // namespace rdf4cpp::datatypes::registry 43 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/non_negative/UnsignedShort.cpp: -------------------------------------------------------------------------------- 1 | #include "UnsignedShort.hpp" 2 | #include 3 | 4 | namespace rdf4cpp::datatypes::registry { 5 | 6 | #ifndef DOXYGEN_PARSER 7 | template<> 8 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 9 | return util::from_chars(s); 10 | } 11 | 12 | template<> 13 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 14 | return util::to_chars_canonical(value, writer); 15 | } 16 | 17 | 18 | template<> 19 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 20 | return value != 0; 21 | } 22 | #endif 23 | 24 | template struct LiteralDatatypeImpl; 31 | 32 | } // namespace rdf4cpp::datatypes::registry 33 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/signed/Byte.cpp: -------------------------------------------------------------------------------- 1 | #include "Byte.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::datatypes::registry { 6 | 7 | #ifndef DOXYGEN_PARSER 8 | template<> 9 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 10 | return util::from_chars(s); 11 | } 12 | 13 | template<> 14 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 15 | return util::to_chars_canonical(value, writer); 16 | } 17 | 18 | 19 | template<> 20 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 21 | return value != 0; 22 | } 23 | #endif 24 | 25 | template struct LiteralDatatypeImpl; 32 | 33 | } // namespace rdf4cpp::datatypes::registry 34 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/signed/Byte.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_XSD_BYTE_HPP 2 | #define RDF4CPP_XSD_BYTE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace rdf4cpp::datatypes::registry { 13 | 14 | #ifndef DOXYGEN_PARSER 15 | template<> 16 | struct DatatypeMapping { 17 | using cpp_datatype = int8_t; 18 | }; 19 | 20 | template<> 21 | struct DatatypeSupertypeMapping { 22 | using supertype = xsd::Short; 23 | }; 24 | 25 | template<> 26 | struct DatatypeNumericStubMapping { 27 | using numeric_impl_type = xsd::Integer; 28 | }; 29 | 30 | template<> 31 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s); 32 | 33 | template<> 34 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept; 35 | 36 | 37 | template<> 38 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept; 39 | #endif 40 | 41 | extern template struct LiteralDatatypeImpl; 48 | 49 | } // namespace rdf4cpp::datatypes::registry 50 | 51 | 52 | namespace rdf4cpp::datatypes::xsd { 53 | 54 | struct Byte : registry::LiteralDatatypeImpl {}; 61 | 62 | } // namespace rdf4cpp::datatypes::xsd 63 | 64 | 65 | namespace rdf4cpp::datatypes::registry::instantiation_detail { 66 | 67 | [[maybe_unused]] inline xsd::Byte const xsd_byte_instance; 68 | 69 | } // namespace rdf4cpp::datatypes::registry::instantiation_detail 70 | 71 | #endif //RDF4CPP_XSD_BYTE_HPP 72 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/signed/Int.cpp: -------------------------------------------------------------------------------- 1 | #include "Int.hpp" 2 | 3 | #include 4 | #include 5 | 6 | namespace rdf4cpp::datatypes::registry { 7 | 8 | #ifndef DOXYGEN_PARSER 9 | template<> 10 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 11 | return util::from_chars(s); 12 | } 13 | 14 | template<> 15 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 16 | return util::to_chars_canonical(value, writer); 17 | } 18 | 19 | template<> 20 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 21 | return value != 0; 22 | } 23 | #endif 24 | 25 | template struct LiteralDatatypeImpl; 32 | 33 | } // namespace rdf4cpp::datatypes::registry 34 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/signed/Int.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_XSD_INT_HPP 2 | #define RDF4CPP_XSD_INT_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace rdf4cpp::datatypes::registry { 13 | 14 | #ifndef DOXYGEN_PARSER 15 | template<> 16 | struct DatatypeMapping { 17 | using cpp_datatype = int32_t; 18 | }; 19 | 20 | template<> 21 | struct DatatypeSupertypeMapping { 22 | using supertype = xsd::Long; 23 | }; 24 | 25 | template<> 26 | struct DatatypeNumericStubMapping { 27 | using numeric_impl_type = xsd::Integer; 28 | }; 29 | 30 | template<> 31 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s); 32 | 33 | template<> 34 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept; 35 | 36 | template<> 37 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept; 38 | #endif 39 | 40 | extern template struct LiteralDatatypeImpl; 47 | 48 | } // namespace rdf4cpp::datatypes::registry 49 | 50 | 51 | namespace rdf4cpp::datatypes::xsd { 52 | 53 | struct Int : registry::LiteralDatatypeImpl {}; 60 | 61 | } // namespace rdf4cpp::datatypes::xsd 62 | 63 | 64 | namespace rdf4cpp::datatypes::registry::instantiation_detail { 65 | 66 | [[maybe_unused]] inline xsd::Int const xsd_int_instance; 67 | 68 | } // namespace rdf4cpp::datatypes::registry::instantiation_detail 69 | 70 | #endif //RDF4CPP_XSD_INT_HPP 71 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/signed/Long.cpp: -------------------------------------------------------------------------------- 1 | #include "Long.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::datatypes::registry { 6 | 7 | #ifndef DOXYGEN_PARSER 8 | template<> 9 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 10 | return util::from_chars(s); 11 | } 12 | 13 | template<> 14 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 15 | return util::to_chars_canonical(value, writer); 16 | } 17 | 18 | template<> 19 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 20 | return value != 0; 21 | } 22 | 23 | template<> 24 | template<> 25 | nonstd::expected::cpp_type, DynamicError> capabilities::Subtype::from_supertype<0>(super_cpp_type<0> const &value) noexcept { 26 | if (value > std::numeric_limits::max() || value < std::numeric_limits::min()) { 27 | return nonstd::make_unexpected(DynamicError::InvalidValueForCast); 28 | } 29 | 30 | return static_cast(value); 31 | } 32 | #endif 33 | 34 | template struct LiteralDatatypeImpl; 41 | 42 | } // namespace rdf4cpp::datatypes::registry 43 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/signed/Short.cpp: -------------------------------------------------------------------------------- 1 | #include "Short.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::datatypes::registry { 6 | 7 | #ifndef DOXYGEN_PARSER 8 | template<> 9 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { 10 | return util::from_chars(s); 11 | } 12 | 13 | template<> 14 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept { 15 | return util::to_chars_canonical(value, writer); 16 | } 17 | 18 | 19 | template<> 20 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept { 21 | return value != 0; 22 | } 23 | #endif 24 | 25 | template struct LiteralDatatypeImpl; 32 | 33 | } // namespace rdf4cpp::datatypes::registry 34 | -------------------------------------------------------------------------------- /src/rdf4cpp/datatypes/xsd/integers/signed/Short.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_XSD_SHORT_HPP 2 | #define RDF4CPP_XSD_SHORT_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | namespace rdf4cpp::datatypes::registry { 13 | 14 | #ifndef DOXYGEN_PARSER 15 | template<> 16 | struct DatatypeMapping { 17 | using cpp_datatype = int16_t; 18 | }; 19 | 20 | template<> 21 | struct DatatypeSupertypeMapping { 22 | using supertype = xsd::Int; 23 | }; 24 | 25 | template<> 26 | struct DatatypeNumericStubMapping { 27 | using numeric_impl_type = xsd::Integer; 28 | }; 29 | 30 | template<> 31 | capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s); 32 | 33 | template<> 34 | bool capabilities::Default::serialize_canonical_string(cpp_type const &value, writer::BufWriterParts writer) noexcept; 35 | 36 | 37 | template<> 38 | bool capabilities::Logical::effective_boolean_value(cpp_type const &value) noexcept; 39 | #endif 40 | 41 | extern template struct LiteralDatatypeImpl; 48 | 49 | } // namespace rdf4cpp::datatypes::registry 50 | 51 | 52 | namespace rdf4cpp::datatypes::xsd { 53 | 54 | struct Short : registry::LiteralDatatypeImpl {}; 61 | 62 | } // namespace rdf4cpp::datatypes::xsd 63 | 64 | 65 | namespace rdf4cpp::datatypes::registry::instantiation_detail { 66 | 67 | [[maybe_unused]] inline xsd::Short const xsd_short_instance; 68 | 69 | } // namespace rdf4cpp::datatypes::registry::instantiation_detail 70 | 71 | #endif //RDF4CPP_XSD_SHORT_HPP 72 | -------------------------------------------------------------------------------- /src/rdf4cpp/namespaces.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_NAMESPACES_HPP 2 | #define RDF4CPP_NAMESPACES_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /** 14 | * This namespace contains common XML namespaces used for RDF standard vocabulary. 15 | */ 16 | namespace rdf4cpp::namespaces { 17 | } 18 | 19 | #endif //RDF4CPP_NAMESPACES_HPP 20 | -------------------------------------------------------------------------------- /src/rdf4cpp/namespaces/BFLC.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_BFLC_HPP 2 | #define RDF4CPP_BFLC_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::namespaces { 7 | 8 | /** 9 | * A ClosedNamespace for http://id.loc.gov/ontologies/bflc/ version http://id.loc.gov/ontologies/bflc-1-2-0/ 10 | */ 11 | struct BFLC : ClosedNamespace { 12 | static constexpr std::string_view prefix = "http://id.loc.gov/ontologies/bflc/"; 13 | static constexpr std::array suffixes = {"AppliesTo", "CreatorCharacteristic", "DemographicGroup", 14 | "Eidr", "EncodingLevel", "GrooveCutting", "ImageBitDepth", 15 | "MachineModel", "MetadataLicensor", "OperatingSystem", 16 | "PrimaryContribution", "ProgrammingLanguage", "Relation", 17 | "Relationship", "Relief", "SeriesAnalysis", "SeriesClassification", 18 | "SeriesNumbering", "SeriesNumberingPeculiarities", 19 | "SeriesProvider", "SeriesSequentialDesignation", "SeriesTracing", 20 | "SeriesTreatment", "TransliteratedTitle"}; 21 | 22 | explicit BFLC(storage::DynNodeStoragePtr node_storage = storage::default_node_storage) : ClosedNamespace{prefix, suffixes, node_storage} { 23 | } 24 | }; 25 | 26 | } // namespace rdf4cpp::namespaces 27 | 28 | #endif //RDF4CPP_BFLC_HPP 29 | -------------------------------------------------------------------------------- /src/rdf4cpp/namespaces/FOAF.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_FOAF_HPP 2 | #define RDF4CPP_FOAF_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::namespaces { 7 | 8 | /** 9 | * A ClosedNamespace for http://xmlns.com/foaf/0.1/ version https://xmlns.com/foaf/spec/20140114.rdf 10 | */ 11 | struct FOAF : ClosedNamespace { 12 | static constexpr std::string_view prefix = "http://xmlns.com/foaf/0.1/"; 13 | static constexpr std::array suffixes = {"Person", "name", "homepage", "openid", "img", "Document", 14 | "Image", "mbox", "depiction", "Agent", "Group", "member", 15 | "workplaceHomepage", "membershipClass", "Organization", 16 | "OnlineAccount", "PersonalProfileDocument", "maker", 17 | "primaryTopic", "Project", "LabelProperty", "OnlineChatAccount", 18 | "account", "accountServiceHomepage", "accountName", 19 | "OnlineEcommerceAccount", "OnlineGamingAccount", 20 | "isPrimaryTopicOf", "knows", "made", "page", "weblog", 21 | "aimChatID", "based", "currentProject", "depicts", "familyName", 22 | "firstName", "focus", "gender", "givenName", "icqChatID", 23 | "interest", "jabberID", "lastName", "logo", "msnChatID", 24 | "myersBriggs", "nick", "pastProject", "phone", "plan", 25 | "publications", "schoolHomepage", "skypeID", "thumbnail", 26 | "tipjar", "title", "topic", "workInfoHomepage", "yahooChatID", 27 | "age", "birthday", "sha", "status", "dnaChecksum", "family", 28 | "fundedBy", "geekcode", "givenname", "holdsAccount", "surname", "theme"}; 29 | 30 | explicit FOAF(storage::DynNodeStoragePtr node_storage = storage::default_node_storage) : ClosedNamespace{prefix, suffixes, node_storage} { 31 | } 32 | }; 33 | 34 | } // namespace rdf4cpp::namespaces 35 | 36 | #endif //RDF4CPP_FOAF_HPP 37 | -------------------------------------------------------------------------------- /src/rdf4cpp/namespaces/PREMIS3.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_PREMIS3_HPP 2 | #define RDF4CPP_PREMIS3_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::namespaces { 7 | 8 | /** 9 | * A ClosedNamespace for http://www.loc.gov/premis/rdf/v3/ version https://id.loc.gov/ontologies/premis-3-0-0 10 | */ 11 | struct PREMIS3 : ClosedNamespace { 12 | static constexpr std::string_view prefix = "http://www.loc.gov/premis/rdf/v3/"; 13 | static constexpr std::array suffixes = {"Action", "Agent", "Bitstream", "Copyright", 14 | "Dependency", "EnvironmentCharacteristic", "Event", 15 | "File", "Fixity", "HardwareAgent", "Identifier", 16 | "Inhibitor", "InstitutionalPolicy", "IntellectualEntity", 17 | "License", "Object", "Organization", "OutcomeStatus", 18 | "Person", "PreservationPolicy", "Representation", 19 | "RightsBasis", "RightsStatus", "Rule", "Signature", 20 | "SignatureEncoding", "SignificantProperties", "SoftwareAgent", 21 | "Statute", "StorageLocation", "StorageMedium", "act", 22 | "allows", "basis", "characteristic", "citation", 23 | "compositionLevel", "dependency", "determinationDate", 24 | "documentation", "encoding", "endDate", "fixity", 25 | "governs", "identifier", "inhibitedBy", "inhibits", 26 | "jurisdiction", "key", "medium", "note", "originalName", 27 | "outcome", "outcomeNote", "policy", "prohibits", "purpose", 28 | "rationale", "relationship", "restriction", "rightsStatus", 29 | "signature", "size", "startDate", "storedAt", "terms", 30 | "validationRules", "version"}; 31 | 32 | explicit PREMIS3(storage::DynNodeStoragePtr node_storage = storage::default_node_storage) : ClosedNamespace{prefix, suffixes, node_storage} { 33 | } 34 | }; 35 | 36 | } // namespace rdf4cpp::namespaces 37 | 38 | #endif //RDF4CPP_PREMIS3_HPP 39 | -------------------------------------------------------------------------------- /src/rdf4cpp/namespaces/RDF.cpp: -------------------------------------------------------------------------------- 1 | #include "RDF.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::namespaces { 6 | 7 | RDF::RDF(storage::DynNodeStoragePtr node_storage) : ClosedNamespace{prefix, suffixes, node_storage} {} 8 | 9 | IRI RDF::operator+(std::string_view suffix) const { 10 | if (suffix.starts_with('_')) { 11 | size_t id; 12 | auto from_chars_result = std::from_chars(suffix.data() + 1, suffix.data() + suffix.size(), id); 13 | if (from_chars_result.ec == std::errc() and from_chars_result.ptr == suffix.data() + suffix.size()) { 14 | std::string normalized_suffix = std::string{"_"} + std::to_string(id); 15 | return Namespace::operator+(normalized_suffix); // add rdf:_ which is also a valid member of this namespace 16 | } else { 17 | std::ostringstream oss; 18 | oss << "Resource " << suffix << " does not exist within the vocabulary " << namespace_iri_ << '.'; 19 | throw std::runtime_error{oss.str()}; 20 | } 21 | } 22 | return ClosedNamespace::operator+(suffix); 23 | } 24 | 25 | } // namespace rdf4cpp::namespaces -------------------------------------------------------------------------------- /src/rdf4cpp/namespaces/RDF.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_NAMESPACE_RDF_HPP 2 | #define RDF4CPP_NAMESPACE_RDF_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::namespaces { 7 | 8 | /** 9 | * A ClosedNamespace for http://www.w3.org/1999/02/22-rdf-syntax-ns#
10 | * All rdfs:ContainerMembershipProperty like rdf:_1, rdf:_2, rdf:_3, ... are also available. 11 | */ 12 | struct RDF : ClosedNamespace { 13 | public: 14 | static constexpr std::string_view prefix = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; 15 | static constexpr std::array suffixes = {"HTML", "langString", "PlainLiteral", 16 | "type", "Property", "Statement", "subject", 17 | "predicate", "object", "Bag", "Seq", "Alt", 18 | "value", "List", "nil", "first", "rest", 19 | "XMLLiteral", "JSON", "CompoundLiteral", 20 | "language", "direction"}; 21 | 22 | explicit RDF(storage::DynNodeStoragePtr node_storage = storage::default_node_storage); 23 | 24 | IRI operator+(std::string_view suffix) const override; 25 | }; 26 | 27 | } // namespace rdf4cpp::namespaces 28 | 29 | #endif //RDF4CPP_NAMESPACE_RDF_HPP 30 | -------------------------------------------------------------------------------- /src/rdf4cpp/namespaces/RDFS.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDFS_HPP 2 | #define RDF4CPP_RDFS_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::namespaces { 7 | 8 | /** 9 | * A ClosedNamespace for https://www.w3.org/TR/rdf-schema/ 10 | */ 11 | struct RDFS : ClosedNamespace { 12 | public: 13 | static constexpr std::string_view prefix = "http://www.w3.org/2000/01/rdf-schema#"; 14 | static constexpr std::array suffixes = {"Resource", "Class", "Literal", "Datatype", "range", 15 | "domain", "subClassOf", "subPropertyOf", "label", 16 | "comment", "Container", "ContainerMembershipProperty", 17 | "member", "seeAlso", "isDefinedBy"}; 18 | 19 | explicit RDFS(storage::DynNodeStoragePtr node_storage = storage::default_node_storage) : ClosedNamespace{prefix, suffixes, node_storage} { 20 | } 21 | }; 22 | 23 | } // namespace rdf4cpp::namespaces 24 | 25 | #endif //RDF4CPP_RDFS_HPP 26 | -------------------------------------------------------------------------------- /src/rdf4cpp/namespaces/XSD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_NAMESPACE_XSD_HPP 2 | #define RDF4CPP_NAMESPACE_XSD_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::namespaces { 7 | 8 | /** 9 | * A Namespace for http://www.w3.org/2001/XMLSchema# 10 | */ 11 | struct XSD : Namespace { 12 | static constexpr std::string_view prefix = "http://xmlns.com/XSD/0.1/"; 13 | 14 | explicit XSD(storage::DynNodeStoragePtr node_storage = storage::default_node_storage) : Namespace{prefix, node_storage} { 15 | } 16 | }; 17 | 18 | } // namespace rdf4cpp::namespaces 19 | 20 | #endif //RDF4CPP_NAMESPACE_XSD_HPP 21 | -------------------------------------------------------------------------------- /src/rdf4cpp/parser/ParsingState.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_PARSER_PARSINGSTATE_HPP 2 | #define RDF4CPP_RDF_PARSER_PARSINGSTATE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace rdf4cpp::parser { 10 | 11 | /** 12 | * The publicly known internal state of the IStreamQuadIterator. 13 | * Values of this type can be used to specify the initial state of IStreamQuadIterators, and 14 | * therefore states can be reused between different instantiations. 15 | * 16 | * @example 17 | * @code 18 | * IStreamQuadIterator::state_type state{}; 19 | * { 20 | * std::ifstream ifs_1{"some_file.txt"}; 21 | * IStreamQuadIterator qit_1{ifs_1, ParsingFlags::none(), &state}; 22 | * // consume qit_1 ... 23 | * } 24 | * 25 | * { 26 | * std::ifstream ifs_2{"some_other_file.txt"}; 27 | * IStreamQuadIterator qit_2{ifs_2, ParsingFlags::none(), &state}; 28 | * // consume qit_2 with state inherited from qit_1 ... 29 | * } 30 | * @endcode 31 | */ 32 | struct ParsingState { 33 | /** 34 | * The initial prefixes the parser has knowledge of 35 | * @note default value is an empty map 36 | */ 37 | IRIFactory iri_factory{}; 38 | 39 | /** 40 | * The node storage to put the parsed quads into 41 | */ 42 | storage::DynNodeStoragePtr node_storage = storage::default_node_storage; 43 | 44 | /** 45 | * The node scope manager to use while parsing files 46 | * the scopes names passed in are the graph identifiers. 47 | * 48 | * By default no scope is used, this means all blank nodes will keep the labels from the file. 49 | */ 50 | bnode_mngt::DynNodeScopeManagerPtr blank_node_scope_manager = nullptr; 51 | 52 | /** 53 | * A function that is called for each node that is parsed. 54 | * To discard a triple throw an exception from this function. 55 | */ 56 | std::function inspect_node_func = []([[maybe_unused]] Node const &n) { /* noop */ }; 57 | }; 58 | 59 | } //namespace rdf4cpp::parser 60 | 61 | #endif //RDF4CPP_RDF_PARSER_PARSINGSTATE_HPP 62 | -------------------------------------------------------------------------------- /src/rdf4cpp/parser/RDFFileParser.cpp: -------------------------------------------------------------------------------- 1 | #include "RDFFileParser.hpp" 2 | 3 | 4 | #include 5 | 6 | namespace rdf4cpp::parser { 7 | RDFFileParser::RDFFileParser(const std::string &file_path, flags_type flags, state_type *state) 8 | : file_path_(file_path), flags_(flags), state_(state) { 9 | } 10 | RDFFileParser::RDFFileParser(std::string &&file_path, flags_type flags, state_type *state) 11 | : file_path_(std::move(file_path)), flags_(flags), state_(state) { 12 | } 13 | RDFFileParser::iterator RDFFileParser::begin() const { 14 | FILE *stream = fopen_fastseq(file_path_.c_str(), "r"); 15 | if (stream == nullptr) { 16 | throw std::system_error{errno, std::system_category()}; 17 | } 18 | 19 | return {std::move(stream), flags_, state_}; 20 | } 21 | std::default_sentinel_t RDFFileParser::end() const noexcept { 22 | return {}; 23 | } 24 | 25 | RDFFileParser::iterator::iterator() 26 | : stream_(nullptr), iter_(nullptr) { 27 | } 28 | RDFFileParser::iterator::iterator(FILE *&&stream, 29 | flags_type flags, 30 | state_type *state) 31 | : stream_(stream), 32 | iter_(std::make_unique(stream_, reinterpret_cast(&fread), reinterpret_cast(&ferror), 33 | flags, state)) { 34 | } 35 | RDFFileParser::iterator::~iterator() noexcept { 36 | fclose(stream_); 37 | } 38 | RDFFileParser::iterator::reference RDFFileParser::iterator::operator*() const noexcept { 39 | return (*iter_).operator*(); 40 | } 41 | RDFFileParser::iterator::pointer RDFFileParser::iterator::operator->() const noexcept { 42 | return (*iter_).operator->(); 43 | } 44 | RDFFileParser::iterator &RDFFileParser::iterator::operator++() { 45 | ++(*iter_); 46 | return *this; 47 | } 48 | bool RDFFileParser::iterator::operator==(const RDFFileParser::iterator &other) const noexcept { 49 | return iter_ == other.iter_; 50 | } 51 | bool operator==(const RDFFileParser::iterator &iter, std::default_sentinel_t s) noexcept { 52 | return (*iter.iter_) == s; 53 | } 54 | bool operator==(std::default_sentinel_t s, const RDFFileParser::iterator &iter) noexcept { 55 | return iter == s; 56 | } 57 | } // namespace rdf4cpp::parser 58 | -------------------------------------------------------------------------------- /src/rdf4cpp/query/QuadPattern.cpp: -------------------------------------------------------------------------------- 1 | #include "QuadPattern.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::query { 6 | 7 | QuadPattern::QuadPattern(Node graph, Node subject, Node predicate, Node object) noexcept : entries_{graph, subject, predicate, object} { 8 | } 9 | 10 | bool QuadPattern::valid() const noexcept { 11 | return (graph().is_iri() || graph().is_variable()) 12 | && !subject().is_literal() 13 | && (predicate().is_iri() || predicate().is_variable()) 14 | && !object().null(); 15 | } 16 | 17 | QuadPattern::operator std::string() const { 18 | auto s = writer::StringWriter::oneshot([this](auto &w) { 19 | return writer::write_quad(*this, w, nullptr); 20 | }); 21 | 22 | s.pop_back(); // remove newline 23 | return s; 24 | } 25 | 26 | std::ostream &operator<<(std::ostream &os, const QuadPattern &pattern) { 27 | os << static_cast(pattern); 28 | return os; 29 | } 30 | 31 | QuadPattern QuadPattern::to_node_storage(storage::DynNodeStoragePtr node_storage) const { 32 | QuadPattern qp; 33 | auto it = qp.begin(); 34 | for (const auto &item : *this) { 35 | *(it++) = item.to_node_storage(node_storage); 36 | } 37 | return qp; 38 | } 39 | 40 | QuadPattern QuadPattern::try_get_in_node_storage(storage::DynNodeStoragePtr node_storage) const noexcept { 41 | QuadPattern qp; 42 | auto it = qp.begin(); 43 | for (const auto &item : *this) { 44 | *(it++) = item.try_get_in_node_storage(node_storage); 45 | } 46 | return qp; 47 | } 48 | 49 | TriplePattern const &QuadPattern::without_graph() const noexcept { 50 | static_assert(sizeof(QuadPattern) == 4 * sizeof(Node)); 51 | static_assert(sizeof(TriplePattern) == 3 * sizeof(Node)); 52 | return *reinterpret_cast(entries_.data() + 1); 53 | } 54 | 55 | } // namespace rdf4cpp::query -------------------------------------------------------------------------------- /src/rdf4cpp/query/Solution.cpp: -------------------------------------------------------------------------------- 1 | #include "Solution.hpp" 2 | 3 | namespace rdf4cpp::query { 4 | 5 | template 6 | std::vector Solution::extract_variables(Pat const &quad) { 7 | std::vector variables; 8 | for (const auto &entry : quad) { 9 | if (entry.is_variable()) 10 | variables.push_back(entry.as_variable()); 11 | } 12 | return variables; 13 | } 14 | 15 | std::vector> init(std::vector const &variables) { 16 | std::vector> partial_mapping; 17 | for (const auto &var_name : variables) 18 | partial_mapping.emplace_back(var_name, Node()); 19 | return partial_mapping; 20 | } 21 | 22 | Solution::Solution(std::vector const &variables) : partial_mapping{init(variables)} {} 23 | Solution::Solution(QuadPattern const &qp) : Solution{extract_variables(qp)} {} 24 | Solution::Solution(TriplePattern const &tp) : Solution{extract_variables(tp)} {} 25 | 26 | Node Solution::operator[](Variable const &variable) const noexcept { 27 | size_t pos = std::distance(partial_mapping.begin(), std::find_if(partial_mapping.begin(), partial_mapping.end(), 28 | [=](const auto &item) { return item.first == variable; })); 29 | if (pos < partial_mapping.size()) { 30 | return partial_mapping[pos].second; 31 | } else { 32 | return {}; 33 | } 34 | } 35 | 36 | Node const &Solution::operator[](size_t pos) const noexcept { 37 | assert(pos < partial_mapping.size()); 38 | return partial_mapping[pos].second; 39 | } 40 | 41 | Node &Solution::operator[](size_t pos) noexcept { 42 | assert(pos < partial_mapping.size()); 43 | return partial_mapping[pos].second; 44 | } 45 | 46 | Variable const &Solution::variable(size_t pos) const noexcept { 47 | assert(pos < partial_mapping.size()); 48 | return partial_mapping[pos].first; 49 | } 50 | 51 | size_t Solution::variable_count() const noexcept { 52 | return partial_mapping.size(); 53 | } 54 | 55 | size_t Solution::bound_count() const noexcept { 56 | return std::count_if(partial_mapping.begin(), partial_mapping.end(), 57 | [](const auto &item) { return not item.second.null(); }); 58 | } 59 | 60 | Solution::iterator Solution::begin() noexcept { 61 | return partial_mapping.begin(); 62 | } 63 | 64 | Solution::iterator Solution::end() noexcept { 65 | return partial_mapping.end(); 66 | } 67 | 68 | Solution::const_iterator Solution::begin() const noexcept { 69 | return partial_mapping.begin(); 70 | } 71 | 72 | Solution::const_iterator Solution::end() const noexcept { 73 | return partial_mapping.end(); 74 | } 75 | 76 | } // namespace rdf4cpp::query -------------------------------------------------------------------------------- /src/rdf4cpp/query/Solution.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_SOLUTION_HPP 2 | #define RDF4CPP_SOLUTION_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::query { 8 | 9 | struct Solution { 10 | private: 11 | using storage_type = std::vector>; 12 | 13 | public: 14 | using value_type = std::pair; 15 | using reference = value_type &; 16 | using const_reference = value_type const &; 17 | using pointer = value_type *; 18 | using const_pointer = value_type const *; 19 | using iterator = typename storage_type::iterator; 20 | using const_iterator = typename storage_type::const_iterator; 21 | using size_type = size_t; 22 | using difference_type = ptrdiff_t; 23 | 24 | private: 25 | storage_type partial_mapping; 26 | 27 | template 28 | static std::vector extract_variables(Pat const &pat); 29 | 30 | public: 31 | Solution() noexcept = default; 32 | 33 | explicit Solution(std::vector const &variables); 34 | explicit Solution(QuadPattern const &qp); 35 | explicit Solution(TriplePattern const &tp); 36 | 37 | Node operator[](Variable const &variable) const noexcept; 38 | 39 | Node const &operator[](size_t pos) const noexcept; 40 | Node &operator[](size_t pos) noexcept; 41 | 42 | [[nodiscard]] Variable const &variable(size_t pos) const noexcept; 43 | 44 | [[nodiscard]] size_t variable_count() const noexcept; 45 | [[nodiscard]] size_t bound_count() const noexcept; 46 | 47 | [[nodiscard]] iterator begin() noexcept; 48 | [[nodiscard]] iterator end() noexcept; 49 | [[nodiscard]] const_iterator begin() const noexcept; 50 | [[nodiscard]] const_iterator end() const noexcept; 51 | }; 52 | } // namespace rdf4cpp::query 53 | 54 | #endif //RDF4CPP_SOLUTION_HPP 55 | -------------------------------------------------------------------------------- /src/rdf4cpp/query/TriplePattern.cpp: -------------------------------------------------------------------------------- 1 | #include "TriplePattern.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::query { 6 | 7 | TriplePattern::TriplePattern(Node subject, Node predicate, Node object) noexcept : entries_{subject, predicate, object} { 8 | } 9 | 10 | bool TriplePattern::valid() const noexcept { 11 | return !subject().null() && !subject().is_literal() 12 | && !predicate().null() && (predicate().is_iri() || predicate().is_variable()) 13 | && !object().null(); 14 | } 15 | 16 | TriplePattern::operator std::string() const { 17 | auto s = writer::StringWriter::oneshot([this](auto &w) { 18 | return writer::write_quad(*this, w, nullptr); 19 | }); 20 | 21 | s.pop_back(); // remove newline 22 | return s; 23 | } 24 | 25 | std::ostream &operator<<(std::ostream &os, TriplePattern const &pattern) { 26 | os << static_cast(pattern); 27 | return os; 28 | } 29 | 30 | TriplePattern TriplePattern::to_node_storage(storage::DynNodeStoragePtr node_storage) const { 31 | TriplePattern tp; 32 | auto it = tp.begin(); 33 | for (const auto &item : *this) { 34 | *(it++) = item.to_node_storage(node_storage); 35 | } 36 | return tp; 37 | } 38 | 39 | TriplePattern TriplePattern::try_get_in_node_storage(storage::DynNodeStoragePtr node_storage) const noexcept { 40 | TriplePattern tp; 41 | auto it = tp.begin(); 42 | for (const auto &item : *this) { 43 | *(it++) = item.try_get_in_node_storage(node_storage); 44 | } 45 | return tp; 46 | } 47 | 48 | } // namespace rdf4cpp::query -------------------------------------------------------------------------------- /src/rdf4cpp/regex/Regex.cpp: -------------------------------------------------------------------------------- 1 | #include "Regex.hpp" 2 | #include 3 | #include 4 | 5 | namespace rdf4cpp::regex { 6 | 7 | Regex::Regex(std::string_view regex, flag_type const flags) : impl{std::make_unique(regex, flags)} { 8 | } 9 | 10 | Regex::Regex(Regex &&other) noexcept = default; 11 | Regex &Regex::operator=(Regex &&other) noexcept = default; 12 | Regex::~Regex() noexcept = default; 13 | 14 | bool Regex::regex_match(std::string_view const str) const noexcept { 15 | return this->impl->regex_match(str); 16 | } 17 | 18 | bool Regex::regex_search(std::string_view const str) const noexcept { 19 | return this->impl->regex_search(str); 20 | } 21 | 22 | RegexReplacer Regex::make_replacer(std::string_view const rewrite) const { 23 | return RegexReplacer{std::make_unique(*this->impl, rewrite)}; 24 | } 25 | 26 | } //namespace rdf4cpp::regex 27 | -------------------------------------------------------------------------------- /src/rdf4cpp/regex/RegexError.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_REGEX_REGEXERROR_HPP 2 | #define RDF4CPP_RDF_REGEX_REGEXERROR_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::regex { 8 | 9 | /** 10 | * The type of exception thrown by functions in the rdf4cpp::regex library. 11 | */ 12 | struct RegexError : std::runtime_error { 13 | explicit RegexError(char const *msg) : std::runtime_error{msg} {} 14 | explicit RegexError(std::string const &msg) : std::runtime_error{msg} {} 15 | }; 16 | 17 | } //namespace rdf4cpp::regex 18 | 19 | #endif //RDF4CPP_RDF_REGEX_REGEXERROR_HPP 20 | -------------------------------------------------------------------------------- /src/rdf4cpp/regex/RegexFlags.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_REGEX_REGEXFLAGS_HPP 2 | #define RDF4CPP_RDF_REGEX_REGEXFLAGS_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::regex { 8 | 9 | enum struct RegexFlag : uint8_t { 10 | DotAll = 1 << 0, 11 | CaseInsensitive = 1 << 1, 12 | Literal = 1 << 2, 13 | Multiline = 1 << 3, 14 | RemoveWhitespace = 1 << 4, 15 | }; 16 | 17 | struct RegexFlags { 18 | private: 19 | using flag_u_type = std::underlying_type_t; 20 | flag_u_type flags; 21 | 22 | constexpr RegexFlags(uint8_t const flags) noexcept : flags{flags} {} 23 | 24 | public: 25 | constexpr RegexFlags(RegexFlag const flag) noexcept 26 | : flags{static_cast(flag)} { 27 | } 28 | 29 | static constexpr RegexFlags none() noexcept { 30 | return RegexFlags{0}; 31 | } 32 | 33 | [[nodiscard]] constexpr bool contains(RegexFlag const flag) const noexcept { 34 | return flags & static_cast(flag); 35 | } 36 | 37 | constexpr RegexFlags &operator|=(RegexFlags const other) noexcept { 38 | this->flags |= other.flags; 39 | return *this; 40 | } 41 | 42 | constexpr RegexFlags operator|(RegexFlags const other) const noexcept { 43 | auto cpy = *this; 44 | return (cpy |= other); 45 | } 46 | 47 | constexpr RegexFlags &operator|=(RegexFlag const flag) noexcept { 48 | this->flags |= static_cast(flag); 49 | return *this; 50 | } 51 | 52 | constexpr RegexFlags operator|(RegexFlag const flag) const noexcept { 53 | auto cpy = *this; 54 | return (cpy |= flag); 55 | } 56 | }; 57 | 58 | constexpr RegexFlags operator|(RegexFlag const f1, RegexFlag const f2) noexcept { 59 | return RegexFlags::none() | f1 | f2; 60 | } 61 | 62 | } //namespace rdf4cpp::regex 63 | 64 | #endif //RDF4CPP_RDF_REGEX_REGEXFLAGS_HPP 65 | -------------------------------------------------------------------------------- /src/rdf4cpp/regex/RegexReplacer.cpp: -------------------------------------------------------------------------------- 1 | #include "RegexReplacer.hpp" 2 | #include 3 | 4 | namespace rdf4cpp::regex { 5 | 6 | RegexReplacer::RegexReplacer(std::unique_ptr &&impl) noexcept : impl{std::move(impl)} { 7 | } 8 | 9 | RegexReplacer::RegexReplacer() noexcept = default; 10 | RegexReplacer::RegexReplacer(RegexReplacer &&other) noexcept = default; 11 | RegexReplacer &RegexReplacer::operator=(RegexReplacer &&other) noexcept = default; 12 | RegexReplacer::~RegexReplacer() noexcept = default; 13 | 14 | void RegexReplacer::regex_replace(std::string &str) const noexcept { 15 | if (this->impl != nullptr) { 16 | this->impl->regex_replace(str); 17 | } 18 | } 19 | 20 | } //namespace rdf4cpp::regex 21 | -------------------------------------------------------------------------------- /src/rdf4cpp/regex/RegexReplacer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_REGEX_REGEXREPLACER_HPP 2 | #define RDF4CPP_RDF_REGEX_REGEXREPLACER_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::regex { 8 | 9 | struct RegexReplacer { 10 | using value_type = char; 11 | private: 12 | friend struct Regex; 13 | 14 | struct Impl; 15 | std::unique_ptr impl; 16 | 17 | explicit RegexReplacer(std::unique_ptr &&impl) noexcept; 18 | public: 19 | RegexReplacer() noexcept; 20 | RegexReplacer(RegexReplacer &&other) noexcept; 21 | RegexReplacer &operator=(RegexReplacer &&other) noexcept; 22 | ~RegexReplacer() noexcept; 23 | 24 | /** 25 | * Replaces all matches of the regex this replacer was constructed from in "str" with "rewrite" it 26 | * was constructed with. 27 | * Within "rewrite", dollar-escaped digits ($1 to $9) can be 28 | * used to insert text matching corresponding parenthesized group 29 | * from the pattern. $0 in "rewrite" refers to the entire matching 30 | * 31 | * @param str the string to replace all matches with 32 | * @warning behaviour is undefined if this replacer lives longer than the regex it was created from 33 | * 34 | * @example 35 | * @code 36 | * Regex const r{"[0-9]+"}; 37 | * RegexReplacer const repl = r.make_replacer("$0th"); 38 | * 39 | * std::string s = "Hello 13 World"; 40 | * repl.regex_replace(s); 41 | * 42 | * assert(s == "Hello 13th World); 43 | * @endcode 44 | */ 45 | void regex_replace(std::string &str) const noexcept; 46 | }; 47 | 48 | } //namespace rdf4cpp::regex 49 | 50 | #endif //RDF4CPP_RDF_REGEX_REGEXREPLACER_HPP 51 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/NodeStorage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace rdf4cpp::storage { 5 | 6 | namespace reference_node_storage { 7 | SyncReferenceNodeStorage default_instance{}; 8 | } // reference_node_storage 9 | 10 | #ifndef DOXYGEN_PARSER 11 | DynNodeStoragePtr default_node_storage{reference_node_storage::default_instance}; 12 | #endif // DOXYGEN_PARSER 13 | 14 | } // namespace rdf4cpp::storage 15 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/identifier/LiteralID.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_LITERALID_HPP 2 | #define RDF4CPP_LITERALID_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace rdf4cpp::storage::identifier { 11 | /** 12 | *

An LiteralID identifies a Literal of a given type (e.g. xsd:integer, xsd:string, etc.) within a given NodeStorage.

13 | *

LiteralIDs are available in the range [0,(2^42-1)].

14 | */ 15 | struct __attribute__((__packed__)) LiteralID { 16 | static constexpr size_t width = 42; 17 | using underlying_type = uint64_t; 18 | 19 | private: 20 | underlying_type underlying: width; 21 | 22 | public: 23 | constexpr LiteralID() noexcept = default; 24 | 25 | /** 26 | * Constructor 27 | * @param underlying literal ID. MUST be smaller than 2^42. Bounds are not checked. 28 | */ 29 | explicit constexpr LiteralID(underlying_type const underlying) noexcept : underlying{underlying} { 30 | assert(underlying < (1UL << 42)); 31 | } 32 | 33 | constexpr LiteralID &operator++() noexcept { 34 | ++underlying; 35 | return *this; 36 | } 37 | 38 | [[nodiscard]] constexpr underlying_type to_underlying() const noexcept { 39 | return underlying; 40 | } 41 | 42 | explicit operator underlying_type() const noexcept { 43 | return underlying; 44 | } 45 | 46 | constexpr LiteralID operator++(int) noexcept { 47 | LiteralID new_literal_id{*this}; 48 | ++underlying; 49 | return new_literal_id; 50 | } 51 | 52 | constexpr LiteralID &operator--() noexcept { 53 | --underlying; 54 | return *this; 55 | } 56 | 57 | constexpr LiteralID operator--(int) noexcept { 58 | LiteralID new_literal_id{*this}; 59 | --underlying; 60 | return new_literal_id; 61 | } 62 | 63 | constexpr std::strong_ordering operator<=>(LiteralID const &) const noexcept = default; 64 | }; 65 | 66 | inline std::ostream &operator<<(std::ostream &os, LiteralID id) { 67 | os << "{ .underlying = " << id.to_underlying() << " }"; 68 | return os; 69 | } 70 | 71 | } // namespace rdf4cpp::storage::identifier 72 | #endif //RDF4CPP_LITERALID_HPP 73 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/identifier/RDFNodeType.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDFNODETYPE_HPP 2 | #define RDF4CPP_RDFNODETYPE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace rdf4cpp::storage::identifier { 9 | /** 10 | * Specifies whether an RDF node is a Variable, BlankNode, IRI or Literal. 11 | * The ordering BNode, IRI, Literal is the same as in SPARQL operator<. 12 | */ 13 | enum struct RDFNodeType : uint8_t { 14 | BNode = 0b00, 15 | IRI = 0b01, 16 | Literal = 0b10, 17 | Variable = 0b11, 18 | }; 19 | 20 | constexpr std::string_view to_string_view(RDFNodeType const node_type) noexcept { 21 | switch (node_type) { 22 | case RDFNodeType::Variable: return "Variable"; 23 | case RDFNodeType::BNode: return "BNode"; 24 | case RDFNodeType::IRI: return "IRI"; 25 | case RDFNodeType::Literal: return "Literal"; 26 | default: return "Undefined"; 27 | } 28 | } 29 | 30 | inline std::string to_string(RDFNodeType const node_type) noexcept { 31 | return std::string{to_string_view(node_type)}; 32 | } 33 | 34 | inline std::ostream &operator<<(std::ostream &os, RDFNodeType type) { 35 | os << to_string_view(type); 36 | return os; 37 | } 38 | 39 | } // namespace rdf4cpp::storage::identifier 40 | 41 | 42 | #endif //RDF4CPP_RDFNODETYPE_HPP 43 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/reference_node_storage/BNodeBackend.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_BNODEBACKEND_HPP 2 | #define RDF4CPP_BNODEBACKEND_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace rdf4cpp::storage::reference_node_storage { 10 | 11 | struct BNodeBackend { 12 | using view_type = view::BNodeBackendView; 13 | using id_type = identifier::NodeID; 14 | 15 | size_t hash; 16 | dice::template_library::static_string identifier; 17 | 18 | explicit BNodeBackend(view_type const &view) noexcept : hash{view.hash()}, 19 | identifier{view.identifier} { 20 | } 21 | 22 | explicit operator view_type() const noexcept { 23 | return view_type{.identifier = identifier}; 24 | } 25 | 26 | static identifier::NodeBackendID from_storage_id(id_type const id, [[maybe_unused]] view_type const view) noexcept { 27 | return identifier::NodeBackendID{id, identifier::RDFNodeType::BNode}; 28 | } 29 | 30 | static id_type to_storage_id(identifier::NodeBackendID const id) noexcept { 31 | return id.node_id(); 32 | } 33 | }; 34 | 35 | } // namespace rdf4cpp::storage::reference_node_storage 36 | 37 | #endif //RDF4CPP_BNODEBACKEND_HPP 38 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/reference_node_storage/FallbackLiteralBackend.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_FALLBACKLITERALBACKEND_HPP 2 | #define RDF4CPP_FALLBACKLITERALBACKEND_HPP 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace rdf4cpp::storage::reference_node_storage { 10 | 11 | struct FallbackLiteralBackend { 12 | using view_type = view::LexicalFormLiteralBackendView; 13 | using id_type = identifier::LiteralID; 14 | 15 | size_t hash; 16 | identifier::NodeBackendID datatype_id; 17 | dice::template_library::static_string lexical_form; 18 | dice::template_library::static_string language_tag; 19 | bool needs_escape; 20 | 21 | explicit FallbackLiteralBackend(view_type const &view) noexcept : hash{view.hash()}, 22 | datatype_id{view.datatype_id}, 23 | lexical_form{view.lexical_form}, 24 | language_tag{view.language_tag}, 25 | needs_escape{view.needs_escape} { 26 | } 27 | 28 | explicit operator view_type() const noexcept { 29 | return view_type{.datatype_id = datatype_id, 30 | .lexical_form = lexical_form, 31 | .language_tag = language_tag, 32 | .needs_escape = needs_escape}; 33 | } 34 | 35 | static identifier::NodeBackendID from_storage_id(id_type const id, view_type const view) noexcept { 36 | return identifier::NodeBackendID{identifier::NodeID{id, iri_node_id_to_literal_type(view.datatype_id)}, identifier::RDFNodeType::Literal}; 37 | } 38 | 39 | static id_type to_storage_id(identifier::NodeBackendID const id) noexcept { 40 | return id.node_id().literal_id(); 41 | } 42 | 43 | static view_type get_default_view() noexcept { 44 | auto const default_iri_fixed_id = datatypes::registry::reserved_datatype_ids[datatypes::registry::default_graph_iri]; 45 | auto const default_iri_node_id = identifier::literal_type_to_iri_node_id(default_iri_fixed_id); 46 | 47 | return view_type{.datatype_id = default_iri_node_id, .lexical_form = "", .language_tag = "", .needs_escape = false}; 48 | } 49 | }; 50 | 51 | } // namespace rdf4cpp::storage::view 52 | 53 | #endif //RDF4CPP_FALLBACKLITERALBACKEND_HPP 54 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/reference_node_storage/IRIBackend.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_IRIBACKEND_HPP 2 | #define RDF4CPP_IRIBACKEND_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace rdf4cpp::storage::reference_node_storage { 9 | 10 | struct IRIBackend { 11 | using view_type = view::IRIBackendView; 12 | using id_type = identifier::NodeID; 13 | 14 | size_t hash; 15 | dice::template_library::static_string identifier; 16 | 17 | explicit IRIBackend(view_type const &view) noexcept : hash{view.hash()}, 18 | identifier{view.identifier} { 19 | } 20 | 21 | explicit operator view_type() const noexcept { 22 | return view_type{.identifier = identifier}; 23 | } 24 | 25 | static identifier::NodeBackendID from_storage_id(id_type const id, [[maybe_unused]] view_type const view) noexcept { 26 | return identifier::NodeBackendID{id, identifier::RDFNodeType::IRI}; 27 | } 28 | 29 | static id_type to_storage_id(identifier::NodeBackendID const id) noexcept { 30 | return id.node_id(); 31 | } 32 | }; 33 | 34 | } // namespace rdf4cpp::storage::reference_node_storage 35 | 36 | #endif //RDF4CPP_IRIBACKEND_HPP 37 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/reference_node_storage/VariableBackend.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_VARIABLEBACKEND_HPP 2 | #define RDF4CPP_VARIABLEBACKEND_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace rdf4cpp::storage::reference_node_storage { 9 | 10 | struct VariableBackend { 11 | using view_type = view::VariableBackendView; 12 | using id_type = identifier::NodeID; 13 | 14 | size_t hash; 15 | dice::template_library::static_string name; 16 | bool is_anonymous; 17 | 18 | explicit VariableBackend(view_type const &view) noexcept : hash{view.hash()}, 19 | name{view.name}, 20 | is_anonymous{view.is_anonymous} { 21 | } 22 | 23 | explicit operator view_type() const noexcept { 24 | return view_type{.name = name, 25 | .is_anonymous = is_anonymous}; 26 | } 27 | 28 | static identifier::NodeBackendID from_storage_id(id_type const id, [[maybe_unused]] view_type const view) noexcept { 29 | return identifier::NodeBackendID{id, identifier::RDFNodeType::Variable}; 30 | } 31 | 32 | static id_type to_storage_id(identifier::NodeBackendID const id) noexcept { 33 | return id.node_id(); 34 | } 35 | }; 36 | 37 | } // namespace rdf4cpp::storage::reference_node_storage 38 | 39 | #endif //RDF4CPP_VARIABLEBACKEND_HPP 40 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/reference_node_storage/detail/SyncNodeTypeStorage.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_SYNCNODETYPESTORAGE_HPP 2 | #define RDF4CPP_SYNCNODETYPESTORAGE_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::storage::reference_node_storage { 8 | 9 | /** 10 | * Storage for one of the Node Backend types. Includes a shared mutex to synchronize access and bidirectional mappings between the Backend type and identifier::NodeID. 11 | * @tparam BackendType_t one of BNodeBackend, IRIBackend, FallbackLiteralBackend, SpecializedLiteralBackend and VariableBackend. 12 | */ 13 | template 14 | struct SyncNodeTypeStorage : UnsyncNodeTypeStorage { 15 | using base_type = UnsyncNodeTypeStorage; 16 | using backend_type = typename base_type::backend_type; 17 | using backend_view_type = typename base_type::backend_view_type; 18 | 19 | std::shared_mutex mutable mutex; 20 | }; 21 | 22 | } // namespace rdf4cpp::storage::reference_node_storage 23 | 24 | #endif //RDF4CPP_SYNCNODETYPESTORAGE_HPP 25 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/view/BNodeBackendView.cpp: -------------------------------------------------------------------------------- 1 | #include "BNodeBackendView.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::storage::view { 6 | size_t BNodeBackendView::hash() const noexcept { 7 | return dice::hash::dice_hash_templates<::dice::hash::Policies::wyhash>::dice_hash(identifier); 8 | } 9 | } // namespace rdf4cpp::storage::view 10 | 11 | size_t std::hash::operator()(rdf4cpp::storage::view::BNodeBackendView const &x) const noexcept { 12 | return x.hash(); 13 | } 14 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/view/BNodeBackendView.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_BNODEBACKENDHANDLE_HPP 2 | #define RDF4CPP_BNODEBACKENDHANDLE_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::storage::view { 8 | 9 | struct BNodeBackendView { 10 | std::string_view identifier; 11 | 12 | [[nodiscard]] size_t hash() const noexcept; 13 | auto operator<=>(BNodeBackendView const &other) const noexcept = default; 14 | }; 15 | } // namespace rdf4cpp::storage::view 16 | 17 | template<> 18 | struct std::hash { 19 | size_t operator()(rdf4cpp::storage::view::BNodeBackendView const &x) const noexcept; 20 | }; 21 | 22 | #endif //RDF4CPP_BNODEBACKENDHANDLE_HPP 23 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/view/IRIBackendView.cpp: -------------------------------------------------------------------------------- 1 | #include "IRIBackendView.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::storage::view { 6 | size_t IRIBackendView::hash() const noexcept { 7 | return dice::hash::dice_hash_templates::dice_hash(identifier); 8 | } 9 | } // namespace rdf4cpp::storage::view 10 | 11 | size_t std::hash::operator()(rdf4cpp::storage::view::IRIBackendView const &x) const noexcept { 12 | return x.hash(); 13 | } -------------------------------------------------------------------------------- /src/rdf4cpp/storage/view/IRIBackendView.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_IRIBACKENDHANDLE_HPP 2 | #define RDF4CPP_IRIBACKENDHANDLE_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::storage::view { 8 | 9 | struct IRIBackendView { 10 | std::string_view identifier; 11 | 12 | auto operator<=>(IRIBackendView const &) const noexcept = default; 13 | [[nodiscard]] size_t hash() const noexcept; 14 | }; 15 | } // namespace rdf4cpp::storage::view 16 | 17 | template<> 18 | struct std::hash { 19 | size_t operator()(rdf4cpp::storage::view::IRIBackendView const &x) const noexcept; 20 | }; 21 | 22 | #endif //RDF4CPP_IRIBACKENDHANDLE_HPP 23 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/view/LiteralBackendView.cpp: -------------------------------------------------------------------------------- 1 | #include "LiteralBackendView.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::storage::view { 6 | 7 | size_t LexicalFormLiteralBackendView::hash() const noexcept { 8 | return dice::hash::dice_hash_templates::dice_hash(std::tie(datatype_id, 9 | lexical_form, 10 | language_tag)); 11 | } 12 | 13 | LiteralBackendView::LiteralBackendView(ValueLiteralBackendView const &any) : inner{any} {} 14 | LiteralBackendView::LiteralBackendView(ValueLiteralBackendView &&any) noexcept : inner{std::move(any)} {} 15 | LiteralBackendView::LiteralBackendView(LexicalFormLiteralBackendView const &lexical) noexcept : inner{lexical} {} 16 | 17 | bool LiteralBackendView::is_lexical() const noexcept { 18 | return this->inner.index() == 0; 19 | } 20 | bool LiteralBackendView::is_value() const noexcept { 21 | return this->inner.index() == 1; 22 | } 23 | LexicalFormLiteralBackendView const &LiteralBackendView::get_lexical() const { 24 | return std::get(this->inner); 25 | } 26 | ValueLiteralBackendView const &LiteralBackendView::get_value() const & { 27 | return std::get(this->inner); 28 | } 29 | ValueLiteralBackendView &&LiteralBackendView::get_value() && { 30 | return std::get(std::move(this->inner)); 31 | } 32 | 33 | } // namespace rdf4cpp::storage::view 34 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/view/README.md: -------------------------------------------------------------------------------- 1 | # Backend Views 2 | 3 | `BNodeBackendView`, `IRIBackendView`, `LiteralBackendView` and `VariableBackendView` act as messenger objects between 4 | the `Node` types `BlankNode`, `IRI`, `Literal` and `Variable` and there implementation specific storage in the backend. -------------------------------------------------------------------------------- /src/rdf4cpp/storage/view/VariableBackendView.cpp: -------------------------------------------------------------------------------- 1 | #include "VariableBackendView.hpp" 2 | 3 | #include 4 | 5 | namespace rdf4cpp::storage::view { 6 | size_t VariableBackendView::hash() const noexcept { 7 | return dice::hash::dice_hash_templates<::dice::hash::Policies::wyhash>::dice_hash(std::tie(is_anonymous, name)); 8 | } 9 | } // namespace rdf4cpp::storage::view 10 | 11 | size_t std::hash::operator()(rdf4cpp::storage::view::VariableBackendView const &x) const noexcept { 12 | return x.hash(); 13 | } 14 | -------------------------------------------------------------------------------- /src/rdf4cpp/storage/view/VariableBackendView.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_VARIABLEBACKENDHANDLE_HPP 2 | #define RDF4CPP_VARIABLEBACKENDHANDLE_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace rdf4cpp::storage::view { 8 | 9 | struct VariableBackendView { 10 | std::string_view name; 11 | bool is_anonymous; 12 | 13 | auto operator<=>(VariableBackendView const &) const noexcept = default; 14 | [[nodiscard]] size_t hash() const noexcept; 15 | }; 16 | 17 | } // namespace rdf4cpp::storage::view 18 | 19 | template<> 20 | struct std::hash { 21 | size_t operator()(rdf4cpp::storage::view::VariableBackendView const &x) const noexcept; 22 | }; 23 | 24 | #endif //RDF4CPP_VARIABLEBACKENDHANDLE_HPP 25 | -------------------------------------------------------------------------------- /src/rdf4cpp/util/CaseInsensitiveCharTraits.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_RDF_UTIL_CASEINSENSITIVECHARTRAITS_HPP 2 | #define RDF4CPP_RDF_UTIL_CASEINSENSITIVECHARTRAITS_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::util { 7 | 8 | /** 9 | * Case insensitive char traits. 10 | * Identical to std::char_traits except that CiCharTraits treats comparisons as case insensitive 11 | */ 12 | struct CiCharTraits : std::char_traits { 13 | using char_type = std::char_traits::char_type; 14 | using pos_type = std::char_traits::pos_type; 15 | using int_type = std::char_traits::int_type; 16 | using off_type = std::char_traits::off_type; 17 | using state_type = std::char_traits::state_type; 18 | using comparison_category = std::char_traits::comparison_category; 19 | 20 | static bool eq(char_type const c1, char_type const c2) noexcept { 21 | return std::tolower(c1) == std::tolower(c2); 22 | } 23 | 24 | static bool ne(char_type const c1, char_type const c2) noexcept { 25 | return std::tolower(c1) != std::tolower(c2); 26 | } 27 | 28 | static bool lt(char_type const c1, char_type const c2) noexcept { 29 | return std::tolower(c1) < std::tolower(c2); 30 | } 31 | 32 | static int compare(char_type const *s1, char_type const *s2, size_t const len) noexcept { 33 | for (size_t ix = 0; ix < len; ++ix) { 34 | auto const c1 = std::tolower(s1[ix]); 35 | auto const c2 = std::tolower(s2[ix]); 36 | 37 | if (c1 < c2) { 38 | return -1; 39 | } 40 | 41 | if (c1 > c2) { 42 | return 1; 43 | } 44 | } 45 | 46 | return 0; 47 | } 48 | 49 | static char_type const *find(char_type const *s, size_t const len, char const needle) noexcept { 50 | auto const ineedle = std::tolower(needle); 51 | 52 | for (size_t ix = 0; ix < len; ++ix) { 53 | if (std::tolower(s[ix]) == ineedle) { 54 | return &s[ix]; 55 | } 56 | } 57 | 58 | return nullptr; 59 | } 60 | }; 61 | 62 | /** 63 | * Case insensitive view to a string 64 | */ 65 | using CiStringView = std::basic_string_view; 66 | 67 | } //namespace rdf4cpp::util 68 | 69 | #endif //RDF4CPP_RDF_UTIL_CASEINSENSITIVECHARTRAITS_HPP 70 | -------------------------------------------------------------------------------- /src/rdf4cpp/writer/SerializationState.cpp: -------------------------------------------------------------------------------- 1 | #include "SerializationState.hpp" 2 | #include 3 | #include 4 | 5 | namespace rdf4cpp::writer { 6 | 7 | bool SerializationState::begin(BufWriterParts const writer) noexcept { 8 | for (auto const &p : iri_prefixes) { 9 | RDF4CPP_DETAIL_TRY_WRITE_STR("@prefix "); 10 | RDF4CPP_DETAIL_TRY_WRITE_STR(p.shorthand); 11 | RDF4CPP_DETAIL_TRY_WRITE_STR(": <"); 12 | RDF4CPP_DETAIL_TRY_WRITE_STR(p.prefix); 13 | RDF4CPP_DETAIL_TRY_WRITE_STR("> .\n"); 14 | } 15 | 16 | return true; 17 | } 18 | 19 | bool SerializationState::flush(BufWriterParts const writer) noexcept { 20 | if (!active_predicate.null() || !active_subject.null()) { 21 | RDF4CPP_DETAIL_TRY_WRITE_STR(" .\n"); 22 | } 23 | 24 | if (!active_graph.null()) { 25 | RDF4CPP_DETAIL_TRY_WRITE_STR("}\n"); 26 | } 27 | 28 | active_predicate = Node::make_null(); 29 | active_subject = Node::make_null(); 30 | active_graph = Node::make_null(); 31 | return true; 32 | } 33 | 34 | } // namespace rdf4cpp::writer 35 | -------------------------------------------------------------------------------- /src/rdf4cpp/writer/SerializationState.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RDF4CPP_SERIALIZATIONSTATE_HPP 2 | #define RDF4CPP_SERIALIZATIONSTATE_HPP 3 | 4 | #include 5 | 6 | namespace rdf4cpp::writer { 7 | 8 | struct SerializationState { 9 | Node active_graph; 10 | Node active_subject; 11 | Node active_predicate; 12 | 13 | static bool begin(BufWriterParts writer) noexcept; 14 | bool flush(BufWriterParts writer) noexcept; 15 | }; 16 | 17 | } // namespace rdf4cpp::writer 18 | 19 | #endif //RDF4CPP_SERIALIZATIONSTATE_HPP 20 | -------------------------------------------------------------------------------- /test_FetchContent/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.17) 2 | project(FetchContentTest CXX) 3 | 4 | # find out the current tag of the parent repos in the folder above 5 | execute_process(COMMAND git rev-parse HEAD 6 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../ 7 | OUTPUT_VARIABLE parent_git_tag 8 | OUTPUT_STRIP_TRAILING_WHITESPACE 9 | ) 10 | # fetch the repo from the local copy 11 | # beware: only submitted changes are checked out! 12 | include(FetchContent) 13 | FetchContent_Declare( 14 | rdf4cpp 15 | GIT_REPOSITORY "${CMAKE_CURRENT_SOURCE_DIR}/../" 16 | GIT_TAG ${parent_git_tag} 17 | GIT_SHALLOW TRUE 18 | ) 19 | FetchContent_MakeAvailable(rdf4cpp) 20 | add_executable(test_FetchContent src/test_FetchContent.cpp) 21 | # With FetchContent_Declare we don't need find_package 22 | target_link_libraries(test_FetchContent rdf4cpp::rdf4cpp) 23 | 24 | set_target_properties( 25 | test_FetchContent PROPERTIES 26 | CXX_STANDARD 20 27 | CXX_STANDARD_REQUIRED ON 28 | CXX_EXTENSIONS OFF 29 | ) -------------------------------------------------------------------------------- /test_FetchContent/src/test_FetchContent.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main() { 6 | using namespace rdf4cpp; 7 | 8 | auto const datatype_test_lit = Literal::make_typed("123.0", IRI{"http://www.w3.org/2001/XMLSchema#double"}); // segfault if registering of datatypes does not work 9 | std::cout << datatype_test_lit << std::endl; 10 | std::cout << Literal::make_simple("Using FetchContent works.") << std::endl; 11 | } -------------------------------------------------------------------------------- /test_package/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(PackageTest CXX) 3 | 4 | find_package(rdf4cpp REQUIRED) 5 | 6 | add_executable(example example.cpp) 7 | 8 | target_link_libraries(example PUBLIC 9 | rdf4cpp::rdf4cpp) 10 | 11 | set_target_properties( 12 | example PROPERTIES 13 | CXX_STANDARD 20 14 | CXX_STANDARD_REQUIRED ON 15 | CXX_EXTENSIONS OFF 16 | ) 17 | -------------------------------------------------------------------------------- /test_package/conanfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | from conan import ConanFile 3 | from conan.tools.build import can_run 4 | from conan.tools.cmake import CMake, cmake_layout 5 | 6 | required_conan_version = ">=1.43.0" 7 | 8 | 9 | class TestPackageConan(ConanFile): 10 | settings = "os", "compiler", "build_type", "arch" 11 | generators = "CMakeDeps", "CMakeToolchain" 12 | 13 | def requirements(self): 14 | self.requires(self.tested_reference_str) 15 | 16 | def layout(self): 17 | cmake_layout(self) 18 | 19 | def build(self): 20 | cmake = CMake(self) 21 | cmake.configure() 22 | cmake.build() 23 | 24 | def test(self): 25 | if can_run(self): 26 | cmd = os.path.join(self.cpp.build.bindir, "example") 27 | self.run(cmd, env="conanrun") 28 | -------------------------------------------------------------------------------- /test_package/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main() { 6 | using namespace rdf4cpp; 7 | 8 | auto const datatype_test_lit = Literal::make_typed("123.0", IRI{"http://www.w3.org/2001/XMLSchema#double"}); // segfault if registering of datatypes does not work 9 | std::cout << datatype_test_lit << std::endl; 10 | std::cout << Literal::make_simple("Using the conan package works.") << std::endl; 11 | } -------------------------------------------------------------------------------- /tests/datatype/tests_AnyURI.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("anyURI capabilities") { 9 | static_assert(datatypes::LiteralDatatype); 10 | static_assert(datatypes::LogicalLiteralDatatype); 11 | static_assert(!datatypes::NumericLiteralDatatype); 12 | static_assert(datatypes::PromotableLiteralDatatype); 13 | static_assert(!datatypes::SubtypedLiteralDatatype); 14 | static_assert(datatypes::ComparableLiteralDatatype); 15 | static_assert(datatypes::FixedIdLiteralDatatype); 16 | } 17 | 18 | TEST_CASE("Datatype AnyURI") { 19 | 20 | constexpr std::string_view correct_type_iri_cstr = "http://www.w3.org/2001/XMLSchema#anyURI"; 21 | 22 | CHECK(datatypes::xsd::AnyURI::identifier == correct_type_iri_cstr); 23 | 24 | CHECK(Literal::make_typed("https://example.com").lexical_form() == "https://example.com"); 25 | CHECK(Literal::make_typed("https://example.com").ebv() == TriBool::True); 26 | CHECK(Literal::make_typed("").ebv() == TriBool::False); 27 | CHECK(Literal::make_typed("/relative/iri?to?somewhere").lexical_form() == "/relative/iri?to?somewhere"); 28 | CHECK(Literal::make_typed("//relative/iri?to?somewhere").lexical_form() == "//relative/iri?to?somewhere"); 29 | CHECK(Literal::make_typed("https://example.com").cast() == Literal::make_typed("https://example.com")); 30 | Literal e{}; 31 | CHECK_THROWS_AS(e = Literal::make_typed("invalid uri"), rdf4cpp::InvalidNode); 32 | 33 | CHECK(e.null()); 34 | } 35 | -------------------------------------------------------------------------------- /tests/datatype/tests_Byte.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("Datatype Byte") { 9 | 10 | constexpr auto correct_type_iri_cstr = "http://www.w3.org/2001/XMLSchema#byte"; 11 | 12 | CHECK(std::string(datatypes::xsd::Byte::identifier) == correct_type_iri_cstr); 13 | 14 | auto type_iri = IRI(datatypes::xsd::Byte::identifier); 15 | CHECK(type_iri.identifier() == correct_type_iri_cstr); 16 | 17 | using type = datatypes::xsd::Byte::cpp_type; 18 | 19 | CHECK(std::is_same_v); 20 | 21 | auto value = 1; 22 | auto lit1 = Literal::make_typed_from_value(value); 23 | CHECK(lit1.value() == value); 24 | CHECK(lit1.lexical_form() == std::to_string(value)); 25 | 26 | value = -128; 27 | auto lit2 = Literal::make_typed_from_value(value); 28 | CHECK(lit2.value() == value); 29 | CHECK(lit2.lexical_form() == std::to_string(value)); 30 | 31 | value = 127; 32 | auto lit3 = Literal::make_typed_from_value(value); 33 | CHECK(lit3.value() == value); 34 | CHECK(lit3.lexical_form() == std::to_string(value)); 35 | 36 | value = 1; 37 | auto lit4 = Literal::make_typed(std::to_string(value), type_iri); 38 | CHECK(lit4.value() == value); 39 | CHECK(lit4.lexical_form() == std::to_string(value)); 40 | 41 | value = 127; 42 | auto lit5 = Literal::make_typed(std::to_string(value), type_iri); 43 | CHECK(lit5.value() == value); 44 | CHECK(lit5.lexical_form() == std::to_string(value)); 45 | 46 | CHECK(lit1 != lit2); 47 | CHECK(lit2 != lit3); 48 | CHECK(lit1 == lit4); 49 | CHECK(lit3 == lit5); 50 | 51 | // suppress warnings regarding attribute ‘nodiscard’ 52 | Literal no_discard_dummy; 53 | 54 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("139", type_iri)); 55 | 56 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("-130", type_iri)); 57 | 58 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("0.00001", type_iri)); 59 | 60 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("qwerty", type_iri)); 61 | 62 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("a23dg.59566", type_iri)); 63 | } 64 | -------------------------------------------------------------------------------- /tests/datatype/tests_NegativeInteger.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("Datatype NegativeInteger") { 9 | 10 | constexpr auto correct_type_iri_cstr = "http://www.w3.org/2001/XMLSchema#negativeInteger"; 11 | 12 | CHECK(std::string(datatypes::xsd::NegativeInteger::identifier) == correct_type_iri_cstr); 13 | 14 | auto type_iri = IRI(datatypes::xsd::NegativeInteger::identifier); 15 | CHECK(type_iri.identifier() == correct_type_iri_cstr); 16 | 17 | int64_t value = -1; 18 | auto lit1 = Literal::make_typed_from_value(value); 19 | CHECK(lit1.value() == value); 20 | CHECK(lit1.lexical_form() == std::to_string(value)); 21 | 22 | value = -18446744073709; 23 | auto lit2 = Literal::make_typed_from_value(value); 24 | CHECK(lit2.value() == value); 25 | CHECK(lit2.lexical_form() == std::to_string(value)); 26 | 27 | value = -2147483647; 28 | auto lit3 = Literal::make_typed_from_value(value); 29 | CHECK(lit3.value() == value); 30 | CHECK(lit3.lexical_form() == std::to_string(value)); 31 | 32 | value = -1; 33 | auto lit4 = Literal::make_typed(std::to_string(value), type_iri); 34 | CHECK(lit4.value() == value); 35 | 36 | value = -18446744073709; 37 | auto lit5 = Literal::make_typed(std::to_string(value), type_iri); 38 | CHECK(lit5.value() == value); 39 | 40 | CHECK(lit1 != lit2); 41 | CHECK(lit2 != lit3); 42 | CHECK(lit1 == lit4); 43 | CHECK(lit2 == lit5); 44 | 45 | // suppress warnings regarding attribute ‘nodiscard’ 46 | Literal no_discard_dummy; 47 | 48 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("a23dg", type_iri)); 49 | 50 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("0", type_iri)); 51 | 52 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("100", type_iri)); 53 | 54 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("a23dg.59566", type_iri)); 55 | } 56 | 57 | TEST_CASE("xsd:negativeInteger inlining") { 58 | using datatypes::xsd::NegativeInteger; 59 | 60 | auto one_lit = Literal::make_typed_from_value(-1); 61 | CHECK(one_lit.backend_handle().is_inlined()); 62 | CHECK(one_lit.value() == -1); 63 | 64 | auto large_lit = Literal::make_typed_from_value(-(1l << 42)); 65 | CHECK(large_lit.backend_handle().is_inlined()); 66 | CHECK(large_lit.value() == (-(1l << 42))); 67 | } 68 | -------------------------------------------------------------------------------- /tests/datatype/tests_PositiveInteger.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("Datatype PositiveInteger") { 9 | 10 | constexpr auto correct_type_iri_cstr = "http://www.w3.org/2001/XMLSchema#positiveInteger"; 11 | 12 | CHECK(std::string(datatypes::xsd::PositiveInteger::identifier) == correct_type_iri_cstr); 13 | 14 | auto type_iri = IRI(datatypes::xsd::PositiveInteger::identifier); 15 | CHECK(type_iri.identifier() == correct_type_iri_cstr); 16 | 17 | uint64_t value = 1; 18 | auto lit1 = Literal::make_typed_from_value(value); 19 | CHECK(lit1.value() == value); 20 | CHECK(lit1.lexical_form() == std::to_string(value)); 21 | 22 | value = 18446744073709; 23 | auto lit2 = Literal::make_typed_from_value(value); 24 | CHECK(lit2.value() == value); 25 | CHECK(lit2.lexical_form() == std::to_string(value)); 26 | 27 | value = 2147483647; 28 | auto lit3 = Literal::make_typed_from_value(value); 29 | CHECK(lit3.value() == value); 30 | CHECK(lit3.lexical_form() == std::to_string(value)); 31 | 32 | value = 1; 33 | auto lit4 = Literal::make_typed(std::to_string(value), type_iri); 34 | CHECK(lit4.value() == value); 35 | 36 | value = 18446744073709; 37 | auto lit5 = Literal::make_typed(std::to_string(value), type_iri); 38 | CHECK(lit5.value() == value); 39 | 40 | CHECK(lit1 != lit2); 41 | CHECK(lit2 != lit3); 42 | CHECK(lit1 == lit4); 43 | CHECK(lit2 == lit5); 44 | 45 | // suppress warnings regarding attribute ‘nodiscard’ 46 | Literal no_discard_dummy; 47 | 48 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("-1", type_iri)); 49 | 50 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("0", type_iri)); 51 | 52 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("a23dg.59566", type_iri)); 53 | 54 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("-0.01", type_iri)); 55 | } 56 | 57 | TEST_CASE("xsd:positiveInteger inlining") { 58 | using datatypes::xsd::PositiveInteger; 59 | 60 | auto one_lit = Literal::make_typed_from_value(1); 61 | CHECK(one_lit.backend_handle().is_inlined()); 62 | CHECK(one_lit.value() == 1); 63 | 64 | auto large_lit = Literal::make_typed_from_value(1l << 42); 65 | CHECK(large_lit.backend_handle().is_inlined()); 66 | CHECK(large_lit.value() == (1l << 42)); 67 | } 68 | -------------------------------------------------------------------------------- /tests/datatype/tests_UnsignedByte.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("Datatype UnsignedByte") { 9 | 10 | constexpr auto correct_type_iri_cstr = "http://www.w3.org/2001/XMLSchema#unsignedByte"; 11 | 12 | CHECK(std::string(datatypes::xsd::UnsignedByte::identifier) == correct_type_iri_cstr); 13 | 14 | auto type_iri = IRI(datatypes::xsd::UnsignedByte::identifier); 15 | CHECK(type_iri.identifier() == correct_type_iri_cstr); 16 | 17 | using type = datatypes::xsd::UnsignedByte::cpp_type; 18 | 19 | CHECK(std::is_same_v); 20 | 21 | uint8_t value = 1; 22 | auto lit1 = Literal::make_typed_from_value(value); 23 | CHECK(lit1.value() == value); 24 | CHECK(lit1.lexical_form() == std::to_string(value)); 25 | 26 | value = 0; 27 | auto lit2 = Literal::make_typed_from_value(value); 28 | CHECK(lit2.value() == value); 29 | CHECK(lit2.lexical_form() == std::to_string(value)); 30 | 31 | value = 255; 32 | auto lit3 = Literal::make_typed_from_value(value); 33 | CHECK(lit3.value() == value); 34 | CHECK(lit3.lexical_form() == std::to_string(value)); 35 | 36 | value = 1; 37 | auto lit4 = Literal::make_typed_from_value(value); 38 | CHECK(lit4.value() == value); 39 | CHECK(lit4.lexical_form() == std::to_string(value)); 40 | 41 | CHECK(lit1 != lit2); 42 | CHECK(lit2 != lit3); 43 | CHECK(lit1 == lit4); 44 | 45 | // suppress warnings regarding attribute ‘nodiscard’ 46 | Literal no_discard_dummy; 47 | 48 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("256", type_iri)); 49 | 50 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("-1", type_iri)); 51 | 52 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("a23dg.59566", type_iri)); 53 | 54 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("-0.00001", type_iri)); 55 | 56 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("qwerty", type_iri)); 57 | } 58 | -------------------------------------------------------------------------------- /tests/datatype/tests_UnsignedInt.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("Datatype UnsignedInt") { 9 | 10 | constexpr auto correct_type_iri_cstr = "http://www.w3.org/2001/XMLSchema#unsignedInt"; 11 | 12 | CHECK(std::string(datatypes::xsd::UnsignedInt::identifier) == correct_type_iri_cstr); 13 | 14 | auto type_iri = IRI(datatypes::xsd::UnsignedInt::identifier); 15 | CHECK(type_iri.identifier() == correct_type_iri_cstr); 16 | 17 | using type = datatypes::xsd::UnsignedInt::cpp_type; 18 | 19 | CHECK(std::is_same_v); 20 | 21 | uint32_t value = 1; 22 | auto lit1 = Literal::make_typed_from_value(value); 23 | CHECK(lit1.value() == value); 24 | CHECK(lit1.lexical_form() == std::to_string(value)); 25 | 26 | value = 0; 27 | auto lit2 = Literal::make_typed_from_value(value); 28 | CHECK(lit2.value() == value); 29 | CHECK(lit2.lexical_form() == std::to_string(value)); 30 | 31 | value = std::numeric_limits::max(); 32 | auto lit3 = Literal::make_typed_from_value(value); 33 | CHECK(lit3.value() == value); 34 | CHECK(lit3.lexical_form() == std::to_string(value)); 35 | 36 | value = 1; 37 | auto lit4 = Literal::make_typed(std::to_string(value), type_iri); 38 | CHECK(lit4.value() == value); 39 | 40 | value = 0; 41 | auto lit5 = Literal::make_typed(std::to_string(value), type_iri); 42 | CHECK(lit5.value() == value); 43 | 44 | value = std::numeric_limits::min(); 45 | auto lit6 = Literal::make_typed_from_value(value); 46 | CHECK(lit6.value() == value); 47 | CHECK(lit6.lexical_form() == std::to_string(value)); 48 | 49 | CHECK(lit1 != lit2); 50 | CHECK(lit2 != lit3); 51 | CHECK(lit1 == lit4); 52 | CHECK(lit2 == lit5); 53 | CHECK(lit2 == lit6); 54 | CHECK(lit5 == lit6); 55 | 56 | // suppress warnings regarding attribute ‘nodiscard’ 57 | Literal no_discard_dummy; 58 | 59 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("4294967296", type_iri)); 60 | 61 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("-1", type_iri)); 62 | 63 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("a23dg.59566", type_iri)); 64 | 65 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("-0.01", type_iri)); 66 | } 67 | -------------------------------------------------------------------------------- /tests/datatype/tests_UnsignedLong.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("Datatype UnsignedLong") { 9 | 10 | constexpr auto correct_type_iri_cstr = "http://www.w3.org/2001/XMLSchema#unsignedLong"; 11 | 12 | CHECK(std::string(datatypes::xsd::UnsignedLong::identifier) == correct_type_iri_cstr); 13 | 14 | auto type_iri = IRI(datatypes::xsd::UnsignedLong::identifier); 15 | CHECK(type_iri.identifier() == correct_type_iri_cstr); 16 | 17 | using type = datatypes::xsd::UnsignedLong::cpp_type; 18 | 19 | CHECK(std::is_same_v); 20 | 21 | uint64_t value = 1; 22 | auto lit1 = Literal::make_typed_from_value(value); 23 | CHECK(lit1.value() == value); 24 | CHECK(lit1.lexical_form() == std::to_string(value)); 25 | 26 | value = 0; 27 | auto lit2 = Literal::make_typed_from_value(value); 28 | CHECK(lit2.value() == value); 29 | CHECK(lit2.lexical_form() == std::to_string(value)); 30 | 31 | value = std::numeric_limits::max(); 32 | auto lit3 = Literal::make_typed_from_value(value); 33 | CHECK(lit3.value() == value); 34 | CHECK(lit3.lexical_form() == std::to_string(value)); 35 | 36 | value = 1; 37 | auto lit4 = Literal::make_typed(std::to_string(value), type_iri); 38 | CHECK(lit4.value() == value); 39 | 40 | value = 0; 41 | auto lit5 = Literal::make_typed(std::to_string(value), type_iri); 42 | CHECK(lit5.value() == value); 43 | 44 | value = std::numeric_limits::min(); 45 | auto lit6 = Literal::make_typed_from_value(value); 46 | CHECK(lit6.value() == value); 47 | CHECK(lit6.lexical_form() == std::to_string(value)); 48 | 49 | CHECK(lit1 != lit2); 50 | CHECK(lit2 != lit3); 51 | CHECK(lit1 == lit4); 52 | CHECK(lit2 == lit5); 53 | CHECK(lit2 == lit6); 54 | CHECK(lit5 == lit6); 55 | 56 | // suppress warnings regarding attribute ‘nodiscard’ 57 | Literal no_discard_dummy; 58 | 59 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("a23dg.59566", type_iri)); 60 | 61 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("qwerty", type_iri)); 62 | 63 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("53.59566", type_iri)); 64 | 65 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("0.01", type_iri)); 66 | } 67 | -------------------------------------------------------------------------------- /tests/datatype/tests_UnsignedShort.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("Datatype UnsignedShort") { 9 | 10 | constexpr auto correct_type_iri_cstr = "http://www.w3.org/2001/XMLSchema#unsignedShort"; 11 | 12 | CHECK(std::string(datatypes::xsd::UnsignedShort::identifier) == correct_type_iri_cstr); 13 | 14 | auto type_iri = IRI(datatypes::xsd::UnsignedShort::identifier); 15 | CHECK(type_iri.identifier() == correct_type_iri_cstr); 16 | 17 | using type = datatypes::xsd::UnsignedShort::cpp_type; 18 | 19 | CHECK(std::is_same_v); 20 | 21 | uint16_t value = 1; 22 | auto lit1 = Literal::make_typed_from_value(value); 23 | CHECK(lit1.value() == value); 24 | CHECK(lit1.lexical_form() == std::to_string(value)); 25 | 26 | value = 0; 27 | auto lit2 = Literal::make_typed_from_value(value); 28 | CHECK(lit2.value() == value); 29 | CHECK(lit2.lexical_form() == std::to_string(value)); 30 | 31 | value = std::numeric_limits::max(); 32 | auto lit3 = Literal::make_typed_from_value(value); 33 | CHECK(lit3.value() == value); 34 | CHECK(lit3.lexical_form() == std::to_string(value)); 35 | 36 | value = 1; 37 | auto lit4 = Literal::make_typed(std::to_string(value), type_iri); 38 | CHECK(lit4.value() == value); 39 | 40 | value = 0; 41 | auto lit5 = Literal::make_typed(std::to_string(value), type_iri); 42 | CHECK(lit5.value() == value); 43 | 44 | value = std::numeric_limits::min(); 45 | auto lit6 = Literal::make_typed_from_value(value); 46 | CHECK(lit6.value() == value); 47 | CHECK(lit6.lexical_form() == std::to_string(value)); 48 | 49 | CHECK(lit1 != lit2); 50 | CHECK(lit2 != lit3); 51 | CHECK(lit1 == lit4); 52 | CHECK(lit2 == lit6); 53 | CHECK(lit5 == lit6); 54 | 55 | // suppress warnings regarding attribute ‘nodiscard’ 56 | Literal no_discard_dummy; 57 | 58 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("-1", type_iri)); 59 | 60 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("65536", type_iri)); 61 | 62 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("a23dg.59566", type_iri)); 63 | 64 | CHECK_THROWS(no_discard_dummy = Literal::make_typed("-0.01", type_iri)); 65 | } 66 | -------------------------------------------------------------------------------- /tests/graph/tests_dataset.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include 3 | 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("base functions") { 9 | Dataset set{}; 10 | CHECK((set.begin() == set.end())); 11 | set.add(Quad{IRI{"https://www.example.com/sub"}, IRI{"https://www.example.com/pred"}, IRI{"https://www.example.com/obj"}}); 12 | set.add(Quad{IRI{"https://www.example.com/graph"}, IRI{"https://www.example.com/sub"}, IRI{"https://www.example.com/pred"}, Literal::make_simple("some string")}); 13 | SUBCASE("simple functions") { 14 | CHECK((set.begin() != set.end())); 15 | for (const auto &q : set) { 16 | CHECK(q.subject() == IRI{"https://www.example.com/sub"}); 17 | CHECK(q.predicate() == IRI{"https://www.example.com/pred"}); 18 | if (q.object().is_iri()) 19 | CHECK(q.object() == IRI{"https://www.example.com/obj"}); 20 | else if (q.object().is_literal()) 21 | CHECK(q.object() == Literal::make_simple("some string")); 22 | else 23 | CHECK(false); 24 | CHECK((q.graph() == IRI{"https://www.example.com/graph"} || q.graph() == IRI::default_graph())); 25 | } 26 | CHECK(set.size() == 2); 27 | CHECK(set.size(IRI{"https://www.example.com/graph"}) == 1); 28 | CHECK(set.contains(Quad{IRI{"https://www.example.com/sub"}, IRI{"https://www.example.com/pred"}, IRI{"https://www.example.com/obj"}})); 29 | CHECK(!set.contains(Quad{IRI{"https://www.example.com/sub"}, IRI{"https://www.example.com/pred2"}, IRI{"https://www.example.com/obj"}})); 30 | } 31 | 32 | SUBCASE("empty pattern") { 33 | query::QuadPattern pattern{query::Variable("g"), query::Variable("x"), IRI{"https://www.example.com/pred2"}, query::Variable{"z"}}; 34 | auto sol = set.match(pattern); 35 | CHECK((sol.begin() == sol.end())); 36 | } 37 | 38 | SUBCASE("pattern") { 39 | query::QuadPattern pattern{query::Variable("g"), query::Variable("x"), IRI{"https://www.example.com/pred"}, query::Variable{"z"}}; 40 | auto sol = set.match(pattern); 41 | int i = 0; 42 | for (const auto& s : sol) { 43 | CHECK(s.bound_count() == 3); 44 | ++i; 45 | } 46 | CHECK(i == 2); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/graph/tests_loading.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include 3 | 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("load Graph") { 9 | Graph set{}; 10 | std::fstream file{"test_swdf/swdf.nt"}; 11 | set.load_rdf_data(file, parser::ParsingFlags::none(), nullptr, [](parser::ParsingError e) { 12 | FAIL(std::format("{}", e)); 13 | }); 14 | CHECK(set.size() == 304592); 15 | } 16 | 17 | TEST_CASE("load dataset") { 18 | Dataset set{}; 19 | std::fstream file{"tests_loading_simple.trig"}; 20 | set.load_rdf_data(file, parser::ParsingFlags::none(), nullptr, [](parser::ParsingError e) { 21 | FAIL(std::format("{}", e)); 22 | }); 23 | CHECK(set.size() == 4); 24 | int i = 0; 25 | for ([[maybe_unused]] const auto& _ : set) { 26 | ++i; 27 | } 28 | CHECK(i == 4); 29 | CHECK(set.graph(IRI::make("http://data.semanticweb.org/workshop/admire/2012")).size() == 4); 30 | } 31 | -------------------------------------------------------------------------------- /tests/graph/tests_loading_simple.trig: -------------------------------------------------------------------------------- 1 | { 2 | "search" . 3 | . 4 | "web applications" . 5 | "1937-1-1"^^ . 6 | } -------------------------------------------------------------------------------- /tests/namespaces/tests_Namespace.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace rdf4cpp; 8 | 9 | TEST_CASE("Namespace sanity check") { 10 | using namespace rdf4cpp; 11 | 12 | SUBCASE("closed NS") { 13 | storage::reference_node_storage::SyncReferenceNodeStorage ns; 14 | namespaces::RDF rdf{ns}; 15 | 16 | auto rdf_property = rdf + "Property"; 17 | CHECK_EQ(rdf_property.identifier(), std::string{namespaces::RDF::prefix} + "Property"); 18 | 19 | CHECK_THROWS(rdf + "AAAAAAAAAAAA"); 20 | } 21 | 22 | SUBCASE("open NS") { 23 | storage::reference_node_storage::SyncReferenceNodeStorage ns; 24 | namespaces::XSD xsd{ns}; 25 | 26 | CHECK_EQ((xsd + "AAAAAAAAA").identifier(), std::string{xsd.prefix} + "AAAAAAAAA"); // create 27 | CHECK_EQ((xsd + "AAAAAAAAA").identifier(), std::string{xsd.prefix} + "AAAAAAAAA"); // fetch 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/nodes/tests_DBpediaMode.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | #include 3 | 4 | #include 5 | 6 | using namespace rdf4cpp; 7 | 8 | TEST_CASE("IRI") { 9 | IRIFactory f{}; 10 | static constexpr std::string_view iri = "http//:example:foo/bar"; 11 | 12 | datatypes::registry::relaxed_parsing_mode = false; 13 | CHECK(!f.create_and_validate(iri).has_value()); 14 | 15 | datatypes::registry::relaxed_parsing_mode = true; 16 | CHECK(f.create_and_validate(iri).has_value()); 17 | CHECK(f.create_and_validate(iri).value().identifier() == iri); 18 | } 19 | 20 | TEST_CASE("date/time") { 21 | Literal u{}; 22 | datatypes::registry::relaxed_parsing_mode = false; 23 | CHECK_THROWS_AS(u = Literal::make_typed("1742-0-0"), std::runtime_error); 24 | CHECK_THROWS_AS(u = Literal::make_typed("1742-2-40"), std::runtime_error); 25 | CHECK_THROWS_AS(u = Literal::make_typed("10:90:00"), std::runtime_error); 26 | CHECK_THROWS_AS(u = Literal::make_typed("26:90:60"), std::runtime_error); 27 | CHECK_THROWS_AS(u = Literal::make_typed("1742-2-40T26:90:60"), std::runtime_error); 28 | CHECK_THROWS_AS(u = Literal::make_typed("1742-2-40T26:90:60Z"), std::runtime_error); 29 | 30 | datatypes::registry::relaxed_parsing_mode = true; 31 | CHECK(Literal::make_typed("1742-0-0") == Literal::make_typed("1741-11-30")); 32 | CHECK(Literal::make_typed("1742-2-40") == Literal::make_typed("1742-3-12")); 33 | CHECK(Literal::make_typed("10:90:00") == Literal::make_typed("11:30:00")); 34 | CHECK_THROWS_AS(u = Literal::make_typed("26:90:60"), std::runtime_error); 35 | CHECK(Literal::make_typed("1742-2-40T26:90:60") == Literal::make_typed("1742-3-13T3:31:0")); 36 | CHECK(Literal::make_typed("1742-2-40T26:90:60Z") == Literal::make_typed("1742-3-13T3:31:0Z")); 37 | CHECK(Literal::make_typed("1742-2-40T10:10:10Z") == Literal::make_typed("1742-3-12T10:10:10Z")); 38 | CHECK(u.null()); 39 | } 40 | -------------------------------------------------------------------------------- /tests/parser/tests_RDFFileParser.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | TEST_SUITE("RDFFileParser") { 8 | TEST_CASE("not existing file") { 9 | rdf4cpp::parser::RDFFileParser parse{"shouldnotexist.ttl"}; 10 | try { 11 | for (const auto &v : parse) { // more like check that this compiles ;) 12 | FAIL("Unreachable"); 13 | CHECK(v.has_value() == false); 14 | } 15 | FAIL("Unreachable"); 16 | } catch (std::system_error const &e) { 17 | // expecting exception 18 | } 19 | } 20 | TEST_CASE("existing file") { 21 | int count = 0; 22 | for (const auto &v : rdf4cpp::parser::RDFFileParser{"./tests_RDFFileParser_simple.ttl"}) { 23 | if (v.has_value()) { 24 | switch (count) { 25 | case 0: 26 | CHECK(v.value().subject() == rdf4cpp::IRI{"http://data.semanticweb.org/workshop/admire/2012/paper/12"}); 27 | CHECK(v.value().predicate() == rdf4cpp::IRI{"http://purl.org/dc/elements/1.1/subject"}); 28 | CHECK(v.value().object() == rdf4cpp::Literal::make_simple("search")); 29 | break; 30 | case 1: 31 | CHECK(v.value().subject() == rdf4cpp::IRI{"http://data.semanticweb.org/workshop/admire/2012/paper/12"}); 32 | CHECK(v.value().predicate() == rdf4cpp::IRI{"http://purl.org/ontology/bibo/authorList"}); 33 | CHECK(v.value().object() == rdf4cpp::IRI{"http://data.semanticweb.org/workshop/admire/2012/paper/12/authorlist"}); 34 | break; 35 | case 2: 36 | CHECK(v.value().subject() == rdf4cpp::IRI{"http://data.semanticweb.org/workshop/admire/2012/paper/12"}); 37 | CHECK(v.value().predicate() == rdf4cpp::IRI{"http://purl.org/dc/elements/1.1/subject"}); 38 | CHECK(v.value().object() == rdf4cpp::Literal::make_simple("web applications")); 39 | break; 40 | } 41 | ++count; 42 | } else if (count == 3) { 43 | ++count; 44 | } else { 45 | CHECK_MESSAGE(false, v.error()); 46 | } 47 | } 48 | CHECK(count == 4); 49 | } 50 | TEST_CASE("move iterator") { 51 | rdf4cpp::parser::RDFFileParser pars{"./tests_RDFFileParser_simple.ttl"}; 52 | auto it = pars.begin(); 53 | ++it; 54 | CHECK(it != pars.end()); 55 | } 56 | // only testing basic iterator functionality here, see tests for IStreamQuadIterator for more parsing tests 57 | } 58 | -------------------------------------------------------------------------------- /tests/parser/tests_RDFFileParser_simple.ttl: -------------------------------------------------------------------------------- 1 | "search" . 2 | . 3 | "web applications" . 4 | "1937-0-0"^^ . -------------------------------------------------------------------------------- /tests/util/tests_CowString.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using rdf4cpp::CowString; 7 | 8 | TEST_SUITE("CowString") { 9 | TEST_CASE("borrowed") { 10 | CowString s{CowString::borrowed, "Hello World"}; 11 | CHECK(s == "Hello World"); 12 | CHECK(s.view() == "Hello World"); 13 | 14 | std::string _ignore; 15 | CHECK_THROWS(_ignore = s.get_owned()); 16 | 17 | CHECK(s.get_borrowed() == "Hello World"); 18 | } 19 | 20 | TEST_CASE("owned") { 21 | CowString bull{CowString::owned, "Moo!"}; 22 | CHECK(bull == "Moo!"); 23 | CHECK(bull.view() == "Moo!"); 24 | 25 | std::string_view _ignore; 26 | CHECK_THROWS(_ignore = bull.get_borrowed()); 27 | 28 | CHECK(bull.get_owned() == "Moo!"); 29 | CHECK(std::move(bull).get_owned() == "Moo!"); 30 | } 31 | 32 | TEST_CASE("CowString equality") { 33 | CowString calf1{CowString::borrowed, "Moo?"}; 34 | CowString calf2{CowString::owned, "Moo?"}; 35 | 36 | CHECK(calf1 == calf2); 37 | } 38 | 39 | TEST_CASE("to_mutable") { 40 | CowString buffalo{CowString::borrowed, "spherical cow"}; 41 | 42 | std::string _ignore; 43 | CHECK_THROWS(_ignore = buffalo.get_owned()); 44 | 45 | buffalo.to_mutable() += "!"; 46 | CHECK_NOTHROW(_ignore = buffalo.get_owned()); 47 | CHECK(buffalo == "spherical cow!"); 48 | 49 | buffalo.to_mutable() += "!"; 50 | CHECK(buffalo == "spherical cow!!"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/util/tests_Regex.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | 3 | #include 4 | #include 5 | 6 | using namespace rdf4cpp::regex; 7 | 8 | TEST_SUITE("regex") { 9 | TEST_CASE("replacement translation") { 10 | Regex const r{"[0-9]"}; 11 | RegexReplacer repl_dummy; 12 | 13 | SUBCASE("no escape") { 14 | CHECK_THROWS(repl_dummy = r.make_replacer("$")); 15 | 16 | { 17 | std::string s = "Hello 99 World"; 18 | r.make_replacer(R"($0_)").regex_replace(s); 19 | CHECK(s == "Hello 9_9_ World"); 20 | } 21 | } 22 | 23 | SUBCASE("1 escape") { 24 | { 25 | std::string s = "Hello 99 World"; 26 | r.make_replacer(R"(\$)").regex_replace(s); 27 | CHECK(s == "Hello $$ World"); 28 | } 29 | 30 | { 31 | std::string s = "Hello 99 World"; 32 | r.make_replacer(R"(\$0)").regex_replace(s); 33 | CHECK(s == "Hello $0$0 World"); 34 | } 35 | } 36 | 37 | SUBCASE("2 escape") { 38 | CHECK_THROWS(repl_dummy = r.make_replacer(R"(\\$)")); 39 | 40 | { 41 | std::string s = "Hello 99 World"; 42 | r.make_replacer(R"(\\$0)").regex_replace(s); 43 | CHECK(s == R"(Hello \9\9 World)"); 44 | } 45 | } 46 | 47 | SUBCASE("3 escape") { 48 | { 49 | std::string s = "Hello 99 World"; 50 | r.make_replacer(R"(\\\$)").regex_replace(s); 51 | CHECK(s == R"(Hello \$\$ World)"); 52 | } 53 | 54 | { 55 | std::string s = "Hello 99 World"; 56 | r.make_replacer(R"(\\\$0)").regex_replace(s); 57 | CHECK(s == R"(Hello \$0\$0 World)"); 58 | } 59 | } 60 | 61 | SUBCASE("4 escape") { 62 | CHECK_THROWS(repl_dummy = r.make_replacer(R"(\\\\$)")); 63 | 64 | { 65 | std::string s = "Hello 99 World"; 66 | r.make_replacer(R"(\\\\$0)").regex_replace(s); 67 | CHECK(s == R"(Hello \\9\\9 World)"); 68 | } 69 | } 70 | 71 | SUBCASE("stray backslash") { 72 | // TODO 73 | // CHECK_THROWS(r.make_replacer(R"(Hello \ World)")); 74 | } 75 | } 76 | } 77 | --------------------------------------------------------------------------------