diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 984fe0b..34a7d97 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,39 +1,51 @@ name: "Build" on: [push, pull_request] jobs: - build: - runs-on: ${{matrix.os}} + generate-matrix: + name: "Generate matrix from cabal" + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + runs-on: ubuntu-latest + steps: + - name: Extract the tested GHC versions + id: set-matrix + uses: kleidukos/get-tested@v0.1.6.0 + with: + cabal-file: souffle-haskell.cabal + ubuntu: true + version: 0.1.6.0 + test: + name: ${{ matrix.ghc }} on ${{ matrix.os }} + needs: generate-matrix + runs-on: ${{ matrix.os }} strategy: - matrix: - os: [ubuntu-latest] + matrix: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }} steps: - - name: Checkout - uses: actions/checkout@v3 - - # Workaround for 'No space left on device' error - - name: free disk space - run: | - sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true - sudo swapoff -a - sudo rm -f /swapfile - sudo apt clean - df -h - - # In this step, this action saves a list of existing images, the cache is created without them in the post run. - # It also restores the cache if it exists. - - uses: jpribyl/action-docker-layer-caching@v0.1.1 - continue-on-error: true # Ignore the failure of a step and avoid terminating the job. - - - name: Build and test + - name: Checkout base repo + uses: actions/checkout@v4 + - name: Set up Haskell + id: setup-haskell + uses: haskell-actions/setup@v2 + with: + ghc-version: ${{ matrix.ghc }} + cabal-version: 'latest' + - name: Install Souffle run: | - set -eo pipefail - export TIMESTAMP=$(date +%s) - docker build -f Dockerfile . -t souffle-haskell:$TIMESTAMP | tee souffle-haskell-lang-${{matrix.os}}.log - docker run --rm souffle-haskell:$TIMESTAMP bash -c "make tests" | tee -a souffle-haskell-lang-${{matrix.os}}.log - - - name: Upload logs - if: ${{ always() }} - uses: actions/upload-artifact@v2 + wget https://github.com/souffle-lang/souffle/releases/download/2.2/x86_64-ubuntu-2004-souffle-2.2-Linux.deb + sudo apt install mcpp libffi7 + sudo dpkg -i ./x86_64-ubuntu-2004-souffle-2.2-Linux.deb + - name: Cache + uses: actions/cache@v4.0.0 with: - name: souffle-haskell-lang-${{matrix.os}}.log - path: souffle-haskell-lang-${{matrix.os}}.log + path: ${{ steps.setup-haskell.outputs.cabal-store }} + key: ${{ runner.os }}-ghc-${{ matrix.ghc }}-cabal-${{ hashFiles('**/plan.json') }} + restore-keys: ${{ runner.os }}-ghc-${{ matrix.ghc }}- + - name: Configure + run: make configure + - name: Build + run: | + cabal install hspec-discover + make build + - name: Test + run: | + make tests diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..984fe0b --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,39 @@ +name: "Build" +on: [push, pull_request] +jobs: + build: + runs-on: ${{matrix.os}} + strategy: + matrix: + os: [ubuntu-latest] + steps: + - name: Checkout + uses: actions/checkout@v3 + + # Workaround for 'No space left on device' error + - name: free disk space + run: | + sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true + sudo swapoff -a + sudo rm -f /swapfile + sudo apt clean + df -h + + # In this step, this action saves a list of existing images, the cache is created without them in the post run. + # It also restores the cache if it exists. + - uses: jpribyl/action-docker-layer-caching@v0.1.1 + continue-on-error: true # Ignore the failure of a step and avoid terminating the job. + + - name: Build and test + run: | + set -eo pipefail + export TIMESTAMP=$(date +%s) + docker build -f Dockerfile . -t souffle-haskell:$TIMESTAMP | tee souffle-haskell-lang-${{matrix.os}}.log + docker run --rm souffle-haskell:$TIMESTAMP bash -c "make tests" | tee -a souffle-haskell-lang-${{matrix.os}}.log + + - name: Upload logs + if: ${{ always() }} + uses: actions/upload-artifact@v2 + with: + name: souffle-haskell-lang-${{matrix.os}}.log + path: souffle-haskell-lang-${{matrix.os}}.log diff --git a/Dockerfile b/Dockerfile index 7d63fd7..3047d11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM primordus/souffle-ubuntu:2.3 +FROM primordus/souffle-ubuntu:2.2 SHELL [ "/bin/bash", "-c" ] diff --git a/Dockerfile.builder b/Dockerfile.builder new file mode 100644 index 0000000..49b4195 --- /dev/null +++ b/Dockerfile.builder @@ -0,0 +1,25 @@ +FROM ubuntu:20.04 +ARG VERSION=2.2 + +RUN echo 'tzdata tzdata/Areas select Europe' | debconf-set-selections \ + && echo 'tzdata tzdata/Zones/Europe select Paris' | debconf-set-selections +RUN apt update \ + && apt autoremove -y \ + && DEBIAN_FRONTEND=noninteractive apt install -y lsb-release wget \ + software-properties-common gnupg curl bison build-essential cmake doxygen \ + flex g++ git libffi-dev libncurses5-dev libsqlite3-dev make mcpp sqlite3 zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* +RUN mkdir -p /tmp/souffle-src \ + && cd /tmp/souffle-src \ + && git clone https://github.com/souffle-lang/souffle.git \ + && cd souffle \ + && git checkout $VERSION \ + && cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \ + && cmake --build build -j \ + && cmake --build build --target install \ + && cd /tmp \ + && rm -rf /tmp/souffle-src + +VOLUME [/code] +WORKDIR /app +CMD ["souffle" "--help"] diff --git a/Makefile b/Makefile index 49da490..4e10210 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,35 @@ - # NOTE: these all assume cabal v3 build: configure @cabal build -configure: - @hpack --force && cabal configure --enable-tests +configure: ## Configure the project + @cabal configure --enable-tests --enable-benchmarks -clean: +clean: ## Clean up the build artifacts @cabal clean -lint: - @hlint . +lint: ## Run the code linter (HLint) + @find tests lib benchmark -name "*.hs" | xargs -P $(PROCS) -I {} hlint --refactor-options="-i" --refactor {} + +style: ## Run the code styler (and cabal-fmt) + @cabal-fmt -i *.cabal -hoogle: +hoogle: ## Start a hoogle server on port 8080 hoogle server --local -p 8080 -tests: configure +tests: configure ## Run tests DATALOG_DIR=tests/fixtures/ cabal run souffle-haskell-test -docs: +docs: ## Generate the documentation @cabal haddock -bench: +bench: ## Run the benchmarks @cabal run souffle-haskell-benchmarks -- --output /tmp/benchmarks.html -.PHONY: hoogle lint clean configure build tests docs bench +help: ## Display this help message + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.* ?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: all $(MAKECMDGOALS) + +.DEFAULT_GOAL := help diff --git a/benchmarks/fixtures/bench.cpp b/benchmarks/fixtures/bench.cpp index f28c73c..7d5d5ad 100644 --- a/benchmarks/fixtures/bench.cpp +++ b/benchmarks/fixtures/bench.cpp @@ -6,7 +6,8 @@ extern "C" { namespace souffle { static const RamDomain RAM_BIT_SHIFT_MASK = RAM_DOMAIN_SIZE - 1; -struct t_btree_u__0__2__1 { +struct t_btree_u__0__1 { +static constexpr Relation::arity_type Arity = 1; using t_tuple = Tuple; struct t_comparator_0{ int operator()(const t_tuple& a, const t_tuple& b) const { @@ -70,18 +71,6 @@ return range(ind_0.begin(),ind_0.end()); range lowerUpperRange_0(const t_tuple& /* lower */, const t_tuple& /* upper */) const { return range(ind_0.begin(),ind_0.end()); } -range lowerUpperRange_2(const t_tuple& lower, const t_tuple& upper, context& h) const { -t_comparator_0 comparator; -int cmp = comparator(lower, upper); -if (cmp > 0) { - return make_range(ind_0.end(), ind_0.end()); -} -return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper)); -} -range lowerUpperRange_2(const t_tuple& lower, const t_tuple& upper) const { -context h; -return lowerUpperRange_2(lower,upper,h); -} range lowerUpperRange_1(const t_tuple& lower, const t_tuple& upper, context& h) const { t_comparator_0 comparator; int cmp = comparator(lower, upper); @@ -120,7 +109,8 @@ o << " arity 1 direct b-tree index 0 lex-order [0]\n"; ind_0.printStats(o); } }; -struct t_btree_u__0__1 { +struct t_btree_u__0__2__1 { +static constexpr Relation::arity_type Arity = 1; using t_tuple = Tuple; struct t_comparator_0{ int operator()(const t_tuple& a, const t_tuple& b) const { @@ -184,6 +174,18 @@ return range(ind_0.begin(),ind_0.end()); range lowerUpperRange_0(const t_tuple& /* lower */, const t_tuple& /* upper */) const { return range(ind_0.begin(),ind_0.end()); } +range lowerUpperRange_2(const t_tuple& lower, const t_tuple& upper, context& h) const { +t_comparator_0 comparator; +int cmp = comparator(lower, upper); +if (cmp > 0) { + return make_range(ind_0.end(), ind_0.end()); +} +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper)); +} +range lowerUpperRange_2(const t_tuple& lower, const t_tuple& upper) const { +context h; +return lowerUpperRange_2(lower,upper,h); +} range lowerUpperRange_1(const t_tuple& lower, const t_tuple& upper, context& h) const { t_comparator_0 comparator; int cmp = comparator(lower, upper); @@ -223,6 +225,7 @@ ind_0.printStats(o); } }; struct t_btree_ui__0_1__11 { +static constexpr Relation::arity_type Arity = 2; using t_tuple = Tuple; struct t_comparator_0{ int operator()(const t_tuple& a, const t_tuple& b) const { @@ -325,6 +328,7 @@ ind_0.printStats(o); } }; struct t_btree_uif__0_1_2__111 { +static constexpr Relation::arity_type Arity = 3; using t_tuple = Tuple; struct t_comparator_0{ int operator()(const t_tuple& a, const t_tuple& b) const { @@ -427,6 +431,7 @@ ind_0.printStats(o); } }; struct t_btree_uiif__0_1_2_3__1111 { +static constexpr Relation::arity_type Arity = 4; using t_tuple = Tuple; struct t_comparator_0{ int operator()(const t_tuple& a, const t_tuple& b) const { @@ -531,15 +536,7 @@ ind_0.printStats(o); class Sf_bench : public SouffleProgram { private: -static inline bool regex_wrapper(const std::string& pattern, const std::string& text) { - bool result = false; - try { result = std::regex_match(text, std::regex(pattern)); } catch(...) { - std::cerr << "warning: wrong pattern provided for match(\"" << pattern << "\",\"" << text << "\").\n"; -} - return result; -} -private: -static inline std::string substr_wrapper(const std::string& str, size_t idx, size_t len) { +static inline std::string substr_wrapper(const std::string& str, std::size_t idx, std::size_t len) { std::string result; try { result = str.substr(idx,len); } catch(...) { std::cerr << "warning: wrong index position provided by substr(\""; @@ -551,55 +548,61 @@ static inline std::string substr_wrapper(const std::string& str, size_t idx, siz SymbolTable symTable{ R"_(abcdef)_", };// -- initialize record table -- -RecordTable recordTable; +SpecializedRecordTable<0> recordTable{}; +// -- Table: from_datalog_fact +Own rel_1_from_datalog_fact = mk(); +souffle::RelationWrapper wrapper_rel_1_from_datalog_fact; // -- Table: @delta_from_datalog_fact -Own rel_1_delta_from_datalog_fact = mk(); +Own rel_2_delta_from_datalog_fact = mk(); // -- Table: @new_from_datalog_fact -Own rel_2_new_from_datalog_fact = mk(); -// -- Table: from_datalog_fact -Own rel_3_from_datalog_fact = mk(); -souffle::RelationWrapper<0,t_btree_u__0__1,Tuple,1,0> wrapper_rel_3_from_datalog_fact; +Own rel_3_new_from_datalog_fact = mk(); // -- Table: from_datalog_string_fact Own rel_4_from_datalog_string_fact = mk(); -souffle::RelationWrapper<1,t_btree_ui__0_1__11,Tuple,2,0> wrapper_rel_4_from_datalog_string_fact; +souffle::RelationWrapper wrapper_rel_4_from_datalog_string_fact; // -- Table: numbers_fact Own rel_5_numbers_fact = mk(); -souffle::RelationWrapper<2,t_btree_uif__0_1_2__111,Tuple,3,0> wrapper_rel_5_numbers_fact; +souffle::RelationWrapper wrapper_rel_5_numbers_fact; // -- Table: strings_fact Own rel_6_strings_fact = mk(); -souffle::RelationWrapper<3,t_btree_uiif__0_1_2_3__1111,Tuple,4,0> wrapper_rel_6_strings_fact; +souffle::RelationWrapper wrapper_rel_6_strings_fact; public: -Sf_bench() : -wrapper_rel_3_from_datalog_fact(*rel_3_from_datalog_fact,symTable,"from_datalog_fact",std::array{{"u:unsigned"}},std::array{{"u"}}), - -wrapper_rel_4_from_datalog_string_fact(*rel_4_from_datalog_string_fact,symTable,"from_datalog_string_fact",std::array{{"u:unsigned","s:symbol"}},std::array{{"u","s"}}), - -wrapper_rel_5_numbers_fact(*rel_5_numbers_fact,symTable,"numbers_fact",std::array{{"u:unsigned","i:number","f:float"}},std::array{{"u","n","f"}}), - -wrapper_rel_6_strings_fact(*rel_6_strings_fact,symTable,"strings_fact",std::array{{"u:unsigned","s:symbol","i:number","f:float"}},std::array{{"u","s","n","f"}}){ -addRelation("from_datalog_fact",&wrapper_rel_3_from_datalog_fact,false,true); -addRelation("from_datalog_string_fact",&wrapper_rel_4_from_datalog_string_fact,false,true); -addRelation("numbers_fact",&wrapper_rel_5_numbers_fact,true,true); -addRelation("strings_fact",&wrapper_rel_6_strings_fact,true,true); +Sf_bench() +: wrapper_rel_1_from_datalog_fact(0, *rel_1_from_datalog_fact, *this, "from_datalog_fact", std::array{{"u:unsigned"}}, std::array{{"u"}}, 0) +, wrapper_rel_4_from_datalog_string_fact(1, *rel_4_from_datalog_string_fact, *this, "from_datalog_string_fact", std::array{{"u:unsigned","s:symbol"}}, std::array{{"u","s"}}, 0) +, wrapper_rel_5_numbers_fact(2, *rel_5_numbers_fact, *this, "numbers_fact", std::array{{"u:unsigned","i:number","f:float"}}, std::array{{"u","n","f"}}, 0) +, wrapper_rel_6_strings_fact(3, *rel_6_strings_fact, *this, "strings_fact", std::array{{"u:unsigned","s:symbol","i:number","f:float"}}, std::array{{"u","s","n","f"}}, 0) +{ +addRelation("from_datalog_fact", wrapper_rel_1_from_datalog_fact, false, true); +addRelation("from_datalog_string_fact", wrapper_rel_4_from_datalog_string_fact, false, true); +addRelation("numbers_fact", wrapper_rel_5_numbers_fact, true, true); +addRelation("strings_fact", wrapper_rel_6_strings_fact, true, true); } ~Sf_bench() { } + private: -std::string inputDirectory; -std::string outputDirectory; -bool performIO; -std::atomic ctr{}; +std::string inputDirectory; +std::string outputDirectory; +SignalHandler* signalHandler {SignalHandler::instance()}; +std::atomic ctr {}; +std::atomic iter {}; + +void runFunction(std::string inputDirectoryArg, + std::string outputDirectoryArg, + bool performIOArg, + bool pruneImdtRelsArg) { + this->inputDirectory = std::move(inputDirectoryArg); + this->outputDirectory = std::move(outputDirectoryArg); + this->performIO = performIOArg; + this->pruneImdtRels = pruneImdtRelsArg; -std::atomic iter{}; -void runFunction(std::string inputDirectoryArg = "", std::string outputDirectoryArg = "", bool performIOArg = false) { -this->inputDirectory = inputDirectoryArg; -this->outputDirectory = outputDirectoryArg; -this->performIO = performIOArg; -SignalHandler::instance()->set(); + // set default threads (in embedded mode) + // if this is not set, and omp is used, the default omp setting of number of cores is used. #if defined(_OPENMP) -if (getNumThreads() > 0) {omp_set_num_threads(getNumThreads());} + if (0 < getNumThreads()) { omp_set_num_threads(getNumThreads()); } #endif + signalHandler->set(); // -- query evaluation -- { std::vector args, ret; @@ -619,57 +622,57 @@ subroutine_3(args, ret); } // -- relation hint statistics -- -SignalHandler::instance()->reset(); +signalHandler->reset(); } public: -void run() override { runFunction("", "", false); } +void run() override { runFunction("", "", false, false); } public: -void runAll(std::string inputDirectoryArg = "", std::string outputDirectoryArg = "") override { runFunction(inputDirectoryArg, outputDirectoryArg, true); +void runAll(std::string inputDirectoryArg = "", std::string outputDirectoryArg = "", bool performIOArg=true, bool pruneImdtRelsArg=true) override { runFunction(inputDirectoryArg, outputDirectoryArg, performIOArg, pruneImdtRelsArg); } public: void printAll(std::string outputDirectoryArg = "") override { -try {std::map directiveMap({{"IO","file"},{"attributeNames","u"},{"name","from_datalog_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"auxArity\": 0, \"params\": [\"u\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"u:unsigned\"]}}"}}); +try {std::map directiveMap({{"IO","file"},{"attributeNames","u"},{"auxArity","0"},{"name","from_datalog_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"u\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"u:unsigned\"]}}"}}); if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} -IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_3_from_datalog_fact); +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_1_from_datalog_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"name","numbers_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"auxArity\": 0, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts\tn\tf"},{"auxArity","0"},{"name","strings_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 4, \"params\": [\"u\", \"s\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 4, \"types\": [\"u:unsigned\", \"s:symbol\", \"i:number\", \"f:float\"]}}"}}); if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} -IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_5_numbers_fact); +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_6_strings_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts\tn\tf"},{"name","strings_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 4, \"auxArity\": 0, \"params\": [\"u\", \"s\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 4, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"s:symbol\", \"i:number\", \"f:float\"]}}"}}); +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"auxArity","0"},{"name","numbers_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} -IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_6_strings_fact); +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_5_numbers_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts"},{"name","from_datalog_string_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 2, \"auxArity\": 0, \"params\": [\"u\", \"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 2, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"s:symbol\"]}}"}}); +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts"},{"auxArity","0"},{"name","from_datalog_string_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 2, \"params\": [\"u\", \"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 2, \"types\": [\"u:unsigned\", \"s:symbol\"]}}"}}); if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_4_from_datalog_string_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} } public: void loadAll(std::string inputDirectoryArg = "") override { -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"fact-dir","."},{"name","numbers_fact"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"auxArity\": 0, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); -if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;} -IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_5_numbers_fact); -} catch (std::exception& e) {std::cerr << "Error loading data: " << e.what() << '\n';} -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts\tn\tf"},{"fact-dir","."},{"name","strings_fact"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 4, \"auxArity\": 0, \"params\": [\"u\", \"s\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 4, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"s:symbol\", \"i:number\", \"f:float\"]}}"}}); +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts\tn\tf"},{"auxArity","0"},{"fact-dir","."},{"name","strings_fact"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 4, \"params\": [\"u\", \"s\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 4, \"types\": [\"u:unsigned\", \"s:symbol\", \"i:number\", \"f:float\"]}}"}}); if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;} IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_6_strings_fact); -} catch (std::exception& e) {std::cerr << "Error loading data: " << e.what() << '\n';} +} catch (std::exception& e) {std::cerr << "Error loading strings_fact data: " << e.what() << '\n';} +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"auxArity","0"},{"fact-dir","."},{"name","numbers_fact"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); +if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;} +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_5_numbers_fact); +} catch (std::exception& e) {std::cerr << "Error loading numbers_fact data: " << e.what() << '\n';} } public: void dumpInputs() override { try {std::map rwOperation; rwOperation["IO"] = "stdout"; -rwOperation["name"] = "numbers_fact"; -rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_5_numbers_fact); -} catch (std::exception& e) {std::cerr << e.what();exit(1);} -try {std::map rwOperation; -rwOperation["IO"] = "stdout"; rwOperation["name"] = "strings_fact"; rwOperation["types"] = "{\"relation\": {\"arity\": 4, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"s:symbol\", \"i:number\", \"f:float\"]}}"; IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_6_strings_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} +try {std::map rwOperation; +rwOperation["IO"] = "stdout"; +rwOperation["name"] = "numbers_fact"; +rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"; +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_5_numbers_fact); +} catch (std::exception& e) {std::cerr << e.what();exit(1);} } public: void dumpOutputs() override { @@ -677,13 +680,7 @@ try {std::map rwOperation; rwOperation["IO"] = "stdout"; rwOperation["name"] = "from_datalog_fact"; rwOperation["types"] = "{\"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"u:unsigned\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_3_from_datalog_fact); -} catch (std::exception& e) {std::cerr << e.what();exit(1);} -try {std::map rwOperation; -rwOperation["IO"] = "stdout"; -rwOperation["name"] = "numbers_fact"; -rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_5_numbers_fact); +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_1_from_datalog_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map rwOperation; rwOperation["IO"] = "stdout"; @@ -693,6 +690,12 @@ IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll( } catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map rwOperation; rwOperation["IO"] = "stdout"; +rwOperation["name"] = "numbers_fact"; +rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"; +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_5_numbers_fact); +} catch (std::exception& e) {std::cerr << e.what();exit(1);} +try {std::map rwOperation; +rwOperation["IO"] = "stdout"; rwOperation["name"] = "from_datalog_string_fact"; rwOperation["types"] = "{\"relation\": {\"arity\": 2, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"s:symbol\"]}}"; IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_4_from_datalog_string_fact); @@ -702,6 +705,14 @@ IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll( SymbolTable& getSymbolTable() override { return symTable; } +RecordTable& getRecordTable() override { +return recordTable; +} +void setNumThreads(std::size_t numThreadsValue) override { +SouffleProgram::setNumThreads(numThreadsValue); +symTable.setNumLanes(getNumThreads()); +recordTable.setNumLanes(getNumThreads()); +} void executeSubroutine(std::string name, const std::vector& args, std::vector& ret) override { if (name == "stratum_0") { subroutine_0(args, ret); @@ -721,101 +732,61 @@ fatal("unknown subroutine"); #pragma warning(disable: 4100) #endif // _MSC_VER void subroutine_0(const std::vector& args, std::vector& ret) { -if (performIO) { -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"fact-dir","."},{"name","numbers_fact"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"auxArity\": 0, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); -if (!inputDirectory.empty()) {directiveMap["fact-dir"] = inputDirectory;} -IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_5_numbers_fact); -} catch (std::exception& e) {std::cerr << "Error loading data: " << e.what() << '\n';} -} -if (performIO) { -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"name","numbers_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"auxArity\": 0, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); -if (!outputDirectory.empty()) {directiveMap["output-dir"] = outputDirectory;} -IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_5_numbers_fact); -} catch (std::exception& e) {std::cerr << e.what();exit(1);} -} -} -#ifdef _MSC_VER -#pragma warning(default: 4100) -#endif // _MSC_VER -#ifdef _MSC_VER -#pragma warning(disable: 4100) -#endif // _MSC_VER -void subroutine_1(const std::vector& args, std::vector& ret) { -if (performIO) { -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts\tn\tf"},{"fact-dir","."},{"name","strings_fact"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 4, \"auxArity\": 0, \"params\": [\"u\", \"s\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 4, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"s:symbol\", \"i:number\", \"f:float\"]}}"}}); -if (!inputDirectory.empty()) {directiveMap["fact-dir"] = inputDirectory;} -IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_6_strings_fact); -} catch (std::exception& e) {std::cerr << "Error loading data: " << e.what() << '\n';} -} -if (performIO) { -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts\tn\tf"},{"name","strings_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 4, \"auxArity\": 0, \"params\": [\"u\", \"s\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 4, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"s:symbol\", \"i:number\", \"f:float\"]}}"}}); -if (!outputDirectory.empty()) {directiveMap["output-dir"] = outputDirectory;} -IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_6_strings_fact); -} catch (std::exception& e) {std::cerr << e.what();exit(1);} -} -} -#ifdef _MSC_VER -#pragma warning(default: 4100) -#endif // _MSC_VER -#ifdef _MSC_VER -#pragma warning(disable: 4100) -#endif // _MSC_VER -void subroutine_2(const std::vector& args, std::vector& ret) { -SignalHandler::instance()->setMsg(R"_(from_datalog_fact(0). -in file /home/luc/souffle-haskell/benchmarks/fixtures/bench.dl [18:1-18:22])_"); +signalHandler->setMsg(R"_(from_datalog_fact(0). +in file /tmp/souffle-haskell/benchmarks/fixtures/bench.dl [18:1-18:22])_"); [&](){ -CREATE_OP_CONTEXT(rel_3_from_datalog_fact_op_ctxt,rel_3_from_datalog_fact->createContext()); +CREATE_OP_CONTEXT(rel_1_from_datalog_fact_op_ctxt,rel_1_from_datalog_fact->createContext()); Tuple tuple{{ramBitCast(RamUnsigned(0))}}; -rel_3_from_datalog_fact->insert(tuple,READ_OP_CONTEXT(rel_3_from_datalog_fact_op_ctxt)); +rel_1_from_datalog_fact->insert(tuple,READ_OP_CONTEXT(rel_1_from_datalog_fact_op_ctxt)); } ();[&](){ -CREATE_OP_CONTEXT(rel_3_from_datalog_fact_op_ctxt,rel_3_from_datalog_fact->createContext()); -CREATE_OP_CONTEXT(rel_1_delta_from_datalog_fact_op_ctxt,rel_1_delta_from_datalog_fact->createContext()); -for(const auto& env0 : *rel_3_from_datalog_fact) { +CREATE_OP_CONTEXT(rel_2_delta_from_datalog_fact_op_ctxt,rel_2_delta_from_datalog_fact->createContext()); +CREATE_OP_CONTEXT(rel_1_from_datalog_fact_op_ctxt,rel_1_from_datalog_fact->createContext()); +for(const auto& env0 : *rel_1_from_datalog_fact) { Tuple tuple{{ramBitCast(env0[0])}}; -rel_1_delta_from_datalog_fact->insert(tuple,READ_OP_CONTEXT(rel_1_delta_from_datalog_fact_op_ctxt)); +rel_2_delta_from_datalog_fact->insert(tuple,READ_OP_CONTEXT(rel_2_delta_from_datalog_fact_op_ctxt)); } } ();iter = 0; for(;;) { -SignalHandler::instance()->setMsg(R"_(from_datalog_fact((x+1)) :- +signalHandler->setMsg(R"_(from_datalog_fact((x+1)) :- from_datalog_fact(x), x < 100. -in file /home/luc/souffle-haskell/benchmarks/fixtures/bench.dl [19:1-21:11])_"); -if(!(rel_1_delta_from_datalog_fact->empty())) { +in file /tmp/souffle-haskell/benchmarks/fixtures/bench.dl [19:1-21:11])_"); +if(!(rel_2_delta_from_datalog_fact->empty())) { [&](){ -CREATE_OP_CONTEXT(rel_3_from_datalog_fact_op_ctxt,rel_3_from_datalog_fact->createContext()); -CREATE_OP_CONTEXT(rel_1_delta_from_datalog_fact_op_ctxt,rel_1_delta_from_datalog_fact->createContext()); -CREATE_OP_CONTEXT(rel_2_new_from_datalog_fact_op_ctxt,rel_2_new_from_datalog_fact->createContext()); -auto range = rel_1_delta_from_datalog_fact->lowerUpperRange_2(Tuple{{ramBitCast(MIN_RAM_UNSIGNED)}},Tuple{{ramBitCast(RamUnsigned(100))}},READ_OP_CONTEXT(rel_1_delta_from_datalog_fact_op_ctxt)); +CREATE_OP_CONTEXT(rel_2_delta_from_datalog_fact_op_ctxt,rel_2_delta_from_datalog_fact->createContext()); +CREATE_OP_CONTEXT(rel_1_from_datalog_fact_op_ctxt,rel_1_from_datalog_fact->createContext()); +CREATE_OP_CONTEXT(rel_3_new_from_datalog_fact_op_ctxt,rel_3_new_from_datalog_fact->createContext()); +auto range = rel_2_delta_from_datalog_fact->lowerUpperRange_2(Tuple{{ramBitCast(MIN_RAM_UNSIGNED)}},Tuple{{ramBitCast(RamUnsigned(100))}},READ_OP_CONTEXT(rel_2_delta_from_datalog_fact_op_ctxt)); for(const auto& env0 : range) { -if( (ramBitCast(env0[0]) != ramBitCast(RamUnsigned(100))) && !(rel_3_from_datalog_fact->contains(Tuple{{ramBitCast((ramBitCast(env0[0]) + ramBitCast(RamUnsigned(1))))}},READ_OP_CONTEXT(rel_3_from_datalog_fact_op_ctxt)))) { +if( (ramBitCast(env0[0]) != ramBitCast(RamUnsigned(100))) && !(rel_1_from_datalog_fact->contains(Tuple{{ramBitCast((ramBitCast(env0[0]) + ramBitCast(RamUnsigned(1))))}},READ_OP_CONTEXT(rel_1_from_datalog_fact_op_ctxt)))) { Tuple tuple{{ramBitCast((ramBitCast(env0[0]) + ramBitCast(RamUnsigned(1))))}}; -rel_2_new_from_datalog_fact->insert(tuple,READ_OP_CONTEXT(rel_2_new_from_datalog_fact_op_ctxt)); +rel_3_new_from_datalog_fact->insert(tuple,READ_OP_CONTEXT(rel_3_new_from_datalog_fact_op_ctxt)); } } } ();} -if(rel_2_new_from_datalog_fact->empty()) break; +if(rel_3_new_from_datalog_fact->empty()) break; [&](){ -CREATE_OP_CONTEXT(rel_3_from_datalog_fact_op_ctxt,rel_3_from_datalog_fact->createContext()); -CREATE_OP_CONTEXT(rel_2_new_from_datalog_fact_op_ctxt,rel_2_new_from_datalog_fact->createContext()); -for(const auto& env0 : *rel_2_new_from_datalog_fact) { +CREATE_OP_CONTEXT(rel_1_from_datalog_fact_op_ctxt,rel_1_from_datalog_fact->createContext()); +CREATE_OP_CONTEXT(rel_3_new_from_datalog_fact_op_ctxt,rel_3_new_from_datalog_fact->createContext()); +for(const auto& env0 : *rel_3_new_from_datalog_fact) { Tuple tuple{{ramBitCast(env0[0])}}; -rel_3_from_datalog_fact->insert(tuple,READ_OP_CONTEXT(rel_3_from_datalog_fact_op_ctxt)); +rel_1_from_datalog_fact->insert(tuple,READ_OP_CONTEXT(rel_1_from_datalog_fact_op_ctxt)); } } -();std::swap(rel_1_delta_from_datalog_fact, rel_2_new_from_datalog_fact); -rel_2_new_from_datalog_fact->purge(); +();std::swap(rel_2_delta_from_datalog_fact, rel_3_new_from_datalog_fact); +rel_3_new_from_datalog_fact->purge(); iter++; } iter = 0; -rel_1_delta_from_datalog_fact->purge(); -rel_2_new_from_datalog_fact->purge(); +rel_2_delta_from_datalog_fact->purge(); +rel_3_new_from_datalog_fact->purge(); if (performIO) { -try {std::map directiveMap({{"IO","file"},{"attributeNames","u"},{"name","from_datalog_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"auxArity\": 0, \"params\": [\"u\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"u:unsigned\"]}}"}}); +try {std::map directiveMap({{"IO","file"},{"attributeNames","u"},{"auxArity","0"},{"name","from_datalog_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"u\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"u:unsigned\"]}}"}}); if (!outputDirectory.empty()) {directiveMap["output-dir"] = outputDirectory;} -IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_3_from_datalog_fact); +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_1_from_datalog_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} } } @@ -825,34 +796,74 @@ IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll #ifdef _MSC_VER #pragma warning(disable: 4100) #endif // _MSC_VER -void subroutine_3(const std::vector& args, std::vector& ret) { -SignalHandler::instance()->setMsg(R"_(from_datalog_string_fact(x,"abcdef") :- +void subroutine_1(const std::vector& args, std::vector& ret) { +signalHandler->setMsg(R"_(from_datalog_string_fact(x,"abcdef") :- from_datalog_fact(x). -in file /home/luc/souffle-haskell/benchmarks/fixtures/bench.dl [23:1-24:24])_"); -if(!(rel_3_from_datalog_fact->empty())) { +in file /tmp/souffle-haskell/benchmarks/fixtures/bench.dl [23:1-24:24])_"); +if(!(rel_1_from_datalog_fact->empty())) { [&](){ -CREATE_OP_CONTEXT(rel_3_from_datalog_fact_op_ctxt,rel_3_from_datalog_fact->createContext()); +CREATE_OP_CONTEXT(rel_1_from_datalog_fact_op_ctxt,rel_1_from_datalog_fact->createContext()); CREATE_OP_CONTEXT(rel_4_from_datalog_string_fact_op_ctxt,rel_4_from_datalog_string_fact->createContext()); -for(const auto& env0 : *rel_3_from_datalog_fact) { +for(const auto& env0 : *rel_1_from_datalog_fact) { Tuple tuple{{ramBitCast(env0[0]),ramBitCast(RamSigned(0))}}; rel_4_from_datalog_string_fact->insert(tuple,READ_OP_CONTEXT(rel_4_from_datalog_string_fact_op_ctxt)); } } ();} if (performIO) { -try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts"},{"name","from_datalog_string_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 2, \"auxArity\": 0, \"params\": [\"u\", \"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 2, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"s:symbol\"]}}"}}); +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts"},{"auxArity","0"},{"name","from_datalog_string_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 2, \"params\": [\"u\", \"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 2, \"types\": [\"u:unsigned\", \"s:symbol\"]}}"}}); if (!outputDirectory.empty()) {directiveMap["output-dir"] = outputDirectory;} IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_4_from_datalog_string_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} } -if (performIO) rel_3_from_datalog_fact->purge(); +if (pruneImdtRels) rel_1_from_datalog_fact->purge(); +} +#ifdef _MSC_VER +#pragma warning(default: 4100) +#endif // _MSC_VER +#ifdef _MSC_VER +#pragma warning(disable: 4100) +#endif // _MSC_VER +void subroutine_2(const std::vector& args, std::vector& ret) { +if (performIO) { +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"auxArity","0"},{"fact-dir","."},{"name","numbers_fact"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); +if (!inputDirectory.empty()) {directiveMap["fact-dir"] = inputDirectory;} +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_5_numbers_fact); +} catch (std::exception& e) {std::cerr << "Error loading numbers_fact data: " << e.what() << '\n';} +} +if (performIO) { +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"auxArity","0"},{"name","numbers_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); +if (!outputDirectory.empty()) {directiveMap["output-dir"] = outputDirectory;} +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_5_numbers_fact); +} catch (std::exception& e) {std::cerr << e.what();exit(1);} +} +} +#ifdef _MSC_VER +#pragma warning(default: 4100) +#endif // _MSC_VER +#ifdef _MSC_VER +#pragma warning(disable: 4100) +#endif // _MSC_VER +void subroutine_3(const std::vector& args, std::vector& ret) { +if (performIO) { +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts\tn\tf"},{"auxArity","0"},{"fact-dir","."},{"name","strings_fact"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 4, \"params\": [\"u\", \"s\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 4, \"types\": [\"u:unsigned\", \"s:symbol\", \"i:number\", \"f:float\"]}}"}}); +if (!inputDirectory.empty()) {directiveMap["fact-dir"] = inputDirectory;} +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_6_strings_fact); +} catch (std::exception& e) {std::cerr << "Error loading strings_fact data: " << e.what() << '\n';} +} +if (performIO) { +try {std::map directiveMap({{"IO","file"},{"attributeNames","u\ts\tn\tf"},{"auxArity","0"},{"name","strings_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 4, \"params\": [\"u\", \"s\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 4, \"types\": [\"u:unsigned\", \"s:symbol\", \"i:number\", \"f:float\"]}}"}}); +if (!outputDirectory.empty()) {directiveMap["output-dir"] = outputDirectory;} +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_6_strings_fact); +} catch (std::exception& e) {std::cerr << e.what();exit(1);} +} } #ifdef _MSC_VER #pragma warning(default: 4100) #endif // _MSC_VER }; SouffleProgram *newInstance_bench(){return new Sf_bench;} -SymbolTable *getST_bench(SouffleProgram *p){return &reinterpret_cast(p)->symTable;} +SymbolTable *getST_bench(SouffleProgram *p){return &reinterpret_cast(p)->getSymbolTable();} #ifdef __EMBEDDED_SOUFFLE__ class factory_Sf_bench: public souffle::ProgramFactory { diff --git a/cbits/souffle/CompiledSouffle.h b/cbits/souffle/CompiledSouffle.h index 01008a7..78f03b7 100644 --- a/cbits/souffle/CompiledSouffle.h +++ b/cbits/souffle/CompiledSouffle.h @@ -24,8 +24,6 @@ #include "souffle/datastructure/BTreeDelete.h" #include "souffle/datastructure/Brie.h" #include "souffle/datastructure/EquivalenceRelation.h" -#include "souffle/datastructure/RecordTableImpl.h" -#include "souffle/datastructure/SymbolTableImpl.h" #include "souffle/datastructure/Table.h" #include "souffle/io/IOSystem.h" #include "souffle/io/WriteStream.h" diff --git a/cbits/souffle/RecordTable.h b/cbits/souffle/RecordTable.h index 5c173cb..e3ce502 100644 --- a/cbits/souffle/RecordTable.h +++ b/cbits/souffle/RecordTable.h @@ -18,11 +18,469 @@ #pragma once #include "souffle/RamTypes.h" +#include "souffle/datastructure/ConcurrentFlyweight.h" #include "souffle/utility/span.h" -#include +#include +#include +#include +#include +#include +#include namespace souffle { +namespace details { + +// Helper to unroll for loop +template +constexpr void constexpr_for(F&& f) { + if constexpr (Start < End) { + f(std::integral_constant()); + constexpr_for(f); + } +} + +/// @brief The data-type of RamDomain records of any size. +using GenericRecord = std::vector; + +/// @brief The data-type of RamDomain records of specialized size. +template +using SpecializedRecord = std::array; + +/// @brief A view in a sequence of RamDomain value. +// TODO: use a `span`. +struct GenericRecordView { + explicit GenericRecordView(const RamDomain* Data, const std::size_t Arity) : Data(Data), Arity(Arity) {} + GenericRecordView(const GenericRecordView& Other) : Data(Other.Data), Arity(Other.Arity) {} + GenericRecordView(GenericRecordView&& Other) : Data(Other.Data), Arity(Other.Arity) {} + + const RamDomain* const Data; + const std::size_t Arity; + + const RamDomain* data() const { + return Data; + } + + const RamDomain& operator[](int I) const { + assert(I >= 0 && static_cast(I) < Arity); + return Data[I]; + } +}; + +template +struct SpecializedRecordView { + explicit SpecializedRecordView(const RamDomain* Data) : Data(Data) {} + SpecializedRecordView(const SpecializedRecordView& Other) : Data(Other.Data) {} + SpecializedRecordView(SpecializedRecordView&& Other) : Data(Other.Data) {} + + const RamDomain* const Data; + + const RamDomain* data() const { + return Data; + } + + const RamDomain& operator[](int I) const { + assert(I >= 0 && static_cast(I) < Arity); + return Data[I]; + } +}; + +/// @brief Hash function object for a RamDomain record. +struct GenericRecordHash { + explicit GenericRecordHash(const std::size_t Arity) : Arity(Arity) {} + GenericRecordHash(const GenericRecordHash& Other) : Arity(Other.Arity) {} + GenericRecordHash(GenericRecordHash&& Other) : Arity(Other.Arity) {} + + const std::size_t Arity; + std::hash domainHash; + + template + std::size_t operator()(const T& Record) const { + std::size_t Seed = 0; + for (std::size_t I = 0; I < Arity; ++I) { + Seed ^= domainHash(Record[I]) + 0x9e3779b9 + (Seed << 6) + (Seed >> 2); + } + return Seed; + } +}; + +template +struct SpecializedRecordHash { + explicit SpecializedRecordHash() {} + SpecializedRecordHash(const SpecializedRecordHash& Other) : DomainHash(Other.DomainHash) {} + SpecializedRecordHash(SpecializedRecordHash&& Other) : DomainHash(Other.DomainHash) {} + + std::hash DomainHash; + + template + std::size_t operator()(const T& Record) const { + std::size_t Seed = 0; + constexpr_for<0, Arity, 1>( + [&](auto I) { Seed ^= DomainHash(Record[I]) + 0x9e3779b9 + (Seed << 6) + (Seed >> 2); }); + return Seed; + } +}; + +template <> +struct SpecializedRecordHash<0> { + explicit SpecializedRecordHash() {} + SpecializedRecordHash(const SpecializedRecordHash&) {} + SpecializedRecordHash(SpecializedRecordHash&&) {} + + template + std::size_t operator()(const T&) const { + return 0; + } +}; + +/// @brief Equality function object for RamDomain records. +struct GenericRecordEqual { + explicit GenericRecordEqual(const std::size_t Arity) : Arity(Arity) {} + GenericRecordEqual(const GenericRecordEqual& Other) : Arity(Other.Arity) {} + GenericRecordEqual(GenericRecordEqual&& Other) : Arity(Other.Arity) {} + + const std::size_t Arity; + + template + bool operator()(const T& A, const U& B) const { + return (std::memcmp(A.data(), B.data(), Arity * sizeof(RamDomain)) == 0); + } +}; + +template +struct SpecializedRecordEqual { + explicit SpecializedRecordEqual() {} + SpecializedRecordEqual(const SpecializedRecordEqual&) {} + SpecializedRecordEqual(SpecializedRecordEqual&&) {} + + template + bool operator()(const T& A, const U& B) const { + constexpr std::size_t Len = Arity * sizeof(RamDomain); + return (std::memcmp(A.data(), B.data(), Len) == 0); + } +}; + +template <> +struct SpecializedRecordEqual<0> { + explicit SpecializedRecordEqual() {} + SpecializedRecordEqual(const SpecializedRecordEqual&) {} + SpecializedRecordEqual(SpecializedRecordEqual&&) {} + + template + bool operator()(const T&, const U&) const { + return true; + } +}; + +/// @brief Less function object for RamDomain records. +struct GenericRecordLess { + explicit GenericRecordLess(const std::size_t Arity) : Arity(Arity) {} + GenericRecordLess(const GenericRecordLess& Other) : Arity(Other.Arity) {} + GenericRecordLess(GenericRecordLess&& Other) : Arity(Other.Arity) {} + + const std::size_t Arity; + + template + bool operator()(const T& A, const U& B) const { + return (std::memcmp(A.data(), B.data(), Arity * sizeof(RamDomain)) < 0); + } +}; + +template +struct SpecializedRecordLess { + explicit SpecializedRecordLess() {} + SpecializedRecordLess(const SpecializedRecordLess&) {} + SpecializedRecordLess(SpecializedRecordLess&&) {} + + template + bool operator()(const T& A, const U& B) const { + constexpr std::size_t Len = Arity * sizeof(RamDomain); + return (std::memcmp(A.data(), B.data(), Len) < 0); + } +}; + +template <> +struct SpecializedRecordLess<0> { + explicit SpecializedRecordLess() {} + SpecializedRecordLess(const SpecializedRecordLess&) {} + SpecializedRecordLess(SpecializedRecordLess&&) {} + + template + bool operator()(const T&, const U&) const { + return false; + } +}; + +/// @brief Compare function object for RamDomain records. +struct GenericRecordCmp { + explicit GenericRecordCmp(const std::size_t Arity) : Arity(Arity) {} + GenericRecordCmp(const GenericRecordCmp& Other) : Arity(Other.Arity) {} + GenericRecordCmp(GenericRecordCmp&& Other) : Arity(Other.Arity) {} + + const std::size_t Arity; + + template + int operator()(const T& A, const U& B) const { + return std::memcmp(A.data(), B.data(), Arity * sizeof(RamDomain)); + } +}; + +template +struct SpecializedRecordCmp { + explicit SpecializedRecordCmp() {} + SpecializedRecordCmp(const SpecializedRecordCmp&) {} + SpecializedRecordCmp(SpecializedRecordCmp&&) {} + + template + bool operator()(const T& A, const U& B) const { + constexpr std::size_t Len = Arity * sizeof(RamDomain); + return std::memcmp(A.data(), B.data(), Len); + } +}; + +template <> +struct SpecializedRecordCmp<0> { + explicit SpecializedRecordCmp() {} + SpecializedRecordCmp(const SpecializedRecordCmp&) {} + SpecializedRecordCmp(SpecializedRecordCmp&&) {} + + template + bool operator()(const T&, const U&) const { + return 0; + } +}; + +/// @brief Factory of RamDomain record. +struct GenericRecordFactory { + using value_type = GenericRecord; + using pointer = GenericRecord*; + using reference = GenericRecord&; + + explicit GenericRecordFactory(const std::size_t Arity) : Arity(Arity) {} + GenericRecordFactory(const GenericRecordFactory& Other) : Arity(Other.Arity) {} + GenericRecordFactory(GenericRecordFactory&& Other) : Arity(Other.Arity) {} + + const std::size_t Arity; + + reference replace(reference Place, const std::vector& V) { + assert(V.size() == Arity); + Place = V; + return Place; + } + + reference replace(reference Place, const GenericRecordView& V) { + Place.clear(); + Place.insert(Place.begin(), V.data(), V.data() + Arity); + return Place; + } + + reference replace(reference Place, const RamDomain* V) { + Place.clear(); + Place.insert(Place.begin(), V, V + Arity); + return Place; + } +}; + +template +struct SpecializedRecordFactory { + using value_type = SpecializedRecord; + using pointer = SpecializedRecord*; + using reference = SpecializedRecord&; + + explicit SpecializedRecordFactory() {} + SpecializedRecordFactory(const SpecializedRecordFactory&) {} + SpecializedRecordFactory(SpecializedRecordFactory&&) {} + + reference replace(reference Place, const SpecializedRecord& V) { + assert(V.size() == Arity); + Place = V; + return Place; + } + + reference replace(reference Place, const SpecializedRecordView& V) { + constexpr std::size_t Len = Arity * sizeof(RamDomain); + std::memcpy(Place.data(), V.data(), Len); + return Place; + } + + reference replace(reference Place, const RamDomain* V) { + constexpr std::size_t Len = Arity * sizeof(RamDomain); + std::memcpy(Place.data(), V, Len); + return Place; + } +}; + +template <> +struct SpecializedRecordFactory<0> { + using value_type = SpecializedRecord<0>; + using pointer = SpecializedRecord<0>*; + using reference = SpecializedRecord<0>&; + + explicit SpecializedRecordFactory() {} + SpecializedRecordFactory(const SpecializedRecordFactory&) {} + SpecializedRecordFactory(SpecializedRecordFactory&&) {} + + reference replace(reference Place, const SpecializedRecord<0>&) { + return Place; + } + + reference replace(reference Place, const SpecializedRecordView<0>&) { + return Place; + } + + reference replace(reference Place, const RamDomain*) { + return Place; + } +}; + +} // namespace details + +/** @brief Interface of bidirectional mappping between records and record references. */ +class RecordMap { +public: + virtual ~RecordMap() {} + virtual void setNumLanes(const std::size_t NumLanes) = 0; + virtual RamDomain pack(const std::vector& Vector) = 0; + virtual RamDomain pack(const RamDomain* Tuple) = 0; + virtual RamDomain pack(const std::initializer_list& List) = 0; + virtual const RamDomain* unpack(RamDomain index) const = 0; +}; + +/** @brief Bidirectional mappping between records and record references, for any record arity. */ +class GenericRecordMap : public RecordMap, + protected FlyweightImpl { + using Base = FlyweightImpl; + + const std::size_t Arity; + +public: + explicit GenericRecordMap(const std::size_t lane_count, const std::size_t arity) + : Base(lane_count, 8, true, details::GenericRecordHash(arity), details::GenericRecordEqual(arity), + details::GenericRecordFactory(arity)), + Arity(arity) {} + + virtual ~GenericRecordMap() {} + + void setNumLanes(const std::size_t NumLanes) override { + Base::setNumLanes(NumLanes); + } + + /** @brief converts record to a record reference */ + RamDomain pack(const std::vector& Vector) override { + return findOrInsert(Vector).first; + }; + + /** @brief converts record to a record reference */ + RamDomain pack(const RamDomain* Tuple) override { + details::GenericRecordView View{Tuple, Arity}; + return findOrInsert(View).first; + } + + /** @brief converts record to a record reference */ + RamDomain pack(const std::initializer_list& List) override { + details::GenericRecordView View{std::data(List), Arity}; + return findOrInsert(View).first; + } + + /** @brief convert record reference to a record pointer */ + const RamDomain* unpack(RamDomain Index) const override { + return fetch(Index).data(); + } +}; + +/** @brief Bidirectional mappping between records and record references, specialized for a record arity. */ +template +class SpecializedRecordMap + : public RecordMap, + protected FlyweightImpl, details::SpecializedRecordHash, + details::SpecializedRecordEqual, details::SpecializedRecordFactory> { + using Record = details::SpecializedRecord; + using RecordView = details::SpecializedRecordView; + using RecordHash = details::SpecializedRecordHash; + using RecordEqual = details::SpecializedRecordEqual; + using RecordFactory = details::SpecializedRecordFactory; + using Base = FlyweightImpl; + +public: + SpecializedRecordMap(const std::size_t LaneCount) + : Base(LaneCount, 8, true, RecordHash(), RecordEqual(), RecordFactory()) {} + + virtual ~SpecializedRecordMap() {} + + void setNumLanes(const std::size_t NumLanes) override { + Base::setNumLanes(NumLanes); + } + + /** @brief converts record to a record reference */ + RamDomain pack(const std::vector& Vector) override { + assert(Vector.size() == Arity); + RecordView View{Vector.data()}; + return Base::findOrInsert(View).first; + }; + + /** @brief converts record to a record reference */ + RamDomain pack(const RamDomain* Tuple) override { + RecordView View{Tuple}; + return Base::findOrInsert(View).first; + } + + /** @brief converts record to a record reference */ + RamDomain pack(const std::initializer_list& List) override { + assert(List.size() == Arity); + RecordView View{std::data(List)}; + return Base::findOrInsert(View).first; + } + + /** @brief convert record reference to a record pointer */ + const RamDomain* unpack(RamDomain Index) const override { + return Base::fetch(Index).data(); + } +}; + +/** Record map specialized for arity 0 */ +template <> +class SpecializedRecordMap<0> : public RecordMap { + // The empty record always at index 1 + // The index 0 of each map is reserved. + static constexpr RamDomain EmptyRecordIndex = 1; + + // To comply with previous behavior, the empty record + // has no data: + const RamDomain* EmptyRecordData = nullptr; + +public: + SpecializedRecordMap(const std::size_t /* LaneCount */) {} + + virtual ~SpecializedRecordMap() {} + + void setNumLanes(const std::size_t) override {} + + /** @brief converts record to a record reference */ + RamDomain pack([[maybe_unused]] const std::vector& Vector) override { + assert(Vector.size() == 0); + return EmptyRecordIndex; + }; + + /** @brief converts record to a record reference */ + RamDomain pack(const RamDomain*) override { + return EmptyRecordIndex; + } + + /** @brief converts record to a record reference */ + RamDomain pack([[maybe_unused]] const std::initializer_list& List) override { + assert(List.size() == 0); + return EmptyRecordIndex; + } + + /** @brief convert record reference to a record pointer */ + const RamDomain* unpack([[maybe_unused]] RamDomain Index) const override { + assert(Index == EmptyRecordIndex); + return EmptyRecordData; + } +}; + /** The interface of any Record Table. */ class RecordTable { public: @@ -37,6 +495,121 @@ class RecordTable { virtual const RamDomain* unpack(const RamDomain Ref, const std::size_t Arity) const = 0; }; +/** A concurrent Record Table with some specialized record maps. */ +template +class SpecializedRecordTable : public RecordTable { +private: + // The current size of the Maps vector. + std::size_t Size; + + // The record maps, indexed by arity. + std::vector Maps; + + // The concurrency manager. + mutable ConcurrentLanes Lanes; + + template + void CreateSpecializedMaps() { + if (Arity >= Size) { + Size = Arity + 1; + Maps.reserve(Size); + Maps.resize(Size); + } + Maps[Arity] = new SpecializedRecordMap(Lanes.lanes()); + if constexpr (sizeof...(Arities) > 0) { + CreateSpecializedMaps(); + } + } + +public: + /** @brief Construct a record table with the number of concurrent access lanes. */ + SpecializedRecordTable(const std::size_t LaneCount) : Size(0), Lanes(LaneCount) { + CreateSpecializedMaps(); + } + + SpecializedRecordTable() : SpecializedRecordTable(1) {} + + virtual ~SpecializedRecordTable() { + for (auto Map : Maps) { + delete Map; + } + } + + /** + * @brief set the number of concurrent access lanes. + * Not thread-safe, use only when the datastructure is not being used. + */ + virtual void setNumLanes(const std::size_t NumLanes) override { + Lanes.setNumLanes(NumLanes); + for (auto& Map : Maps) { + if (Map) { + Map->setNumLanes(NumLanes); + } + } + } + + /** @brief convert tuple to record reference */ + virtual RamDomain pack(const RamDomain* Tuple, const std::size_t Arity) override { + auto Guard = Lanes.guard(); + return lookupMap(Arity).pack(Tuple); + } + + /** @brief convert tuple to record reference */ + virtual RamDomain pack(const std::initializer_list& List) override { + auto Guard = Lanes.guard(); + return lookupMap(List.size()).pack(std::data(List)); + } + + /** @brief convert record reference to a record */ + virtual const RamDomain* unpack(const RamDomain Ref, const std::size_t Arity) const override { + auto Guard = Lanes.guard(); + return lookupMap(Arity).unpack(Ref); + } + +private: + /** @brief lookup RecordMap for a given arity; the map for that arity must exist. */ + RecordMap& lookupMap(const std::size_t Arity) const { + assert(Arity < Size && "Lookup for an arity while there is no record for that arity."); + auto* Map = Maps[Arity]; + assert(Map != nullptr && "Lookup for an arity while there is no record for that arity."); + return *Map; + } + + /** @brief lookup RecordMap for a given arity; if it does not exist, create new RecordMap */ + RecordMap& lookupMap(const std::size_t Arity) { + if (Arity < Size) { + auto* Map = Maps[Arity]; + if (Map) { + return *Map; + } + } + + createMap(Arity); + return *Maps[Arity]; + } + + /** @brief create the RecordMap for the given arity. */ + void createMap(const std::size_t Arity) { + Lanes.beforeLockAllBut(); + if (Arity < Size && Maps[Arity] != nullptr) { + // Map of required arity has been created concurrently + Lanes.beforeUnlockAllBut(); + return; + } + Lanes.lockAllBut(); + + if (Arity >= Size) { + Size = Arity + 1; + Maps.reserve(Size); + Maps.resize(Size); + } + Maps[Arity] = new GenericRecordMap(Lanes.lanes(), Arity); + + Lanes.beforeUnlockAllBut(); + Lanes.unlockAllBut(); + } +}; + /** @brief helper to convert tuple to record reference for the synthesiser */ template RamDomain pack(RecordTableT&& recordTab, Tuple const& tuple) { diff --git a/cbits/souffle/SignalHandler.h b/cbits/souffle/SignalHandler.h index 3e9beec..9ad6291 100644 --- a/cbits/souffle/SignalHandler.h +++ b/cbits/souffle/SignalHandler.h @@ -26,12 +26,12 @@ #include #include -#ifndef _MSC_VER -#include -#else +#ifdef _WIN32 #include -#define STDERR_FILENO 2 -#endif +#define STDERR_FILENO 2 /* Standard error output. */ +#else +#include +#endif //_WIN32 namespace souffle { @@ -180,13 +180,7 @@ class SignalHandler { // assign to variable to suppress ignored-return-value error. // I don't think we care enough to handle this fringe failure mode. // Worse case we don't get an error message. -#ifdef _MSC_VER - [[maybe_unused]] auto _ = - ::_write(STDERR_FILENO, msg, static_cast(::strlen(msg))); -#else - [[maybe_unused]] auto _ = - ::write(STDERR_FILENO, msg, static_cast(::strlen(msg))); -#endif + [[maybe_unused]] auto _ = ::write(STDERR_FILENO, msg, ::strlen(msg)); } }; diff --git a/cbits/souffle/SouffleInterface.h b/cbits/souffle/SouffleInterface.h index 2087b38..12b6c0b 100644 --- a/cbits/souffle/SouffleInterface.h +++ b/cbits/souffle/SouffleInterface.h @@ -43,7 +43,7 @@ class tuple; */ class Relation { public: - using arity_type = std::size_t; + using arity_type = uint32_t; protected: /** @@ -67,15 +67,15 @@ class Relation { * * TODO (Honghyw) : Provide a clear documentation of what id is used for. */ - std::size_t id; + uint32_t id; public: /** * Get the ID of the iterator_base object. * - * @return ID of the iterator_base object (std::size_t) + * @return ID of the iterator_base object (unit32_t) */ - virtual std::size_t getId() const { + virtual uint32_t getId() const { return id; } @@ -84,9 +84,9 @@ class Relation { * * Create an instance of iterator_base and set its ID to be arg_id. * - * @param arg_id ID of an iterator object (std::size_t) + * @param arg_id ID of an iterator object (unit32_t) */ - iterator_base(std::size_t arg_id) : id(arg_id) {} + iterator_base(uint32_t arg_id) : id(arg_id) {} /** * Destructor. @@ -332,8 +332,7 @@ class Relation { /** * Get the attribute type of a relation at the column specified by the parameter. * The attribute type is in the form ":". - * can be s, f, u, i, r, or + standing for symbol, float, - * unsigned, integer, record, and ADT respectively, + * can be s, f, u, or i standing for symbol, float, unsigned, and integer respectively, * which are the primitive types in Souffle. * is the name given by the user in the Souffle program * @@ -577,8 +576,7 @@ class tuple { */ tuple& operator<<(RamSigned integer) { assert(pos < size() && "exceeded tuple's size"); - assert((*relation.getAttrType(pos) == 'i' || *relation.getAttrType(pos) == 'r' || - *relation.getAttrType(pos) == '+') && + assert((*relation.getAttrType(pos) == 'i' || *relation.getAttrType(pos) == 'r') && "wrong element type"); array[pos++] = integer; return *this; @@ -635,8 +633,7 @@ class tuple { */ tuple& operator>>(RamSigned& integer) { assert(pos < size() && "exceeded tuple's size"); - assert((*relation.getAttrType(pos) == 'i' || *relation.getAttrType(pos) == 'r' || - *relation.getAttrType(pos) == '+') && + assert((*relation.getAttrType(pos) == 'i' || *relation.getAttrType(pos) == 'r') && "wrong element type"); integer = ramBitCast(array[pos++]); return *this; diff --git a/cbits/souffle/SymbolTable.h b/cbits/souffle/SymbolTable.h index ce947c4..bb71778 100644 --- a/cbits/souffle/SymbolTable.h +++ b/cbits/souffle/SymbolTable.h @@ -17,105 +17,95 @@ #pragma once #include "souffle/RamTypes.h" - -#include +#include "souffle/datastructure/ConcurrentFlyweight.h" +#include "souffle/utility/MiscUtil.h" +#include "souffle/utility/ParallelUtil.h" +#include "souffle/utility/StreamUtil.h" +#include +#include +#include +#include +#include #include +#include +#include +#include namespace souffle { -/** Interface of a generic SymbolTable iterator. */ -class SymbolTableIteratorInterface { -public: - virtual ~SymbolTableIteratorInterface() {} - - virtual const std::pair& get() const = 0; - - virtual bool equals(const SymbolTableIteratorInterface& other) = 0; - - virtual SymbolTableIteratorInterface& incr() = 0; - - virtual std::unique_ptr copy() const = 0; -}; - /** * @class SymbolTable * * SymbolTable encodes symbols to numbers and decodes numbers to symbols. */ -class SymbolTable { -public: - virtual ~SymbolTable() {} - - /** - * @brief Iterator on a symbol table. - * - * Iterator over pairs of a symbol and its encoding index. - */ - class Iterator { - public: - using value_type = const std::pair; - using reference = value_type&; - using pointer = value_type*; - - Iterator(std::unique_ptr ptr) : impl(std::move(ptr)) {} +class SymbolTable : protected FlyweightImpl { +private: + using Base = FlyweightImpl; - Iterator(const Iterator& it) : impl(it.impl->copy()) {} - - Iterator(Iterator&& it) : impl(std::move(it.impl)) {} - - reference operator*() const { - return impl->get(); - } - - pointer operator->() const { - return &impl->get(); - } - - Iterator& operator++() { - impl->incr(); - return *this; - } +public: + using iterator = typename Base::iterator; - Iterator operator++(int) { - Iterator prev(impl->copy()); - impl->incr(); - return prev; - } + /** @brief Construct a symbol table with the given number of concurrent access lanes. */ + SymbolTable(const std::size_t LaneCount = 1) : Base(LaneCount) {} - bool operator==(const Iterator& I) const { - return impl->equals(*I.impl); + /** @brief Construct a symbol table with the given initial symbols. */ + SymbolTable(std::initializer_list symbols) : Base(1, symbols.size()) { + for (const auto& symbol : symbols) { + findOrInsert(symbol); } + } - bool operator!=(const Iterator& I) const { - return !impl->equals(*I.impl); + /** @brief Construct a symbol table with the given number of concurrent access lanes and initial symbols. + */ + SymbolTable(const std::size_t LaneCount, std::initializer_list symbols) + : Base(LaneCount, symbols.size()) { + for (const auto& symbol : symbols) { + findOrInsert(symbol); } + } - private: - std::unique_ptr impl; - }; - - using iterator = Iterator; + /** + * @brief Set the number of concurrent access lanes. + * This function is not thread-safe, do not call when other threads are using the datastructure. + */ + void setNumLanes(const std::size_t NumLanes) { + Base::setNumLanes(NumLanes); + } /** @brief Return an iterator on the first symbol. */ - virtual iterator begin() const = 0; + iterator begin() const { + return Base::begin(); + } /** @brief Return an iterator past the last symbol. */ - virtual iterator end() const = 0; + iterator end() const { + return Base::end(); + } /** @brief Check if the given symbol exist. */ - virtual bool weakContains(const std::string& symbol) const = 0; + bool weakContains(const std::string& symbol) const { + return Base::weakContains(symbol); + } /** @brief Encode a symbol to a symbol index. */ - virtual RamDomain encode(const std::string& symbol) = 0; + RamDomain encode(const std::string& symbol) { + return Base::findOrInsert(symbol).first; + } /** @brief Decode a symbol index to a symbol. */ - virtual const std::string& decode(const RamDomain index) const = 0; + const std::string& decode(const RamDomain index) const { + return Base::fetch(index); + } /** @brief Encode a symbol to a symbol index; aliases encode. */ - virtual RamDomain unsafeEncode(const std::string& symbol) = 0; + RamDomain unsafeEncode(const std::string& symbol) { + return encode(symbol); + } /** @brief Decode a symbol index to a symbol; aliases decode. */ - virtual const std::string& unsafeDecode(const RamDomain index) const = 0; + const std::string& unsafeDecode(const RamDomain index) const { + return decode(index); + } /** * @brief Encode the symbol, it is inserted if it does not exist. @@ -123,7 +113,10 @@ class SymbolTable { * @return the symbol index and a boolean indicating if an insertion * happened. */ - virtual std::pair findOrInsert(const std::string& symbol) = 0; + std::pair findOrInsert(const std::string& symbol) { + auto Res = Base::findOrInsert(symbol); + return std::make_pair(Res.first, Res.second); + } }; } // namespace souffle diff --git a/cbits/souffle/datastructure/BTree.h b/cbits/souffle/datastructure/BTree.h index 47d2bc8..c085636 100644 --- a/cbits/souffle/datastructure/BTree.h +++ b/cbits/souffle/datastructure/BTree.h @@ -624,7 +624,7 @@ class btree { } } - pos = (i > static_cast(other->numElements)) ? 0 : static_cast(i); + pos = (i > other->numElements) ? 0 : i; other->insert_inner(root, root_lock, pos, predecessor, key, newNode, locked_nodes); #else other->insert_inner(root, root_lock, pos, predecessor, key, newNode); @@ -1340,8 +1340,7 @@ class btree { // split this node auto old_root = root; - idx -= cur->rebalance_or_split( - const_cast(&root), root_lock, static_cast(idx), parents); + idx -= cur->rebalance_or_split(const_cast(&root), root_lock, idx, parents); // release parent lock for (auto it = parents.rbegin(); it != parents.rend(); ++it) { @@ -1373,7 +1372,7 @@ class btree { assert(cur->numElements < node::maxKeys && "Split required!"); // move keys - for (int j = static_cast(cur->numElements); j > static_cast(idx); --j) { + for (int j = cur->numElements; j > idx; --j) { cur->keys[j] = cur->keys[j - 1]; } @@ -1961,7 +1960,7 @@ class btree { const int N = node::maxKeys; // divide range in N+1 sub-ranges - int64_t length = (b - a) + 1; + int length = (b - a) + 1; // terminal case: length is less then maxKeys if (length <= N) { @@ -1978,7 +1977,7 @@ class btree { // recursive case - compute step size int numKeys = N; - int64_t step = ((length - numKeys) / (numKeys + 1)); + int step = ((length - numKeys) / (numKeys + 1)); while (numKeys > 1 && (step < N / 2)) { numKeys--; diff --git a/cbits/souffle/datastructure/BTreeDelete.h b/cbits/souffle/datastructure/BTreeDelete.h index be970ad..3f9391b 100644 --- a/cbits/souffle/datastructure/BTreeDelete.h +++ b/cbits/souffle/datastructure/BTreeDelete.h @@ -904,10 +904,8 @@ class btree_delete { /** * The iterator type to be utilized for scanning through btree instances. */ - class iterator { - friend class souffle::detail::btree_delete; - + class iterator : public std::iterator { + public: // a pointer to the node currently referred to // node const* cur; node* cur; @@ -915,7 +913,6 @@ class btree_delete { // the index of the element currently addressed within the referenced node field_index_type pos = 0; - public: using iterator_category = std::forward_iterator_tag; using value_type = Key; using difference_type = ptrdiff_t; @@ -1581,7 +1578,7 @@ class btree_delete { } else { auto lower_iter = internal_lower_bound(k); if (lower_iter != end() && equal(*lower_iter, k)) { - return std::distance(lower_iter, internal_upper_bound(k)); + return distance(lower_iter, internal_upper_bound(k)); } else { return 0; } @@ -1608,7 +1605,7 @@ class btree_delete { } else { iterator lower_iter = internal_lower_bound(k); if (lower_iter != end() && equal(*lower_iter, k)) { - size_type count = std::distance(lower_iter, internal_upper_bound(k)); + size_type count = distance(lower_iter, internal_upper_bound(k)); for (size_type i = 0; i < count; i++) { erase(lower_iter); } diff --git a/cbits/souffle/datastructure/Brie.h b/cbits/souffle/datastructure/Brie.h index dbf579d..d01cf67 100644 --- a/cbits/souffle/datastructure/Brie.h +++ b/cbits/souffle/datastructure/Brie.h @@ -1612,7 +1612,7 @@ class SparseBitMapIter { /** * A sparse bit-map is a bit map virtually assigning a bit value to every value if the - * uint64_t domain. However, only 1-bits are stored utilizing a nested sparse array + * uint32_t domain. However, only 1-bits are stored utilizing a nested sparse array * structure. * * @tparam BITS similar to the BITS parameter of the sparse array type @@ -1640,7 +1640,7 @@ class SparseBitMap { // some constants for manipulating stored values static constexpr std::size_t BITS_PER_ENTRY = sizeof(value_t) * CHAR_BIT; - static constexpr std::size_t LEAF_INDEX_WIDTH = __builtin_ctz(static_cast(BITS_PER_ENTRY)); + static constexpr std::size_t LEAF_INDEX_WIDTH = __builtin_ctz(BITS_PER_ENTRY); static constexpr uint64_t LEAF_INDEX_MASK = BITS_PER_ENTRY - 1; static uint64_t toMask(const value_t& value) { @@ -1936,8 +1936,8 @@ class TrieIterator { // remove ref-qual (if any); this can happen if we're a iterator-view using iter_core_arg_type = typename std::remove_reference_t::store_iter; - Value value = {}; // the value currently pointed to - IterCore iter_core = {}; // the wrapped iterator + Value value; // the value currently pointed to + IterCore iter_core; // the wrapped iterator // return an ephemeral nested iterator-view (view -> mutating us mutates our parent) // NB: be careful that the lifetime of this iterator-view doesn't exceed that of its parent. @@ -2887,9 +2887,9 @@ class Trie : public TrieBase> { if (this->empty()) return res; // use top-level elements for partitioning - size_t step = std::max(store.size() / chunks, std::size_t(1)); + int step = std::max(store.size() / chunks, std::size_t(1)); - size_t c = 1; + int c = 1; auto priv = begin(); for (auto it = store.begin(); it != store.end(); ++it, c++) { if (c % step != 0 || c == 1) { diff --git a/cbits/souffle/datastructure/ConcurrentInsertOnlyHashMap.h b/cbits/souffle/datastructure/ConcurrentInsertOnlyHashMap.h index d9f0746..0f3d274 100644 --- a/cbits/souffle/datastructure/ConcurrentInsertOnlyHashMap.h +++ b/cbits/souffle/datastructure/ConcurrentInsertOnlyHashMap.h @@ -46,7 +46,7 @@ static uint64_t GreaterOrEqualPrime(const uint64_t LowerBound) { for (std::size_t I = 0; I < ToPrime.size(); ++I) { const uint64_t N = ToPrime[I].first; const uint64_t K = ToPrime[I].second; - const uint64_t Prime = (1ULL << N) - K; + const uint64_t Prime = (1UL << N) - K; if (Prime >= LowerBound) { return Prime; } @@ -145,7 +145,7 @@ class ConcurrentInsertOnlyHashMap { } LoadFactor = 1.0; Buckets = std::make_unique[]>(BucketCount); - MaxSizeBeforeGrow = static_cast(std::ceil(LoadFactor * (double)BucketCount)); + MaxSizeBeforeGrow = std::ceil(LoadFactor * (double)BucketCount); } ConcurrentInsertOnlyHashMap(const Hash& hash = Hash(), const KeyEqual& key_equal = KeyEqual(), @@ -412,14 +412,12 @@ class ConcurrentInsertOnlyHashMap { // Chose a prime number of buckets that ensures the desired load factor // given the current number of elements in the map. const std::size_t CurrentSize = Size; - assert(LoadFactor > 0); - const std::size_t NeededBucketCount = - static_cast(std::ceil(static_cast(CurrentSize) / LoadFactor)); + const std::size_t NeededBucketCount = std::ceil((double)CurrentSize / LoadFactor); std::size_t NewBucketCount = NeededBucketCount; for (std::size_t I = 0; I < details::ToPrime.size(); ++I) { const uint64_t N = details::ToPrime[I].first; const uint64_t K = details::ToPrime[I].second; - const uint64_t Prime = (1ULL << N) - K; + const uint64_t Prime = (1UL << N) - K; if (Prime >= NeededBucketCount) { NewBucketCount = Prime; break; @@ -453,8 +451,7 @@ class ConcurrentInsertOnlyHashMap { Buckets = std::move(NewBuckets); BucketCount = NewBucketCount; - MaxSizeBeforeGrow = - static_cast(std::ceil(static_cast(NewBucketCount) * LoadFactor)); + MaxSizeBeforeGrow = ((double)NewBucketCount * LoadFactor); } Lanes.beforeUnlockAllBut(H); diff --git a/cbits/souffle/datastructure/EquivalenceRelation.h b/cbits/souffle/datastructure/EquivalenceRelation.h index aebc569..c22f9c2 100644 --- a/cbits/souffle/datastructure/EquivalenceRelation.h +++ b/cbits/souffle/datastructure/EquivalenceRelation.h @@ -114,10 +114,14 @@ class EquivalenceRelation { other.genAllDisjointSetLists(); // iterate over partitions at a time - for (auto&& [rep, pl] : other.equivalencePartition) { - const std::size_t ksize = pl->size(); - for (std::size_t i = 0; i < ksize; ++i) { - this->sds.unionNodes(rep, pl->get(i)); + for (typename StatesMap::chunk it : other.equivalencePartition.getChunks(MAX_THREADS)) { + for (auto& p : it) { + value_type rep = p.first; + StatesList& pl = *p.second; + const std::size_t ksize = pl.size(); + for (std::size_t i = 0; i < ksize; ++i) { + this->sds.unionNodes(rep, pl.get(i)); + } } } // invalidate iterators unconditionally diff --git a/cbits/souffle/datastructure/LambdaBTree.h b/cbits/souffle/datastructure/LambdaBTree.h index 8f7180c..da51a1c 100644 --- a/cbits/souffle/datastructure/LambdaBTree.h +++ b/cbits/souffle/datastructure/LambdaBTree.h @@ -313,8 +313,8 @@ class LambdaBTree : public btreeroot; - idx -= cur->rebalance_or_split(const_cast(&this->root), - this->root_lock, static_cast(idx), parents); + idx -= cur->rebalance_or_split( + const_cast(&this->root), this->root_lock, idx, parents); // release parent lock for (auto it = parents.rbegin(); it != parents.rend(); ++it) { @@ -346,7 +346,7 @@ class LambdaBTree : public btreenumElements < parenttype::node::maxKeys && "Split required!"); // move keys - for (int j = static_cast(cur->numElements); j > idx; --j) { + for (int j = cur->numElements; j > idx; --j) { cur->keys[j] = cur->keys[j - 1]; } @@ -444,8 +444,8 @@ class LambdaBTree : public btreenumElements >= parenttype::node::maxKeys) { // split this node - idx -= cur->rebalance_or_split(const_cast(&this->root), - this->root_lock, static_cast(idx)); + idx -= cur->rebalance_or_split( + const_cast(&this->root), this->root_lock, idx); // insert element in right fragment if (((typename parenttype::size_type)idx) > cur->numElements) { diff --git a/cbits/souffle/datastructure/PiggyList.h b/cbits/souffle/datastructure/PiggyList.h index 91efd5b..3d8d2f1 100644 --- a/cbits/souffle/datastructure/PiggyList.h +++ b/cbits/souffle/datastructure/PiggyList.h @@ -9,14 +9,18 @@ #include #ifdef _WIN32 -#include /** * Some versions of MSVC do not provide a builtin for counting leading zeroes * like gcc, so we have to implement it ourselves. */ #if defined(_MSC_VER) -int __inline __builtin_clzll(unsigned long long value) { - return static_cast(__lzcnt64(value)); +unsigned long __inline __builtin_clzll(unsigned long long value) { + unsigned long msb = 0; + + if (_BitScanReverse64(&msb, value)) + return 63 - msb; + else + return 64; } #endif // _MSC_VER #endif // _WIN32 @@ -108,7 +112,7 @@ class RandomInsertPiggyList { numElements.store(0); } const std::size_t BLOCKBITS = 16ul; - const std::size_t INITIALBLOCKSIZE = (((std::size_t)1ul) << BLOCKBITS); + const std::size_t INITIALBLOCKSIZE = (1ul << BLOCKBITS); // number of elements currently stored within std::atomic numElements{0}; @@ -248,17 +252,11 @@ class PiggyList { container_size = 0; } - class iterator { + class iterator : std::iterator { std::size_t cIndex = 0; PiggyList* bl; public: - using iterator_category = std::forward_iterator_tag; - using value_type = T; - using difference_type = void; - using pointer = T*; - using reference = T&; - // default ctor, to silence iterator() = default; @@ -301,7 +299,7 @@ class PiggyList { return iterator(this, size()); } const std::size_t BLOCKBITS = 16ul; - const std::size_t BLOCKSIZE = (((std::size_t)1ul) << BLOCKBITS); + const std::size_t BLOCKSIZE = (1ul << BLOCKBITS); // number of inserted std::atomic num_containers = 0; diff --git a/cbits/souffle/datastructure/RecordTableImpl.h b/cbits/souffle/datastructure/RecordTableImpl.h deleted file mode 100644 index 2e7b965..0000000 --- a/cbits/souffle/datastructure/RecordTableImpl.h +++ /dev/null @@ -1,599 +0,0 @@ -/* - * Souffle - A Datalog Compiler - * Copyright (c) 2022, The Souffle Developers. All rights reserved - * Licensed under the Universal Permissive License v 1.0 as shown at: - * - https://opensource.org/licenses/UPL - * - /licenses/SOUFFLE-UPL.txt - */ - -/** - * @file RecordTableImpl.h - * - * RecordTable definition - */ - -#pragma once - -#include "souffle/RamTypes.h" -#include "souffle/RecordTable.h" -#include "souffle/datastructure/ConcurrentFlyweight.h" -#include "souffle/utility/span.h" - -#include -#include -#include -#include -#include -#include - -namespace souffle { - -namespace details { - -// Helper to unroll for loop -template -constexpr void constexpr_for(F&& f) { - if constexpr (Start < End) { - f(std::integral_constant()); - constexpr_for(f); - } -} - -/// @brief The data-type of RamDomain records of any size. -using GenericRecord = std::vector; - -/// @brief The data-type of RamDomain records of specialized size. -template -using SpecializedRecord = std::array; - -/// @brief A view in a sequence of RamDomain value. -// TODO: use a `span`. -struct GenericRecordView { - explicit GenericRecordView(const RamDomain* Data, const std::size_t Arity) : Data(Data), Arity(Arity) {} - GenericRecordView(const GenericRecordView& Other) : Data(Other.Data), Arity(Other.Arity) {} - GenericRecordView(GenericRecordView&& Other) : Data(Other.Data), Arity(Other.Arity) {} - - const RamDomain* const Data; - const std::size_t Arity; - - const RamDomain* data() const { - return Data; - } - - const RamDomain& operator[](int I) const { - assert(I >= 0 && static_cast(I) < Arity); - return Data[I]; - } -}; - -template -struct SpecializedRecordView { - explicit SpecializedRecordView(const RamDomain* Data) : Data(Data) {} - SpecializedRecordView(const SpecializedRecordView& Other) : Data(Other.Data) {} - SpecializedRecordView(SpecializedRecordView&& Other) : Data(Other.Data) {} - - const RamDomain* const Data; - - const RamDomain* data() const { - return Data; - } - - const RamDomain& operator[](int I) const { - assert(I >= 0 && static_cast(I) < Arity); - return Data[I]; - } -}; - -/// @brief Hash function object for a RamDomain record. -struct GenericRecordHash { - explicit GenericRecordHash(const std::size_t Arity) : Arity(Arity) {} - GenericRecordHash(const GenericRecordHash& Other) : Arity(Other.Arity) {} - GenericRecordHash(GenericRecordHash&& Other) : Arity(Other.Arity) {} - - const std::size_t Arity; - std::hash domainHash; - - template - std::size_t operator()(const T& Record) const { - std::size_t Seed = 0; - for (std::size_t I = 0; I < Arity; ++I) { - Seed ^= domainHash(Record[(int)I]) + 0x9e3779b9U + (Seed << 6U) + (Seed >> 2U); - } - return Seed; - } -}; - -template -struct SpecializedRecordHash { - explicit SpecializedRecordHash() {} - SpecializedRecordHash(const SpecializedRecordHash& Other) : DomainHash(Other.DomainHash) {} - SpecializedRecordHash(SpecializedRecordHash&& Other) : DomainHash(Other.DomainHash) {} - - std::hash DomainHash; - - template - std::size_t operator()(const T& Record) const { - std::size_t Seed = 0; - constexpr_for<0, Arity, 1>([&](auto I) { - Seed ^= DomainHash(Record[(int)I]) + 0x9e3779b9U + (Seed << 6U) + (Seed >> 2U); - }); - return Seed; - } -}; - -template <> -struct SpecializedRecordHash<0> { - explicit SpecializedRecordHash() {} - SpecializedRecordHash(const SpecializedRecordHash&) {} - SpecializedRecordHash(SpecializedRecordHash&&) {} - - template - std::size_t operator()(const T&) const { - return 0; - } -}; - -/// @brief Equality function object for RamDomain records. -struct GenericRecordEqual { - explicit GenericRecordEqual(const std::size_t Arity) : Arity(Arity) {} - GenericRecordEqual(const GenericRecordEqual& Other) : Arity(Other.Arity) {} - GenericRecordEqual(GenericRecordEqual&& Other) : Arity(Other.Arity) {} - - const std::size_t Arity; - - template - bool operator()(const T& A, const U& B) const { - return (std::memcmp(A.data(), B.data(), Arity * sizeof(RamDomain)) == 0); - } -}; - -template -struct SpecializedRecordEqual { - explicit SpecializedRecordEqual() {} - SpecializedRecordEqual(const SpecializedRecordEqual&) {} - SpecializedRecordEqual(SpecializedRecordEqual&&) {} - - template - bool operator()(const T& A, const U& B) const { - constexpr std::size_t Len = Arity * sizeof(RamDomain); - return (std::memcmp(A.data(), B.data(), Len) == 0); - } -}; - -template <> -struct SpecializedRecordEqual<0> { - explicit SpecializedRecordEqual() {} - SpecializedRecordEqual(const SpecializedRecordEqual&) {} - SpecializedRecordEqual(SpecializedRecordEqual&&) {} - - template - bool operator()(const T&, const U&) const { - return true; - } -}; - -/// @brief Less function object for RamDomain records. -struct GenericRecordLess { - explicit GenericRecordLess(const std::size_t Arity) : Arity(Arity) {} - GenericRecordLess(const GenericRecordLess& Other) : Arity(Other.Arity) {} - GenericRecordLess(GenericRecordLess&& Other) : Arity(Other.Arity) {} - - const std::size_t Arity; - - template - bool operator()(const T& A, const U& B) const { - return (std::memcmp(A.data(), B.data(), Arity * sizeof(RamDomain)) < 0); - } -}; - -template -struct SpecializedRecordLess { - explicit SpecializedRecordLess() {} - SpecializedRecordLess(const SpecializedRecordLess&) {} - SpecializedRecordLess(SpecializedRecordLess&&) {} - - template - bool operator()(const T& A, const U& B) const { - constexpr std::size_t Len = Arity * sizeof(RamDomain); - return (std::memcmp(A.data(), B.data(), Len) < 0); - } -}; - -template <> -struct SpecializedRecordLess<0> { - explicit SpecializedRecordLess() {} - SpecializedRecordLess(const SpecializedRecordLess&) {} - SpecializedRecordLess(SpecializedRecordLess&&) {} - - template - bool operator()(const T&, const U&) const { - return false; - } -}; - -/// @brief Compare function object for RamDomain records. -struct GenericRecordCmp { - explicit GenericRecordCmp(const std::size_t Arity) : Arity(Arity) {} - GenericRecordCmp(const GenericRecordCmp& Other) : Arity(Other.Arity) {} - GenericRecordCmp(GenericRecordCmp&& Other) : Arity(Other.Arity) {} - - const std::size_t Arity; - - template - int operator()(const T& A, const U& B) const { - return std::memcmp(A.data(), B.data(), Arity * sizeof(RamDomain)); - } -}; - -template -struct SpecializedRecordCmp { - explicit SpecializedRecordCmp() {} - SpecializedRecordCmp(const SpecializedRecordCmp&) {} - SpecializedRecordCmp(SpecializedRecordCmp&&) {} - - template - bool operator()(const T& A, const U& B) const { - constexpr std::size_t Len = Arity * sizeof(RamDomain); - return std::memcmp(A.data(), B.data(), Len); - } -}; - -template <> -struct SpecializedRecordCmp<0> { - explicit SpecializedRecordCmp() {} - SpecializedRecordCmp(const SpecializedRecordCmp&) {} - SpecializedRecordCmp(SpecializedRecordCmp&&) {} - - template - bool operator()(const T&, const U&) const { - return 0; - } -}; - -/// @brief Factory of RamDomain record. -struct GenericRecordFactory { - using value_type = GenericRecord; - using pointer = GenericRecord*; - using reference = GenericRecord&; - - explicit GenericRecordFactory(const std::size_t Arity) : Arity(Arity) {} - GenericRecordFactory(const GenericRecordFactory& Other) : Arity(Other.Arity) {} - GenericRecordFactory(GenericRecordFactory&& Other) : Arity(Other.Arity) {} - - const std::size_t Arity; - - reference replace(reference Place, const std::vector& V) { - assert(V.size() == Arity); - Place = V; - return Place; - } - - reference replace(reference Place, const GenericRecordView& V) { - Place.clear(); - Place.insert(Place.begin(), V.data(), V.data() + Arity); - return Place; - } - - reference replace(reference Place, const RamDomain* V) { - Place.clear(); - Place.insert(Place.begin(), V, V + Arity); - return Place; - } -}; - -template -struct SpecializedRecordFactory { - using value_type = SpecializedRecord; - using pointer = SpecializedRecord*; - using reference = SpecializedRecord&; - - explicit SpecializedRecordFactory() {} - SpecializedRecordFactory(const SpecializedRecordFactory&) {} - SpecializedRecordFactory(SpecializedRecordFactory&&) {} - - reference replace(reference Place, const SpecializedRecord& V) { - assert(V.size() == Arity); - Place = V; - return Place; - } - - reference replace(reference Place, const SpecializedRecordView& V) { - constexpr std::size_t Len = Arity * sizeof(RamDomain); - std::memcpy(Place.data(), V.data(), Len); - return Place; - } - - reference replace(reference Place, const RamDomain* V) { - constexpr std::size_t Len = Arity * sizeof(RamDomain); - std::memcpy(Place.data(), V, Len); - return Place; - } -}; - -template <> -struct SpecializedRecordFactory<0> { - using value_type = SpecializedRecord<0>; - using pointer = SpecializedRecord<0>*; - using reference = SpecializedRecord<0>&; - - explicit SpecializedRecordFactory() {} - SpecializedRecordFactory(const SpecializedRecordFactory&) {} - SpecializedRecordFactory(SpecializedRecordFactory&&) {} - - reference replace(reference Place, const SpecializedRecord<0>&) { - return Place; - } - - reference replace(reference Place, const SpecializedRecordView<0>&) { - return Place; - } - - reference replace(reference Place, const RamDomain*) { - return Place; - } -}; - -} // namespace details - -/** @brief Interface of bidirectional mappping between records and record references. */ -class RecordMap { -public: - virtual ~RecordMap() {} - virtual void setNumLanes(const std::size_t NumLanes) = 0; - virtual RamDomain pack(const std::vector& Vector) = 0; - virtual RamDomain pack(const RamDomain* Tuple) = 0; - virtual RamDomain pack(const std::initializer_list& List) = 0; - virtual const RamDomain* unpack(RamDomain index) const = 0; -}; - -/** @brief Bidirectional mappping between records and record references, for any record arity. */ -class GenericRecordMap : public RecordMap, - protected FlyweightImpl { - using Base = FlyweightImpl; - - const std::size_t Arity; - -public: - explicit GenericRecordMap(const std::size_t lane_count, const std::size_t arity) - : Base(lane_count, 8, true, details::GenericRecordHash(arity), details::GenericRecordEqual(arity), - details::GenericRecordFactory(arity)), - Arity(arity) {} - - virtual ~GenericRecordMap() {} - - void setNumLanes(const std::size_t NumLanes) override { - Base::setNumLanes(NumLanes); - } - - /** @brief converts record to a record reference */ - RamDomain pack(const std::vector& Vector) override { - return findOrInsert(Vector).first; - }; - - /** @brief converts record to a record reference */ - RamDomain pack(const RamDomain* Tuple) override { - details::GenericRecordView View{Tuple, Arity}; - return findOrInsert(View).first; - } - - /** @brief converts record to a record reference */ - RamDomain pack(const std::initializer_list& List) override { - details::GenericRecordView View{std::data(List), Arity}; - return findOrInsert(View).first; - } - - /** @brief convert record reference to a record pointer */ - const RamDomain* unpack(RamDomain Index) const override { - return fetch(Index).data(); - } -}; - -/** @brief Bidirectional mappping between records and record references, specialized for a record arity. */ -template -class SpecializedRecordMap - : public RecordMap, - protected FlyweightImpl, details::SpecializedRecordHash, - details::SpecializedRecordEqual, details::SpecializedRecordFactory> { - using Record = details::SpecializedRecord; - using RecordView = details::SpecializedRecordView; - using RecordHash = details::SpecializedRecordHash; - using RecordEqual = details::SpecializedRecordEqual; - using RecordFactory = details::SpecializedRecordFactory; - using Base = FlyweightImpl; - -public: - SpecializedRecordMap(const std::size_t LaneCount) - : Base(LaneCount, 8, true, RecordHash(), RecordEqual(), RecordFactory()) {} - - virtual ~SpecializedRecordMap() {} - - void setNumLanes(const std::size_t NumLanes) override { - Base::setNumLanes(NumLanes); - } - - /** @brief converts record to a record reference */ - RamDomain pack(const std::vector& Vector) override { - assert(Vector.size() == Arity); - RecordView View{Vector.data()}; - return Base::findOrInsert(View).first; - }; - - /** @brief converts record to a record reference */ - RamDomain pack(const RamDomain* Tuple) override { - RecordView View{Tuple}; - return Base::findOrInsert(View).first; - } - - /** @brief converts record to a record reference */ - RamDomain pack(const std::initializer_list& List) override { - assert(List.size() == Arity); - RecordView View{std::data(List)}; - return Base::findOrInsert(View).first; - } - - /** @brief convert record reference to a record pointer */ - const RamDomain* unpack(RamDomain Index) const override { - return Base::fetch(Index).data(); - } -}; - -/** Record map specialized for arity 0 */ -template <> -class SpecializedRecordMap<0> : public RecordMap { - // The empty record always at index 1 - // The index 0 of each map is reserved. - static constexpr RamDomain EmptyRecordIndex = 1; - - // To comply with previous behavior, the empty record - // has no data: - const RamDomain* EmptyRecordData = nullptr; - -public: - SpecializedRecordMap(const std::size_t /* LaneCount */) {} - - virtual ~SpecializedRecordMap() {} - - void setNumLanes(const std::size_t) override {} - - /** @brief converts record to a record reference */ - RamDomain pack([[maybe_unused]] const std::vector& Vector) override { - assert(Vector.size() == 0); - return EmptyRecordIndex; - }; - - /** @brief converts record to a record reference */ - RamDomain pack(const RamDomain*) override { - return EmptyRecordIndex; - } - - /** @brief converts record to a record reference */ - RamDomain pack([[maybe_unused]] const std::initializer_list& List) override { - assert(List.size() == 0); - return EmptyRecordIndex; - } - - /** @brief convert record reference to a record pointer */ - const RamDomain* unpack([[maybe_unused]] RamDomain Index) const override { - assert(Index == EmptyRecordIndex); - return EmptyRecordData; - } -}; - -/** A concurrent Record Table with some specialized record maps. */ -template -class SpecializedRecordTable : public RecordTable { -private: - // The current size of the Maps vector. - std::size_t Size; - - // The record maps, indexed by arity. - std::vector Maps; - - // The concurrency manager. - mutable ConcurrentLanes Lanes; - - template - void CreateSpecializedMaps() { - if (Arity >= Size) { - Size = Arity + 1; - Maps.reserve(Size); - Maps.resize(Size); - } - Maps[Arity] = new SpecializedRecordMap(Lanes.lanes()); - if constexpr (sizeof...(Arities) > 0) { - CreateSpecializedMaps(); - } - } - -public: - /** @brief Construct a record table with the number of concurrent access lanes. */ - SpecializedRecordTable(const std::size_t LaneCount) : Size(0), Lanes(LaneCount) { - CreateSpecializedMaps(); - } - - SpecializedRecordTable() : SpecializedRecordTable(1) {} - - virtual ~SpecializedRecordTable() { - for (auto Map : Maps) { - delete Map; - } - } - - /** - * @brief set the number of concurrent access lanes. - * Not thread-safe, use only when the datastructure is not being used. - */ - virtual void setNumLanes(const std::size_t NumLanes) override { - Lanes.setNumLanes(NumLanes); - for (auto& Map : Maps) { - if (Map) { - Map->setNumLanes(NumLanes); - } - } - } - - /** @brief convert tuple to record reference */ - virtual RamDomain pack(const RamDomain* Tuple, const std::size_t Arity) override { - auto Guard = Lanes.guard(); - return lookupMap(Arity).pack(Tuple); - } - - /** @brief convert tuple to record reference */ - virtual RamDomain pack(const std::initializer_list& List) override { - auto Guard = Lanes.guard(); - return lookupMap(List.size()).pack(std::data(List)); - } - - /** @brief convert record reference to a record */ - virtual const RamDomain* unpack(const RamDomain Ref, const std::size_t Arity) const override { - auto Guard = Lanes.guard(); - return lookupMap(Arity).unpack(Ref); - } - -private: - /** @brief lookup RecordMap for a given arity; the map for that arity must exist. */ - RecordMap& lookupMap(const std::size_t Arity) const { - assert(Arity < Size && "Lookup for an arity while there is no record for that arity."); - auto* Map = Maps[Arity]; - assert(Map != nullptr && "Lookup for an arity while there is no record for that arity."); - return *Map; - } - - /** @brief lookup RecordMap for a given arity; if it does not exist, create new RecordMap */ - RecordMap& lookupMap(const std::size_t Arity) { - if (Arity < Size) { - auto* Map = Maps[Arity]; - if (Map) { - return *Map; - } - } - - createMap(Arity); - return *Maps[Arity]; - } - - /** @brief create the RecordMap for the given arity. */ - void createMap(const std::size_t Arity) { - Lanes.beforeLockAllBut(); - if (Arity < Size && Maps[Arity] != nullptr) { - // Map of required arity has been created concurrently - Lanes.beforeUnlockAllBut(); - return; - } - Lanes.lockAllBut(); - - if (Arity >= Size) { - Size = Arity + 1; - Maps.reserve(Size); - Maps.resize(Size); - } - Maps[Arity] = new GenericRecordMap(Lanes.lanes(), Arity); - - Lanes.beforeUnlockAllBut(); - Lanes.unlockAllBut(); - } -}; - -} // namespace souffle diff --git a/cbits/souffle/datastructure/SymbolTableImpl.h b/cbits/souffle/datastructure/SymbolTableImpl.h deleted file mode 100644 index e618c28..0000000 --- a/cbits/souffle/datastructure/SymbolTableImpl.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Souffle - A Datalog Compiler - * Copyright (c) 2022, The Souffle Developers. All rights reserved - * Licensed under the Universal Permissive License v 1.0 as shown at: - * - https://opensource.org/licenses/UPL - * - /licenses/SOUFFLE-UPL.txt - */ - -/** - * @file SymbolTableImpl.h - * - * SymbolTable definition - */ - -#pragma once - -#include "souffle/SymbolTable.h" -#include "souffle/datastructure/ConcurrentFlyweight.h" -#include "souffle/utility/MiscUtil.h" -#include "souffle/utility/ParallelUtil.h" -#include "souffle/utility/StreamUtil.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace souffle { - -/** - * @class SymbolTableImpl - * - * Implementation of the symbol table. - */ -class SymbolTableImpl : public SymbolTable, protected FlyweightImpl { -private: - using Base = FlyweightImpl; - -public: - class IteratorImpl : public SymbolTableIteratorInterface, private Base::iterator { - public: - IteratorImpl(Base::iterator&& it) : Base::iterator(it) {} - - IteratorImpl(const Base::iterator& it) : Base::iterator(it) {} - - const std::pair& get() const { - return **this; - } - - bool equals(const SymbolTableIteratorInterface& other) { - return (*this) == static_cast(other); - } - - SymbolTableIteratorInterface& incr() { - ++(*this); - return *this; - } - - std::unique_ptr copy() const { - return std::make_unique(*this); - } - }; - - using iterator = SymbolTable::Iterator; - - /** @brief Construct a symbol table with the given number of concurrent access lanes. */ - SymbolTableImpl(const std::size_t LaneCount = 1) : Base(LaneCount) {} - - /** @brief Construct a symbol table with the given initial symbols. */ - SymbolTableImpl(std::initializer_list symbols) : Base(1, symbols.size()) { - for (const auto& symbol : symbols) { - findOrInsert(symbol); - } - } - - /** @brief Construct a symbol table with the given number of concurrent access lanes and initial symbols. - */ - SymbolTableImpl(const std::size_t LaneCount, std::initializer_list symbols) - : Base(LaneCount, symbols.size()) { - for (const auto& symbol : symbols) { - findOrInsert(symbol); - } - } - - /** - * @brief Set the number of concurrent access lanes. - * This function is not thread-safe, do not call when other threads are using the datastructure. - */ - void setNumLanes(const std::size_t NumLanes) { - Base::setNumLanes(NumLanes); - } - - iterator begin() const override { - return SymbolTable::Iterator(std::make_unique(Base::begin())); - } - - iterator end() const override { - return SymbolTable::Iterator(std::make_unique(Base::end())); - } - - bool weakContains(const std::string& symbol) const override { - return Base::weakContains(symbol); - } - - RamDomain encode(const std::string& symbol) override { - return Base::findOrInsert(symbol).first; - } - - const std::string& decode(const RamDomain index) const override { - return Base::fetch(index); - } - - RamDomain unsafeEncode(const std::string& symbol) override { - return encode(symbol); - } - - const std::string& unsafeDecode(const RamDomain index) const override { - return decode(index); - } - - std::pair findOrInsert(const std::string& symbol) override { - auto Res = Base::findOrInsert(symbol); - return std::make_pair(static_cast(Res.first), Res.second); - } -}; - -} // namespace souffle diff --git a/cbits/souffle/datastructure/Table.h b/cbits/souffle/datastructure/Table.h index 9e299ad..08627d3 100644 --- a/cbits/souffle/datastructure/Table.h +++ b/cbits/souffle/datastructure/Table.h @@ -49,17 +49,11 @@ class Table { std::size_t count = 0; public: - class iterator { + class iterator : public std::iterator { Block* block; unsigned pos; public: - using iterator_category = std::forward_iterator_tag; - using value_type = T; - using difference_type = void; - using pointer = T*; - using reference = T&; - iterator(Block* block = nullptr, unsigned pos = 0) : block(block), pos(pos) {} iterator(const iterator&) = default; diff --git a/cbits/souffle/io/ReadStreamCSV.h b/cbits/souffle/io/ReadStreamCSV.h index 5d96b75..223879e 100644 --- a/cbits/souffle/io/ReadStreamCSV.h +++ b/cbits/souffle/io/ReadStreamCSV.h @@ -347,8 +347,8 @@ class ReadFileCSV : public ReadStreamCSV { */ static std::string getFileName(const std::map& rwOperation) { auto name = getOr(rwOperation, "filename", rwOperation.at("name") + ".facts"); - if (!isAbsolute(name)) { - name = getOr(rwOperation, "fact-dir", ".") + pathSeparator + name; + if (name.front() != '/') { + name = getOr(rwOperation, "fact-dir", ".") + "/" + name; } return name; } diff --git a/cbits/souffle/io/ReadStreamSQLite.h b/cbits/souffle/io/ReadStreamSQLite.h index e027d3c..0a09ed4 100644 --- a/cbits/souffle/io/ReadStreamSQLite.h +++ b/cbits/souffle/io/ReadStreamSQLite.h @@ -127,7 +127,6 @@ class ReadStreamSQLite : public ReadStream { } void openDB() { - sqlite3_config(SQLITE_CONFIG_URI, 1); if (sqlite3_open(dbFilename.c_str(), &db) != SQLITE_OK) { throwError("SQLite error in sqlite3_open: "); } @@ -172,10 +171,6 @@ class ReadStreamSQLite : public ReadStream { auto name = getOr(rwOperation, "dbname", rwOperation.at("name") + ".sqlite"); name = getOr(rwOperation, "filename", name); - if (name.rfind("file:", 0) == 0 || name.rfind(":memory:", 0) == 0) { - return name; - } - if (name.front() != '/') { name = getOr(rwOperation, "fact-dir", ".") + "/" + name; } diff --git a/cbits/souffle/io/WriteStreamSQLite.h b/cbits/souffle/io/WriteStreamSQLite.h index 240b6da..5aca796 100644 --- a/cbits/souffle/io/WriteStreamSQLite.h +++ b/cbits/souffle/io/WriteStreamSQLite.h @@ -65,11 +65,9 @@ class WriteStreamSQLite : public WriteStream { } #if RAM_DOMAIN_SIZE == 64 - if (sqlite3_bind_int64(insertStatement, static_cast(i + 1), - static_cast(value)) != SQLITE_OK) { + if (sqlite3_bind_int64(insertStatement, i + 1, value) != SQLITE_OK) { #else - if (sqlite3_bind_int(insertStatement, static_cast(i + 1), static_cast(value)) != - SQLITE_OK) { + if (sqlite3_bind_int(insertStatement, i + 1, value) != SQLITE_OK) { #endif throwError("SQLite error in sqlite3_bind_text: "); } @@ -104,7 +102,7 @@ class WriteStreamSQLite : public WriteStream { throw std::invalid_argument(error.str()); } - uint64_t getSymbolTableIDFromDB(std::size_t index) { + uint64_t getSymbolTableIDFromDB(int index) { if (sqlite3_bind_text(symbolSelectStatement, 1, symbolTable.decode(index).c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK) { throwError("SQLite error in sqlite3_bind_text: "); @@ -117,7 +115,7 @@ class WriteStreamSQLite : public WriteStream { sqlite3_reset(symbolSelectStatement); return rowid; } - uint64_t getSymbolTableID(std::size_t index) { + uint64_t getSymbolTableID(int index) { if (dbSymbolTable.count(index) != 0) { return dbSymbolTable[index]; } @@ -142,9 +140,8 @@ class WriteStreamSQLite : public WriteStream { } void openDB() { - sqlite3_config(SQLITE_CONFIG_URI, 1); if (sqlite3_open(dbFilename.c_str(), &db) != SQLITE_OK) { - throwError("SQLite error in sqlite3_open: "); + throwError("SQLite error in sqlite3_open"); } sqlite3_extended_result_codes(db, 1); executeSQL("PRAGMA synchronous = OFF", db); @@ -273,10 +270,6 @@ class WriteStreamSQLite : public WriteStream { auto name = getOr(rwOperation, "dbname", rwOperation.at("name") + ".sqlite"); name = getOr(rwOperation, "filename", name); - if (name.rfind("file:", 0) == 0 || name.rfind(":memory:", 0) == 0) { - return name; - } - if (name.front() != '/') { name = getOr(rwOperation, "output-dir", ".") + "/" + name; } diff --git a/cbits/souffle/io/gzfstream.h b/cbits/souffle/io/gzfstream.h index bfa42a8..f7ec488 100644 --- a/cbits/souffle/io/gzfstream.h +++ b/cbits/souffle/io/gzfstream.h @@ -91,8 +91,8 @@ class gzfstreambuf : public std::streambuf { *pptr() = c; pbump(1); } - const int toWrite = static_cast(pptr() - pbase()); - if (gzwrite(fileHandle, pbase(), static_cast(toWrite)) != toWrite) { + int toWrite = pptr() - pbase(); + if (gzwrite(fileHandle, pbase(), toWrite) != toWrite) { return EOF; } pbump(-toWrite); @@ -108,14 +108,13 @@ class gzfstreambuf : public std::streambuf { return traits_type::to_int_type(*gptr()); } - std::size_t charsPutBack = gptr() - eback(); + unsigned charsPutBack = gptr() - eback(); if (charsPutBack > reserveSize) { charsPutBack = reserveSize; } memcpy(buffer + reserveSize - charsPutBack, gptr() - charsPutBack, charsPutBack); - int charsRead = - gzread(fileHandle, buffer + reserveSize, static_cast(bufferSize - reserveSize)); + int charsRead = gzread(fileHandle, buffer + reserveSize, bufferSize - reserveSize); if (charsRead <= 0) { return EOF; } @@ -127,8 +126,8 @@ class gzfstreambuf : public std::streambuf { int sync() override { if ((pptr() != nullptr) && pptr() > pbase()) { - const int toWrite = static_cast(pptr() - pbase()); - if (gzwrite(fileHandle, pbase(), static_cast(toWrite)) != toWrite) { + int toWrite = pptr() - pbase(); + if (gzwrite(fileHandle, pbase(), toWrite) != toWrite) { return -1; } pbump(-toWrite); @@ -137,8 +136,8 @@ class gzfstreambuf : public std::streambuf { } private: - static constexpr std::size_t bufferSize = 65536; - static constexpr std::size_t reserveSize = 16; + static constexpr unsigned int bufferSize = 65536; + static constexpr unsigned int reserveSize = 16; char buffer[bufferSize] = {}; gzFile fileHandle = {}; diff --git a/cbits/souffle/utility/ContainerUtil.h b/cbits/souffle/utility/ContainerUtil.h index 6e250db..e08d99c 100644 --- a/cbits/souffle/utility/ContainerUtil.h +++ b/cbits/souffle/utility/ContainerUtil.h @@ -219,20 +219,6 @@ bool equal_targets(const Container>& a, const Container>& b) { return equal_targets(a, b, comp_deref>()); } -#ifdef _MSC_VER -// issue: -// https://developercommunity.visualstudio.com/t/c-template-template-not-recognized-as-class-templa/558979 -template -bool equal_targets(const std::vector>& a, const std::vector>& b) { - return equal_targets(a, b, comp_deref>()); -} - -template -bool equal_targets(const std::vector& a, const std::vector& b) { - return equal_targets(a, b, comp_deref()); -} -#endif - /** * A function testing whether two maps of unique pointers are referencing to equivalent * targets. diff --git a/cbits/souffle/utility/EvaluatorUtil.h b/cbits/souffle/utility/EvaluatorUtil.h index 7d21a9f..7309e47 100644 --- a/cbits/souffle/utility/EvaluatorUtil.h +++ b/cbits/souffle/utility/EvaluatorUtil.h @@ -24,7 +24,7 @@ namespace souffle::evaluator { template -> void */> -void runRange(const A from, const A to, const A step, F&& go) { +void runRange(A from, A to, A step, F&& go) { #define GO(x) go(Tuple{ramBitCast(x)}) if (0 < step) { for (auto x = from; x < to; x += step) { @@ -42,26 +42,8 @@ void runRange(const A from, const A to, const A step, F&& go) { } template -> void */> -void runRangeBackward(const A from, const A to, F&& func) { - assert(from > to); - if (from > to) { - for (auto x = from; x > to; --x) { - func(Tuple{ramBitCast(x)}); - } - } -} - -template -> void */> -void runRange(const A from, const A to, F&& go) { - if constexpr (std::is_unsigned()) { - if (from <= to) { - runRange(from, to, static_cast(1U), std::forward(go)); - } else { - runRangeBackward(from, to, std::forward(go)); - } - } else { - return runRange(from, to, A(from <= to ? 1 : -1), std::forward(go)); - } +void runRange(A from, A to, F&& go) { + return runRange(from, to, A(from <= to ? 1 : -1), std::forward(go)); } template diff --git a/cbits/souffle/utility/FileUtil.h b/cbits/souffle/utility/FileUtil.h index fbb3497..df7e9c6 100644 --- a/cbits/souffle/utility/FileUtil.h +++ b/cbits/souffle/utility/FileUtil.h @@ -16,39 +16,36 @@ #pragma once -#include #include #include #include -#include #include -#include -#include #include #include #include #include -// ------------------------------------------------------------------------------- -// File Utils -// ------------------------------------------------------------------------------- - #ifndef _WIN32 #include #else -#define NOMINMAX -#define NOGDI #include #include #include #include // ------------------------------------------------------------------------------- -// Windows +// File Utils // ------------------------------------------------------------------------------- +#define X_OK 1 /* execute permission - unsupported in windows*/ + #define PATH_MAX 260 +/** + * access and realpath are missing on windows, we use their windows equivalents + * as work-arounds. + */ +#define access _access inline char* realpath(const char* path, char* resolved_path) { return _fullpath(resolved_path, path, PATH_MAX); } @@ -60,52 +57,19 @@ inline char* realpath(const char* path, char* resolved_path) { #define pclose _pclose #endif -// ------------------------------------------------------------------------------- -// All systems -// ------------------------------------------------------------------------------- - namespace souffle { -// The separator in the PATH variable -#ifdef _MSC_VER -const char PATHdelimiter = ';'; -const char pathSeparator = '/'; -#else -const char PATHdelimiter = ':'; -const char pathSeparator = '/'; -#endif - -inline std::string& makePreferred(std::string& name) { - std::replace(name.begin(), name.end(), '\\', '/'); - // std::replace(name.begin(), name.end(), '/', pathSeparator); - return name; -} - -inline bool isAbsolute(const std::string& path) { - std::filesystem::path P(path); - return P.is_absolute(); -} - /** * Check whether a file exists in the file system */ inline bool existFile(const std::string& name) { - static std::map existFileCache{}; - auto it = existFileCache.find(name); - if (it != existFileCache.end()) { - return it->second; - } - std::filesystem::path P(name); - bool result = std::filesystem::exists(P); - /*bool result = false; struct stat buffer = {}; - if (stat(P.native().c_str(), &buffer) == 0) { + if (stat(name.c_str(), &buffer) == 0) { if ((buffer.st_mode & S_IFMT) != 0) { - result = true; + return true; } - }*/ - existFileCache[name] = result; - return result; + } + return false; } /** @@ -124,24 +88,16 @@ inline bool existDir(const std::string& name) { /** * Check whether a given file exists and it is an executable */ -#ifdef _WIN32 -inline bool isExecutable(const std::string& name) { - return existFile( - name); // there is no EXECUTABLE bit on Windows, so theoretically any file may be executable -} -#else inline bool isExecutable(const std::string& name) { return existFile(name) && (access(name.c_str(), X_OK) == 0); } -#endif /** * Simple implementation of a which tool */ inline std::string which(const std::string& name) { // Check if name has path components in it and if so return it immediately - std::filesystem::path P(name); - if (P.has_parent_path()) { + if (name.find('/') != std::string::npos) { return name; } // Get PATH from environment, if it exists. @@ -155,8 +111,8 @@ inline std::string which(const std::string& name) { std::string sub; // Check for existence of a binary called 'name' in PATH - while (std::getline(sstr, sub, PATHdelimiter)) { - std::string path = sub + pathSeparator + name; + while (std::getline(sstr, sub, ':')) { + std::string path = sub + "/" + name; if ((::realpath(path.c_str(), buf) != nullptr) && isExecutable(path) && !existDir(path)) { return buf; } @@ -171,27 +127,19 @@ inline std::string dirName(const std::string& name) { if (name.empty()) { return "."; } - - std::filesystem::path P(name); - if (P.has_parent_path()) { - return P.parent_path().string(); - } else { - return "."; - } - - std::size_t lastNotSlash = name.find_last_not_of(pathSeparator); + std::size_t lastNotSlash = name.find_last_not_of('/'); // All '/' if (lastNotSlash == std::string::npos) { return "/"; } - std::size_t leadingSlash = name.find_last_of(pathSeparator, lastNotSlash); + std::size_t leadingSlash = name.find_last_of('/', lastNotSlash); // No '/' if (leadingSlash == std::string::npos) { return "."; } // dirname is '/' if (leadingSlash == 0) { - return std::string(1, pathSeparator); + return "/"; } return name.substr(0, leadingSlash); } @@ -209,17 +157,15 @@ inline std::string absPath(const std::string& path) { * Join two paths together; note that this does not resolve overlaps or relative paths. */ inline std::string pathJoin(const std::string& first, const std::string& second) { - return (std::filesystem::path(first) / std::filesystem::path(second)).string(); - - /*unsigned firstPos = static_cast(first.size()) - 1; - while (first.at(firstPos) == pathSeparator) { + unsigned firstPos = static_cast(first.size()) - 1; + while (first.at(firstPos) == '/') { firstPos--; } unsigned secondPos = 0; - while (second.at(secondPos) == pathSeparator) { + while (second.at(secondPos) == '/') { secondPos++; } - return first.substr(0, firstPos + 1) + pathSeparator + second.substr(secondPos);*/ + return first.substr(0, firstPos + 1) + '/' + second.substr(secondPos); } /* @@ -227,19 +173,18 @@ inline std::string pathJoin(const std::string& first, const std::string& second) * relative to the directory given by @ base. A path here refers a * colon-separated list of directories. */ -inline std::optional findTool( - const std::string& tool, const std::string& base, const std::string& path) { - std::filesystem::path dir(dirName(base)); +inline std::string findTool(const std::string& tool, const std::string& base, const std::string& path) { + std::string dir = dirName(base); std::stringstream sstr(path); std::string sub; while (std::getline(sstr, sub, ':')) { - auto subpath = (dir / sub / tool); - if (std::filesystem::exists(subpath)) { - return absPath(subpath.string()); + std::string subpath = dir + "/" + sub + '/' + tool; + if (isExecutable(subpath)) { + return absPath(subpath); } } - return {}; + return ""; } /* @@ -250,12 +195,12 @@ inline std::string baseName(const std::string& filename) { return "."; } - std::size_t lastNotSlash = filename.find_last_not_of(pathSeparator); + std::size_t lastNotSlash = filename.find_last_not_of('/'); if (lastNotSlash == std::string::npos) { - return std::string(1, pathSeparator); + return "/"; } - std::size_t lastSlashBeforeBasename = filename.find_last_of(pathSeparator, lastNotSlash - 1); + std::size_t lastSlashBeforeBasename = filename.find_last_of('/', lastNotSlash - 1); if (lastSlashBeforeBasename == std::string::npos) { lastSlashBeforeBasename = static_cast(-1); } @@ -272,7 +217,7 @@ inline std::string simpleName(const std::string& path) { if (lastDot == std::string::npos) { return name; } - const std::size_t lastSlash = name.find_last_of(pathSeparator); + const std::size_t lastSlash = name.find_last_of('/'); // last slash occurs after last dot, so no extension if (lastSlash != std::string::npos && lastSlash > lastDot) { return name; @@ -291,7 +236,7 @@ inline std::string fileExtension(const std::string& path) { if (lastDot == std::string::npos) { return std::string(); } - const std::size_t lastSlash = name.find_last_of(pathSeparator); + const std::size_t lastSlash = name.find_last_of('/'); // last slash occurs after last dot, so no extension if (lastSlash != std::string::npos && lastSlash > lastDot) { return std::string(); @@ -305,11 +250,10 @@ inline std::string fileExtension(const std::string& path) { */ inline std::string tempFile() { #ifdef _WIN32 - char ctempl[L_tmpnam]; std::string templ; std::FILE* f = nullptr; while (f == nullptr) { - templ = std::tmpnam(ctempl); + templ = std::tmpnam(nullptr); f = fopen(templ.c_str(), "wx"); } fclose(f); @@ -324,16 +268,13 @@ inline std::string tempFile() { inline std::stringstream execStdOut(char const* cmd) { FILE* in = popen(cmd, "r"); std::stringstream data; - - if (in == nullptr) { - return data; - } - - while (!feof(in)) { + while (in != nullptr) { int c = fgetc(in); + if (feof(in) != 0) { + break; + } data << static_cast(c); } - pclose(in); return data; } diff --git a/cbits/souffle/utility/Iteration.h b/cbits/souffle/utility/Iteration.h index 1a37bcd..15d9d7c 100644 --- a/cbits/souffle/utility/Iteration.h +++ b/cbits/souffle/utility/Iteration.h @@ -26,18 +26,7 @@ namespace souffle { namespace detail { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4172) -#elif defined(__GNUC__) && (__GNUC__ >= 7) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wreturn-local-addr" -#elif defined(__has_warning) -#pragma clang diagnostic push -#if __has_warning("-Wreturn-stack-address") -#pragma clang diagnostic ignored "-Wreturn-stack-address" -#endif -#endif + // This is a helper in the cases when the lambda is stateless template F makeFun() { @@ -45,16 +34,9 @@ F makeFun() { // Even thought the lambda is stateless, it has no default ctor // Is this gross? Yes, yes it is. // FIXME: Remove after C++20 - typename std::aligned_storage::type fakeLam{}; + typename std::aligned_storage::type fakeLam; return reinterpret_cast(fakeLam); } -#ifdef _MSC_VER -#pragma warning(pop) -#elif defined(__GNUC__) && (__GNUC__ >= 7) -#pragma GCC diagnostic pop -#elif defined(__has_warning) -#pragma clang diagnostic pop -#endif } // namespace detail // ------------------------------------------------------------- @@ -119,7 +101,7 @@ class TransformIterator { } /* Support for the pointer operator. */ - auto operator->() const { + auto operator-> () const { return &**this; } @@ -283,9 +265,9 @@ struct range { } // splits up this range into the given number of partitions - std::vector partition(std::size_t np = 100) { + std::vector partition(int np = 100) { // obtain the size - std::size_t n = 0; + int n = 0; for (auto i = a; i != b; ++i) { n++; } @@ -297,8 +279,8 @@ struct range { res.reserve(np); auto cur = a; auto last = cur; - std::size_t i = 0; - std::size_t p = 0; + int i = 0; + int p = 0; while (cur != b) { ++cur; i++; diff --git a/cbits/souffle/utility/MiscUtil.h b/cbits/souffle/utility/MiscUtil.h index c405e65..3f8348e 100644 --- a/cbits/souffle/utility/MiscUtil.h +++ b/cbits/souffle/utility/MiscUtil.h @@ -30,13 +30,18 @@ #include #ifdef _WIN32 -#define NOMINMAX -#define NOGDI #include #include #include #include +/** + * Windows headers define these and they interfere with the standard library + * functions. + */ +#undef min +#undef max + /** * On windows, the following gcc builtins are missing. * @@ -49,34 +54,21 @@ #define __builtin_popcountll __popcnt64 #if defined(_MSC_VER) -// return the number of trailing zeroes in value, or 32 if value is zero. -inline constexpr unsigned long __builtin_ctz(unsigned long value) { +constexpr unsigned long __builtin_ctz(unsigned long value) { unsigned long trailing_zeroes = 0; - if (value == 0) return 32; while ((value = value >> 1) ^ 1) { ++trailing_zeroes; } return trailing_zeroes; } -// return the number of trailing zeroes in value, or 64 if value is zero. -inline constexpr int __builtin_ctzll_constexpr(unsigned long long value) { - int trailing_zeroes = 0; - - if (value == 0) return 64; - while ((value = value >> 1) ^ 1) { - ++trailing_zeroes; - } - return trailing_zeroes; -} - -inline int __builtin_ctzll(unsigned long long value) { - unsigned long trailing_zeroes = 0; +inline unsigned long __builtin_ctzll(unsigned long long value) { + unsigned long trailing_zero = 0; - if (_BitScanForward64(&trailing_zeroes, value)) { - return static_cast(trailing_zeroes); + if (_BitScanForward64(&trailing_zero, value)) { + return trailing_zero; } else { - return 64; // return 64 like GCC would when value == 0 + return 64; } } #endif // _MSC_VER diff --git a/cbits/souffle/utility/ParallelUtil.h b/cbits/souffle/utility/ParallelUtil.h index 7d8a5cd..3cf6c06 100644 --- a/cbits/souffle/utility/ParallelUtil.h +++ b/cbits/souffle/utility/ParallelUtil.h @@ -48,28 +48,14 @@ constexpr std::size_t hardware_destructive_interference_size = 2 * sizeof(max_al #include // pthread_yield is deprecated and should be replaced by sched_yield #define pthread_yield sched_yield -#elif defined _MSC_VER -#include -#define NOMINMAX -#include -#define pthread_yield std::this_thread::yield #endif -#ifdef _MSC_VER -// support for a parallel region -#define PARALLEL_START __pragma(omp parallel) { -#define PARALLEL_END } - -// support for parallel loops -#define pfor __pragma(omp for schedule(dynamic)) for -#else // support for a parallel region #define PARALLEL_START _Pragma("omp parallel") { #define PARALLEL_END } // support for parallel loops #define pfor _Pragma("omp for schedule(dynamic)") for -#endif // spawn and sync are processed sequentially (overhead to expensive) #define task_spawn @@ -235,15 +221,11 @@ class Lock { namespace detail { /* Pause instruction to prevent excess processor bus usage */ -#if defined _MSC_VER -#define cpu_relax() YieldProcessor() -#else #ifdef __x86_64__ #define cpu_relax() asm volatile("pause\n" : : : "memory") #else #define cpu_relax() asm volatile("" : : : "memory") #endif -#endif /** * A utility class managing waiting operations for spin locks. diff --git a/cbits/souffle/utility/tinyformat.h b/cbits/souffle/utility/tinyformat.h index aa06c04..b26a9df 100644 --- a/cbits/souffle/utility/tinyformat.h +++ b/cbits/souffle/utility/tinyformat.h @@ -792,29 +792,27 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& positionalMode break; case 'X': out.setf(std::ios::uppercase); - [[fallthrough]]; - case 'x': - [[fallthrough]]; - case 'p': + // Falls through + case 'x': case 'p': out.setf(std::ios::hex, std::ios::basefield); intConversion = true; break; case 'E': out.setf(std::ios::uppercase); - [[fallthrough]]; + // Falls through case 'e': out.setf(std::ios::scientific, std::ios::floatfield); out.setf(std::ios::dec, std::ios::basefield); break; case 'F': out.setf(std::ios::uppercase); - [[fallthrough]]; + // Falls through case 'f': out.setf(std::ios::fixed, std::ios::floatfield); break; case 'A': out.setf(std::ios::uppercase); - [[fallthrough]]; + // Falls through case 'a': # ifdef _MSC_VER // Workaround https://developercommunity.visualstudio.com/content/problem/520472/hexfloat-stream-output-does-not-ignore-precision-a.html @@ -826,7 +824,7 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& positionalMode break; case 'G': out.setf(std::ios::uppercase); - [[fallthrough]]; + // Falls through case 'g': out.setf(std::ios::dec, std::ios::basefield); // As in boost::format, let stream decide float format. diff --git a/lib/Language/Souffle/Compiled.hs b/lib/Language/Souffle/Compiled.hs index a781a2e..9570101 100644 --- a/lib/Language/Souffle/Compiled.hs +++ b/lib/Language/Souffle/Compiled.hs @@ -31,7 +31,7 @@ module Language.Souffle.Compiled ) where import Prelude hiding ( init ) -import Control.Monad.State.Strict +import Control.Monad.State.Strict (StateT, MonadState (..), evalStateT, modify, gets) import Data.Foldable ( traverse_ ) import Data.Functor.Identity import Data.Proxy @@ -59,7 +59,8 @@ import Language.Souffle.Class import qualified Language.Souffle.Internal as Internal import Language.Souffle.Marshal import Control.Concurrent - +import Control.Monad (when) +import Control.Monad.IO.Class (MonadIO (..)) type ByteCount :: Type type ByteCount = Int diff --git a/lib/Language/Souffle/Interpreted.hs b/lib/Language/Souffle/Interpreted.hs index 75a9db8..bae427c 100644 --- a/lib/Language/Souffle/Interpreted.hs +++ b/lib/Language/Souffle/Interpreted.hs @@ -35,7 +35,7 @@ import Data.Kind (Type, Constraint) import Control.DeepSeq (deepseq) import Control.Exception (ErrorCall(..), throwIO, bracket) -import Control.Monad.State.Strict +import Control.Monad.State.Strict (State, MonadState (state), modify, evalState, execState) import Data.IORef import Data.Foldable (traverse_) import qualified Data.List as List hiding (init) @@ -46,8 +46,6 @@ import qualified Data.Array as A import qualified Data.Text as T import qualified Data.Vector as V import Data.Word -import Language.Souffle.Class -import Language.Souffle.Marshal import System.Directory import System.Environment import System.Exit @@ -57,6 +55,11 @@ import System.IO.Temp import System.Process import Text.Printf +import Language.Souffle.Class +import Language.Souffle.Marshal +import Control.Monad.IO.Class (MonadIO (..)) +import Control.Monad (forM, (<$!>), forM_) + -- | A monad for executing Souffle-related actions in. type SouffleM :: Type -> Type diff --git a/package.yaml b/package.yaml index 3469c1e..dca145c 100644 --- a/package.yaml +++ b/package.yaml @@ -46,7 +46,7 @@ ghc-options: - -Wno-prepositive-qualified-module - -Wno-missing-safe-haskell-mode - -Wno-operator-whitespace - - -optP-Wno-nonportable-include-path + # - -optP-Wno-nonportable-include-path - -fhide-source-paths - -fno-show-valid-hole-fits - -fno-sort-valid-hole-fits @@ -62,6 +62,9 @@ install-includes: - souffle/CompiledSouffle.h - souffle/RamTypes.h - souffle/RecordTable.h + - souffle/datastructure/ConcurrentFlyweight.h + - souffle/datastructure/ConcurrentInsertOnlyHashMap.h + - souffle/utility/ParallelUtil.h - souffle/utility/span.h - souffle/SignalHandler.h - souffle/SouffleInterface.h @@ -71,23 +74,18 @@ install-includes: - souffle/utility/Iteration.h - souffle/utility/Types.h - souffle/utility/tinyformat.h + - souffle/utility/StreamUtil.h + - souffle/utility/ContainerUtil.h + - souffle/utility/DynamicCasting.h - souffle/datastructure/BTreeDelete.h - souffle/datastructure/BTreeUtil.h - souffle/utility/CacheUtil.h - - souffle/utility/ContainerUtil.h - - souffle/utility/DynamicCasting.h - - souffle/utility/ParallelUtil.h - souffle/datastructure/Brie.h - - souffle/utility/StreamUtil.h - souffle/datastructure/EquivalenceRelation.h - souffle/datastructure/LambdaBTree.h - souffle/datastructure/BTree.h - souffle/datastructure/PiggyList.h - souffle/datastructure/UnionFind.h - - souffle/datastructure/RecordTableImpl.h - - souffle/datastructure/ConcurrentFlyweight.h - - souffle/datastructure/ConcurrentInsertOnlyHashMap.h - - souffle/datastructure/SymbolTableImpl.h - souffle/datastructure/Table.h - souffle/io/IOSystem.h - souffle/io/ReadStream.h @@ -104,7 +102,6 @@ install-includes: - souffle/io/ReadStreamSQLite.h - souffle/io/WriteStreamSQLite.h - souffle/utility/EvaluatorUtil.h - - souffle/utility/EvaluatorUtil.h library: source-dirs: lib diff --git a/souffle b/souffle index cc8ea09..ea4ebd4 160000 --- a/souffle +++ b/souffle @@ -1 +1 @@ -Subproject commit cc8ea091721fcfb60bed45a0edf571ad9d0c58a5 +Subproject commit ea4ebd45b56619f9362d5db9bb6b7783b4bbb24c diff --git a/souffle-haskell.cabal b/souffle-haskell.cabal index ed8a7e3..bc46395 100644 --- a/souffle-haskell.cabal +++ b/souffle-haskell.cabal @@ -4,19 +4,19 @@ cabal-version: 2.2 -- -- see: https://github.com/sol/hpack -name: souffle-haskell -version: 4.0.0 -synopsis: Souffle Datalog bindings for Haskell -description: Souffle Datalog bindings for Haskell. -category: Logic Programming, Foreign Binding, Bindings -homepage: https://github.com/luc-tielen/souffle-haskell#README.md -bug-reports: https://github.com/luc-tielen/souffle-haskell/issues -author: Luc Tielen -maintainer: luc.tielen@gmail.com -copyright: 2022 Luc Tielen -license: MIT -license-file: LICENSE -build-type: Simple +name: souffle-haskell +version: 4.0.0 +synopsis: Souffle Datalog bindings for Haskell +description: Souffle Datalog bindings for Haskell. +category: Logic Programming, Foreign Binding, Bindings +homepage: https://github.com/luc-tielen/souffle-haskell#README.md +bug-reports: https://github.com/luc-tielen/souffle-haskell/issues +author: Luc Tielen +maintainer: luc.tielen@gmail.com +copyright: 2022 Luc Tielen +license: MIT +license-file: LICENSE +build-type: Simple extra-source-files: cbits/souffle.h cbits/souffle/CompiledSouffle.h @@ -29,8 +29,6 @@ extra-source-files: cbits/souffle/datastructure/EquivalenceRelation.h cbits/souffle/datastructure/LambdaBTree.h cbits/souffle/datastructure/PiggyList.h - cbits/souffle/datastructure/RecordTableImpl.h - cbits/souffle/datastructure/SymbolTableImpl.h cbits/souffle/datastructure/Table.h cbits/souffle/datastructure/UnionFind.h cbits/souffle/io/gzfstream.h @@ -97,7 +95,7 @@ library OverloadedStrings ScopedTypeVariables StandaloneKindSignatures - ghc-options: -Wall -Weverything -Wno-safe -Wno-unsafe -Wno-implicit-prelude -Wno-missed-specializations -Wno-all-missed-specializations -Wno-missing-import-lists -Wno-type-defaults -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-missing-safe-haskell-mode -Wno-operator-whitespace -optP-Wno-nonportable-include-path -fhide-source-paths -fno-show-valid-hole-fits -fno-sort-valid-hole-fits + ghc-options: -Wall -Weverything -Wno-safe -Wno-unsafe -Wno-implicit-prelude -Wno-missed-specializations -Wno-all-missed-specializations -Wno-missing-import-lists -Wno-type-defaults -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-missing-safe-haskell-mode -Wno-operator-whitespace -fhide-source-paths -fno-show-valid-hole-fits -fno-sort-valid-hole-fits cxx-options: -std=c++17 -Wall include-dirs: cbits @@ -106,6 +104,9 @@ library souffle/CompiledSouffle.h souffle/RamTypes.h souffle/RecordTable.h + souffle/datastructure/ConcurrentFlyweight.h + souffle/datastructure/ConcurrentInsertOnlyHashMap.h + souffle/utility/ParallelUtil.h souffle/utility/span.h souffle/SignalHandler.h souffle/SouffleInterface.h @@ -115,23 +116,18 @@ library souffle/utility/Iteration.h souffle/utility/Types.h souffle/utility/tinyformat.h + souffle/utility/StreamUtil.h + souffle/utility/ContainerUtil.h + souffle/utility/DynamicCasting.h souffle/datastructure/BTreeDelete.h souffle/datastructure/BTreeUtil.h souffle/utility/CacheUtil.h - souffle/utility/ContainerUtil.h - souffle/utility/DynamicCasting.h - souffle/utility/ParallelUtil.h souffle/datastructure/Brie.h - souffle/utility/StreamUtil.h souffle/datastructure/EquivalenceRelation.h souffle/datastructure/LambdaBTree.h souffle/datastructure/BTree.h souffle/datastructure/PiggyList.h souffle/datastructure/UnionFind.h - souffle/datastructure/RecordTableImpl.h - souffle/datastructure/ConcurrentFlyweight.h - souffle/datastructure/ConcurrentInsertOnlyHashMap.h - souffle/datastructure/SymbolTableImpl.h souffle/datastructure/Table.h souffle/io/IOSystem.h souffle/io/ReadStream.h @@ -148,7 +144,6 @@ library souffle/io/ReadStreamSQLite.h souffle/io/WriteStreamSQLite.h souffle/utility/EvaluatorUtil.h - souffle/utility/EvaluatorUtil.h cxx-sources: cbits/souffle.cpp build-depends: @@ -190,7 +185,7 @@ test-suite souffle-haskell-test OverloadedStrings ScopedTypeVariables StandaloneKindSignatures - ghc-options: -Wall -Weverything -Wno-safe -Wno-unsafe -Wno-implicit-prelude -Wno-missed-specializations -Wno-all-missed-specializations -Wno-missing-import-lists -Wno-type-defaults -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-missing-safe-haskell-mode -Wno-operator-whitespace -optP-Wno-nonportable-include-path -fhide-source-paths -fno-show-valid-hole-fits -fno-sort-valid-hole-fits -Wno-missing-kind-signatures -Wno-operator-whitespace + ghc-options: -Wall -Weverything -Wno-safe -Wno-unsafe -Wno-implicit-prelude -Wno-missed-specializations -Wno-all-missed-specializations -Wno-missing-import-lists -Wno-type-defaults -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-missing-safe-haskell-mode -Wno-operator-whitespace -fhide-source-paths -fno-show-valid-hole-fits -fno-sort-valid-hole-fits -Wno-missing-kind-signatures -Wno-operator-whitespace cxx-options: -std=c++17 -D__EMBEDDED_SOUFFLE__ include-dirs: cbits @@ -199,6 +194,9 @@ test-suite souffle-haskell-test souffle/CompiledSouffle.h souffle/RamTypes.h souffle/RecordTable.h + souffle/datastructure/ConcurrentFlyweight.h + souffle/datastructure/ConcurrentInsertOnlyHashMap.h + souffle/utility/ParallelUtil.h souffle/utility/span.h souffle/SignalHandler.h souffle/SouffleInterface.h @@ -208,23 +206,18 @@ test-suite souffle-haskell-test souffle/utility/Iteration.h souffle/utility/Types.h souffle/utility/tinyformat.h + souffle/utility/StreamUtil.h + souffle/utility/ContainerUtil.h + souffle/utility/DynamicCasting.h souffle/datastructure/BTreeDelete.h souffle/datastructure/BTreeUtil.h souffle/utility/CacheUtil.h - souffle/utility/ContainerUtil.h - souffle/utility/DynamicCasting.h - souffle/utility/ParallelUtil.h souffle/datastructure/Brie.h - souffle/utility/StreamUtil.h souffle/datastructure/EquivalenceRelation.h souffle/datastructure/LambdaBTree.h souffle/datastructure/BTree.h souffle/datastructure/PiggyList.h souffle/datastructure/UnionFind.h - souffle/datastructure/RecordTableImpl.h - souffle/datastructure/ConcurrentFlyweight.h - souffle/datastructure/ConcurrentInsertOnlyHashMap.h - souffle/datastructure/SymbolTableImpl.h souffle/datastructure/Table.h souffle/io/IOSystem.h souffle/io/ReadStream.h @@ -241,7 +234,6 @@ test-suite souffle-haskell-test souffle/io/ReadStreamSQLite.h souffle/io/WriteStreamSQLite.h souffle/utility/EvaluatorUtil.h - souffle/utility/EvaluatorUtil.h cxx-sources: tests/fixtures/edge_cases.cpp tests/fixtures/path.cpp @@ -279,7 +271,7 @@ benchmark souffle-haskell-benchmarks OverloadedStrings ScopedTypeVariables StandaloneKindSignatures - ghc-options: -Wall -Weverything -Wno-safe -Wno-unsafe -Wno-implicit-prelude -Wno-missed-specializations -Wno-all-missed-specializations -Wno-missing-import-lists -Wno-type-defaults -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-missing-safe-haskell-mode -Wno-operator-whitespace -optP-Wno-nonportable-include-path -fhide-source-paths -fno-show-valid-hole-fits -fno-sort-valid-hole-fits +RTS -N1 -RTS + ghc-options: -Wall -Weverything -Wno-safe -Wno-unsafe -Wno-implicit-prelude -Wno-missed-specializations -Wno-all-missed-specializations -Wno-missing-import-lists -Wno-type-defaults -Wno-missing-local-signatures -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-missing-safe-haskell-mode -Wno-operator-whitespace -fhide-source-paths -fno-show-valid-hole-fits -fno-sort-valid-hole-fits +RTS -N1 -RTS cxx-options: -std=c++17 -D__EMBEDDED_SOUFFLE__ -std=c++17 -march=native include-dirs: cbits @@ -288,6 +280,9 @@ benchmark souffle-haskell-benchmarks souffle/CompiledSouffle.h souffle/RamTypes.h souffle/RecordTable.h + souffle/datastructure/ConcurrentFlyweight.h + souffle/datastructure/ConcurrentInsertOnlyHashMap.h + souffle/utility/ParallelUtil.h souffle/utility/span.h souffle/SignalHandler.h souffle/SouffleInterface.h @@ -297,23 +292,18 @@ benchmark souffle-haskell-benchmarks souffle/utility/Iteration.h souffle/utility/Types.h souffle/utility/tinyformat.h + souffle/utility/StreamUtil.h + souffle/utility/ContainerUtil.h + souffle/utility/DynamicCasting.h souffle/datastructure/BTreeDelete.h souffle/datastructure/BTreeUtil.h souffle/utility/CacheUtil.h - souffle/utility/ContainerUtil.h - souffle/utility/DynamicCasting.h - souffle/utility/ParallelUtil.h souffle/datastructure/Brie.h - souffle/utility/StreamUtil.h souffle/datastructure/EquivalenceRelation.h souffle/datastructure/LambdaBTree.h souffle/datastructure/BTree.h souffle/datastructure/PiggyList.h souffle/datastructure/UnionFind.h - souffle/datastructure/RecordTableImpl.h - souffle/datastructure/ConcurrentFlyweight.h - souffle/datastructure/ConcurrentInsertOnlyHashMap.h - souffle/datastructure/SymbolTableImpl.h souffle/datastructure/Table.h souffle/io/IOSystem.h souffle/io/ReadStream.h @@ -330,7 +320,6 @@ benchmark souffle-haskell-benchmarks souffle/io/ReadStreamSQLite.h souffle/io/WriteStreamSQLite.h souffle/utility/EvaluatorUtil.h - souffle/utility/EvaluatorUtil.h cxx-sources: benchmarks/fixtures/bench.cpp build-depends: diff --git a/tests/fixtures/edge_cases.cpp b/tests/fixtures/edge_cases.cpp index cd1a60c..5919d5a 100644 --- a/tests/fixtures/edge_cases.cpp +++ b/tests/fixtures/edge_cases.cpp @@ -1,9 +1,7 @@ #include "souffle/CompiledSouffle.h" -namespace functors { - extern "C" { -} +extern "C" { } namespace souffle { @@ -16,7 +14,7 @@ struct t_comparator_0{ return (ramBitCast(a[0]) < ramBitCast(b[0])) ? -1 : (ramBitCast(a[0]) > ramBitCast(b[0])) ? 1 :((ramBitCast(a[1]) < ramBitCast(b[1])) ? -1 : (ramBitCast(a[1]) > ramBitCast(b[1])) ? 1 :((ramBitCast(a[2]) < ramBitCast(b[2])) ? -1 : (ramBitCast(a[2]) > ramBitCast(b[2])) ? 1 :(0))); } bool less(const t_tuple& a, const t_tuple& b) const { - return (ramBitCast(a[0]) < ramBitCast(b[0]))|| ((ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1]))|| ((ramBitCast(a[1]) == ramBitCast(b[1])) && ((ramBitCast(a[2]) < ramBitCast(b[2])))))); + return (ramBitCast(a[0]) < ramBitCast(b[0]))|| (ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1]))|| (ramBitCast(a[1]) == ramBitCast(b[1])) && ((ramBitCast(a[2]) < ramBitCast(b[2])))); } bool equal(const t_tuple& a, const t_tuple& b) const { return (ramBitCast(a[0]) == ramBitCast(b[0]))&&(ramBitCast(a[1]) == ramBitCast(b[1]))&&(ramBitCast(a[2]) == ramBitCast(b[2])); @@ -222,7 +220,7 @@ struct t_comparator_0{ return (ramBitCast(a[0]) < ramBitCast(b[0])) ? -1 : (ramBitCast(a[0]) > ramBitCast(b[0])) ? 1 :((ramBitCast(a[1]) < ramBitCast(b[1])) ? -1 : (ramBitCast(a[1]) > ramBitCast(b[1])) ? 1 :((ramBitCast(a[2]) < ramBitCast(b[2])) ? -1 : (ramBitCast(a[2]) > ramBitCast(b[2])) ? 1 :(0))); } bool less(const t_tuple& a, const t_tuple& b) const { - return (ramBitCast(a[0]) < ramBitCast(b[0]))|| ((ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1]))|| ((ramBitCast(a[1]) == ramBitCast(b[1])) && ((ramBitCast(a[2]) < ramBitCast(b[2])))))); + return (ramBitCast(a[0]) < ramBitCast(b[0]))|| (ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1]))|| (ramBitCast(a[1]) == ramBitCast(b[1])) && ((ramBitCast(a[2]) < ramBitCast(b[2])))); } bool equal(const t_tuple& a, const t_tuple& b) const { return (ramBitCast(a[0]) == ramBitCast(b[0]))&&(ramBitCast(a[1]) == ramBitCast(b[1]))&&(ramBitCast(a[2]) == ramBitCast(b[2])); @@ -329,7 +327,7 @@ static inline std::string substr_wrapper(const std::string& str, std::size_t idx } public: // -- initialize symbol table -- -SymbolTableImpl symTable{ +SymbolTable symTable{ R"_()_", R"_(abc)_", R"_(long_string_from_DL:...............................................................................................................................................................................................................................................................................................end)_", @@ -383,7 +381,7 @@ void runFunction(std::string inputDirectoryArg, // set default threads (in embedded mode) // if this is not set, and omp is used, the default omp setting of number of cores is used. #if defined(_OPENMP) - if (0 < getNumThreads()) { omp_set_num_threads(static_cast(getNumThreads())); } + if (0 < getNumThreads()) { omp_set_num_threads(getNumThreads()); } #endif signalHandler->set(); @@ -415,55 +413,55 @@ void runAll(std::string inputDirectoryArg = "", std::string outputDirectoryArg = } public: void printAll(std::string outputDirectoryArg = "") override { -try {std::map directiveMap({{"IO","file"},{"attributeNames","s"},{"auxArity","0"},{"name","long_strings"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"s:symbol\"]}}"}}); -if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} -IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_2_long_strings); -} catch (std::exception& e) {std::cerr << e.what();exit(1);} -try {std::map directiveMap({{"IO","file"},{"attributeNames","s"},{"auxArity","0"},{"name","unicode"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"s:symbol\"]}}"}}); -if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} -IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_4_unicode); -} catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map directiveMap({{"IO","file"},{"attributeNames","s\ts2\tn"},{"auxArity","0"},{"name","empty_strings"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"params\": [\"s\", \"s2\", \"n\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"types\": [\"s:symbol\", \"s:symbol\", \"i:number\"]}}"}}); if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_1_empty_strings); } catch (std::exception& e) {std::cerr << e.what();exit(1);} +try {std::map directiveMap({{"IO","file"},{"attributeNames","s"},{"auxArity","0"},{"name","long_strings"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"s:symbol\"]}}"}}); +if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_2_long_strings); +} catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"auxArity","0"},{"name","no_strings"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_3_no_strings); } catch (std::exception& e) {std::cerr << e.what();exit(1);} +try {std::map directiveMap({{"IO","file"},{"attributeNames","s"},{"auxArity","0"},{"name","unicode"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"s:symbol\"]}}"}}); +if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_4_unicode); +} catch (std::exception& e) {std::cerr << e.what();exit(1);} } public: void loadAll(std::string inputDirectoryArg = "") override { +try {std::map directiveMap({{"IO","file"},{"attributeNames","s"},{"auxArity","0"},{"fact-dir","."},{"name","long_strings"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"s:symbol\"]}}"}}); +if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;} +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_2_long_strings); +} catch (std::exception& e) {std::cerr << "Error loading long_strings data: " << e.what() << '\n';} try {std::map directiveMap({{"IO","file"},{"attributeNames","u\tn\tf"},{"auxArity","0"},{"fact-dir","."},{"name","no_strings"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"params\": [\"u\", \"n\", \"f\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"}}); if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;} IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_3_no_strings); } catch (std::exception& e) {std::cerr << "Error loading no_strings data: " << e.what() << '\n';} -try {std::map directiveMap({{"IO","file"},{"attributeNames","s\ts2\tn"},{"auxArity","0"},{"fact-dir","."},{"name","empty_strings"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"params\": [\"s\", \"s2\", \"n\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"types\": [\"s:symbol\", \"s:symbol\", \"i:number\"]}}"}}); -if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;} -IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_1_empty_strings); -} catch (std::exception& e) {std::cerr << "Error loading empty_strings data: " << e.what() << '\n';} try {std::map directiveMap({{"IO","file"},{"attributeNames","s"},{"auxArity","0"},{"fact-dir","."},{"name","unicode"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"s:symbol\"]}}"}}); if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;} IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_4_unicode); } catch (std::exception& e) {std::cerr << "Error loading unicode data: " << e.what() << '\n';} -try {std::map directiveMap({{"IO","file"},{"attributeNames","s"},{"auxArity","0"},{"fact-dir","."},{"name","long_strings"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"s\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"s:symbol\"]}}"}}); +try {std::map directiveMap({{"IO","file"},{"attributeNames","s\ts2\tn"},{"auxArity","0"},{"fact-dir","."},{"name","empty_strings"},{"operation","input"},{"params","{\"records\": {}, \"relation\": {\"arity\": 3, \"params\": [\"s\", \"s2\", \"n\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 3, \"types\": [\"s:symbol\", \"s:symbol\", \"i:number\"]}}"}}); if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;} -IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_2_long_strings); -} catch (std::exception& e) {std::cerr << "Error loading long_strings data: " << e.what() << '\n';} +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_1_empty_strings); +} catch (std::exception& e) {std::cerr << "Error loading empty_strings data: " << e.what() << '\n';} } public: void dumpInputs() override { try {std::map rwOperation; rwOperation["IO"] = "stdout"; -rwOperation["name"] = "no_strings"; -rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_3_no_strings); +rwOperation["name"] = "long_strings"; +rwOperation["types"] = "{\"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"s:symbol\"]}}"; +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_2_long_strings); } catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map rwOperation; rwOperation["IO"] = "stdout"; -rwOperation["name"] = "empty_strings"; -rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"s:symbol\", \"s:symbol\", \"i:number\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_1_empty_strings); +rwOperation["name"] = "no_strings"; +rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"; +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_3_no_strings); } catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map rwOperation; rwOperation["IO"] = "stdout"; @@ -473,30 +471,24 @@ IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll( } catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map rwOperation; rwOperation["IO"] = "stdout"; -rwOperation["name"] = "long_strings"; -rwOperation["types"] = "{\"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"s:symbol\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_2_long_strings); +rwOperation["name"] = "empty_strings"; +rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"s:symbol\", \"s:symbol\", \"i:number\"]}}"; +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_1_empty_strings); } catch (std::exception& e) {std::cerr << e.what();exit(1);} } public: void dumpOutputs() override { try {std::map rwOperation; rwOperation["IO"] = "stdout"; -rwOperation["name"] = "long_strings"; -rwOperation["types"] = "{\"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"s:symbol\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_2_long_strings); +rwOperation["name"] = "empty_strings"; +rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"s:symbol\", \"s:symbol\", \"i:number\"]}}"; +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_1_empty_strings); } catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map rwOperation; rwOperation["IO"] = "stdout"; -rwOperation["name"] = "unicode"; +rwOperation["name"] = "long_strings"; rwOperation["types"] = "{\"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"s:symbol\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_4_unicode); -} catch (std::exception& e) {std::cerr << e.what();exit(1);} -try {std::map rwOperation; -rwOperation["IO"] = "stdout"; -rwOperation["name"] = "empty_strings"; -rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"s:symbol\", \"s:symbol\", \"i:number\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_1_empty_strings); +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_2_long_strings); } catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map rwOperation; rwOperation["IO"] = "stdout"; @@ -504,6 +496,12 @@ rwOperation["name"] = "no_strings"; rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"u:unsigned\", \"i:number\", \"f:float\"]}}"; IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_3_no_strings); } catch (std::exception& e) {std::cerr << e.what();exit(1);} +try {std::map rwOperation; +rwOperation["IO"] = "stdout"; +rwOperation["name"] = "unicode"; +rwOperation["types"] = "{\"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"s:symbol\"]}}"; +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_4_unicode); +} catch (std::exception& e) {std::cerr << e.what();exit(1);} } public: SymbolTable& getSymbolTable() override { @@ -543,21 +541,21 @@ IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll( } catch (std::exception& e) {std::cerr << "Error loading empty_strings data: " << e.what() << '\n';} } signalHandler->setMsg(R"_(empty_strings("","",42). -in file edge_cases.dl [20:1-20:27])_"); +in file /tmp/souffle-haskell/tests/fixtures/edge_cases.dl [20:1-20:27])_"); [&](){ CREATE_OP_CONTEXT(rel_1_empty_strings_op_ctxt,rel_1_empty_strings->createContext()); Tuple tuple{{ramBitCast(RamSigned(0)),ramBitCast(RamSigned(0)),ramBitCast(RamSigned(42))}}; rel_1_empty_strings->insert(tuple,READ_OP_CONTEXT(rel_1_empty_strings_op_ctxt)); } ();signalHandler->setMsg(R"_(empty_strings("","abc",42). -in file edge_cases.dl [21:1-21:30])_"); +in file /tmp/souffle-haskell/tests/fixtures/edge_cases.dl [21:1-21:30])_"); [&](){ CREATE_OP_CONTEXT(rel_1_empty_strings_op_ctxt,rel_1_empty_strings->createContext()); Tuple tuple{{ramBitCast(RamSigned(0)),ramBitCast(RamSigned(1)),ramBitCast(RamSigned(42))}}; rel_1_empty_strings->insert(tuple,READ_OP_CONTEXT(rel_1_empty_strings_op_ctxt)); } ();signalHandler->setMsg(R"_(empty_strings("abc","",42). -in file edge_cases.dl [22:1-22:30])_"); +in file /tmp/souffle-haskell/tests/fixtures/edge_cases.dl [22:1-22:30])_"); [&](){ CREATE_OP_CONTEXT(rel_1_empty_strings_op_ctxt,rel_1_empty_strings->createContext()); Tuple tuple{{ramBitCast(RamSigned(1)),ramBitCast(RamSigned(0)),ramBitCast(RamSigned(42))}}; @@ -584,7 +582,7 @@ IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll( } catch (std::exception& e) {std::cerr << "Error loading long_strings data: " << e.what() << '\n';} } signalHandler->setMsg(R"_(long_strings("long_string_from_DL:...............................................................................................................................................................................................................................................................................................end"). -in file edge_cases.dl [25:1-25:328])_"); +in file /tmp/souffle-haskell/tests/fixtures/edge_cases.dl [25:1-25:328])_"); [&](){ CREATE_OP_CONTEXT(rel_2_long_strings_op_ctxt,rel_2_long_strings->createContext()); Tuple tuple{{ramBitCast(RamSigned(2))}}; @@ -611,14 +609,14 @@ IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll( } catch (std::exception& e) {std::cerr << "Error loading no_strings data: " << e.what() << '\n';} } signalHandler->setMsg(R"_(no_strings(42,-100,1.5). -in file edge_cases.dl [33:1-33:27])_"); +in file /tmp/souffle-haskell/tests/fixtures/edge_cases.dl [33:1-33:27])_"); [&](){ CREATE_OP_CONTEXT(rel_3_no_strings_op_ctxt,rel_3_no_strings->createContext()); Tuple tuple{{ramBitCast(RamUnsigned(42)),ramBitCast(RamSigned(-100)),ramBitCast(RamFloat(1.5))}}; rel_3_no_strings->insert(tuple,READ_OP_CONTEXT(rel_3_no_strings_op_ctxt)); } ();signalHandler->setMsg(R"_(no_strings(123,-456,3.14). -in file edge_cases.dl [34:1-34:29])_"); +in file /tmp/souffle-haskell/tests/fixtures/edge_cases.dl [34:1-34:29])_"); [&](){ CREATE_OP_CONTEXT(rel_3_no_strings_op_ctxt,rel_3_no_strings->createContext()); Tuple tuple{{ramBitCast(RamUnsigned(123)),ramBitCast(RamSigned(-456)),ramBitCast(RamFloat(3.1400001))}}; @@ -645,14 +643,14 @@ IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll( } catch (std::exception& e) {std::cerr << "Error loading unicode data: " << e.what() << '\n';} } signalHandler->setMsg(R"_(unicode("∀"). -in file edge_cases.dl [30:1-30:16])_"); +in file /tmp/souffle-haskell/tests/fixtures/edge_cases.dl [30:1-30:16])_"); [&](){ CREATE_OP_CONTEXT(rel_4_unicode_op_ctxt,rel_4_unicode->createContext()); Tuple tuple{{ramBitCast(RamSigned(3))}}; rel_4_unicode->insert(tuple,READ_OP_CONTEXT(rel_4_unicode_op_ctxt)); } ();signalHandler->setMsg(R"_(unicode("∀∀"). -in file edge_cases.dl [31:1-31:19])_"); +in file /tmp/souffle-haskell/tests/fixtures/edge_cases.dl [31:1-31:19])_"); [&](){ CREATE_OP_CONTEXT(rel_4_unicode_op_ctxt,rel_4_unicode->createContext()); Tuple tuple{{ramBitCast(RamSigned(4))}}; diff --git a/tests/fixtures/path.cpp b/tests/fixtures/path.cpp index f3cd228..522cdea 100644 --- a/tests/fixtures/path.cpp +++ b/tests/fixtures/path.cpp @@ -1,9 +1,7 @@ #include "souffle/CompiledSouffle.h" -namespace functors { - extern "C" { -} +extern "C" { } namespace souffle { @@ -16,7 +14,7 @@ struct t_comparator_0{ return (ramBitCast(a[0]) < ramBitCast(b[0])) ? -1 : (ramBitCast(a[0]) > ramBitCast(b[0])) ? 1 :((ramBitCast(a[1]) < ramBitCast(b[1])) ? -1 : (ramBitCast(a[1]) > ramBitCast(b[1])) ? 1 :(0)); } bool less(const t_tuple& a, const t_tuple& b) const { - return (ramBitCast(a[0]) < ramBitCast(b[0]))|| ((ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1])))); + return (ramBitCast(a[0]) < ramBitCast(b[0]))|| (ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1]))); } bool equal(const t_tuple& a, const t_tuple& b) const { return (ramBitCast(a[0]) == ramBitCast(b[0]))&&(ramBitCast(a[1]) == ramBitCast(b[1])); @@ -119,7 +117,7 @@ struct t_comparator_0{ return (ramBitCast(a[0]) < ramBitCast(b[0])) ? -1 : (ramBitCast(a[0]) > ramBitCast(b[0])) ? 1 :((ramBitCast(a[1]) < ramBitCast(b[1])) ? -1 : (ramBitCast(a[1]) > ramBitCast(b[1])) ? 1 :(0)); } bool less(const t_tuple& a, const t_tuple& b) const { - return (ramBitCast(a[0]) < ramBitCast(b[0]))|| ((ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1])))); + return (ramBitCast(a[0]) < ramBitCast(b[0]))|| (ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1]))); } bool equal(const t_tuple& a, const t_tuple& b) const { return (ramBitCast(a[0]) == ramBitCast(b[0]))&&(ramBitCast(a[1]) == ramBitCast(b[1])); @@ -238,7 +236,7 @@ static inline std::string substr_wrapper(const std::string& str, std::size_t idx } public: // -- initialize symbol table -- -SymbolTableImpl symTable{ +SymbolTable symTable{ R"_(a)_", R"_(b)_", R"_(c)_", @@ -284,7 +282,7 @@ void runFunction(std::string inputDirectoryArg, // set default threads (in embedded mode) // if this is not set, and omp is used, the default omp setting of number of cores is used. #if defined(_OPENMP) - if (0 < getNumThreads()) { omp_set_num_threads(static_cast(getNumThreads())); } + if (0 < getNumThreads()) { omp_set_num_threads(getNumThreads()); } #endif signalHandler->set(); @@ -380,14 +378,14 @@ IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll( } catch (std::exception& e) {std::cerr << "Error loading edge data: " << e.what() << '\n';} } signalHandler->setMsg(R"_(edge("a","b"). -in file path.dl [11:1-11:16])_"); +in file /tmp/souffle-haskell/tests/fixtures/path.dl [11:1-11:16])_"); [&](){ CREATE_OP_CONTEXT(rel_1_edge_op_ctxt,rel_1_edge->createContext()); Tuple tuple{{ramBitCast(RamSigned(0)),ramBitCast(RamSigned(1))}}; rel_1_edge->insert(tuple,READ_OP_CONTEXT(rel_1_edge_op_ctxt)); } ();signalHandler->setMsg(R"_(edge("b","c"). -in file path.dl [12:1-12:16])_"); +in file /tmp/souffle-haskell/tests/fixtures/path.dl [12:1-12:16])_"); [&](){ CREATE_OP_CONTEXT(rel_1_edge_op_ctxt,rel_1_edge->createContext()); Tuple tuple{{ramBitCast(RamSigned(1)),ramBitCast(RamSigned(2))}}; @@ -409,11 +407,11 @@ IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll void subroutine_1(const std::vector& args, std::vector& ret) { signalHandler->setMsg(R"_(reachable(x,y) :- edge(x,y). -in file path.dl [14:1-14:31])_"); +in file /tmp/souffle-haskell/tests/fixtures/path.dl [14:1-14:31])_"); if(!(rel_1_edge->empty())) { [&](){ -CREATE_OP_CONTEXT(rel_1_edge_op_ctxt,rel_1_edge->createContext()); CREATE_OP_CONTEXT(rel_2_reachable_op_ctxt,rel_2_reachable->createContext()); +CREATE_OP_CONTEXT(rel_1_edge_op_ctxt,rel_1_edge->createContext()); for(const auto& env0 : *rel_1_edge) { Tuple tuple{{ramBitCast(env0[0]),ramBitCast(env0[1])}}; rel_2_reachable->insert(tuple,READ_OP_CONTEXT(rel_2_reachable_op_ctxt)); @@ -433,12 +431,12 @@ for(;;) { signalHandler->setMsg(R"_(reachable(x,z) :- edge(x,y), reachable(y,z). -in file path.dl [15:1-15:48])_"); +in file /tmp/souffle-haskell/tests/fixtures/path.dl [15:1-15:48])_"); if(!(rel_1_edge->empty()) && !(rel_3_delta_reachable->empty())) { [&](){ -CREATE_OP_CONTEXT(rel_1_edge_op_ctxt,rel_1_edge->createContext()); -CREATE_OP_CONTEXT(rel_4_new_reachable_op_ctxt,rel_4_new_reachable->createContext()); CREATE_OP_CONTEXT(rel_2_reachable_op_ctxt,rel_2_reachable->createContext()); +CREATE_OP_CONTEXT(rel_4_new_reachable_op_ctxt,rel_4_new_reachable->createContext()); +CREATE_OP_CONTEXT(rel_1_edge_op_ctxt,rel_1_edge->createContext()); CREATE_OP_CONTEXT(rel_3_delta_reachable_op_ctxt,rel_3_delta_reachable->createContext()); for(const auto& env0 : *rel_1_edge) { auto range = rel_3_delta_reachable->lowerUpperRange_10(Tuple{{ramBitCast(env0[1]), ramBitCast(MIN_RAM_SIGNED)}},Tuple{{ramBitCast(env0[1]), ramBitCast(MAX_RAM_SIGNED)}},READ_OP_CONTEXT(rel_3_delta_reachable_op_ctxt)); @@ -453,8 +451,8 @@ rel_4_new_reachable->insert(tuple,READ_OP_CONTEXT(rel_4_new_reachable_op_ctxt)); ();} if(rel_4_new_reachable->empty()) break; [&](){ -CREATE_OP_CONTEXT(rel_4_new_reachable_op_ctxt,rel_4_new_reachable->createContext()); CREATE_OP_CONTEXT(rel_2_reachable_op_ctxt,rel_2_reachable->createContext()); +CREATE_OP_CONTEXT(rel_4_new_reachable_op_ctxt,rel_4_new_reachable->createContext()); for(const auto& env0 : *rel_4_new_reachable) { Tuple tuple{{ramBitCast(env0[0]),ramBitCast(env0[1])}}; rel_2_reachable->insert(tuple,READ_OP_CONTEXT(rel_2_reachable_op_ctxt)); diff --git a/tests/fixtures/round_trip.cpp b/tests/fixtures/round_trip.cpp index 492fde3..5855a9a 100644 --- a/tests/fixtures/round_trip.cpp +++ b/tests/fixtures/round_trip.cpp @@ -1,9 +1,7 @@ #include "souffle/CompiledSouffle.h" -namespace functors { - extern "C" { -} +extern "C" { } namespace souffle { @@ -119,7 +117,7 @@ struct t_comparator_0{ return (ramBitCast(a[0]) < ramBitCast(b[0])) ? -1 : (ramBitCast(a[0]) > ramBitCast(b[0])) ? 1 :((ramBitCast(a[1]) < ramBitCast(b[1])) ? -1 : (ramBitCast(a[1]) > ramBitCast(b[1])) ? 1 :((ramBitCast(a[2]) < ramBitCast(b[2])) ? -1 : (ramBitCast(a[2]) > ramBitCast(b[2])) ? 1 :((ramBitCast(a[3]) < ramBitCast(b[3])) ? -1 : (ramBitCast(a[3]) > ramBitCast(b[3])) ? 1 :(0)))); } bool less(const t_tuple& a, const t_tuple& b) const { - return (ramBitCast(a[0]) < ramBitCast(b[0]))|| ((ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1]))|| ((ramBitCast(a[1]) == ramBitCast(b[1])) && ((ramBitCast(a[2]) < ramBitCast(b[2]))|| ((ramBitCast(a[2]) == ramBitCast(b[2])) && ((ramBitCast(a[3]) < ramBitCast(b[3])))))))); + return (ramBitCast(a[0]) < ramBitCast(b[0]))|| (ramBitCast(a[0]) == ramBitCast(b[0])) && ((ramBitCast(a[1]) < ramBitCast(b[1]))|| (ramBitCast(a[1]) == ramBitCast(b[1])) && ((ramBitCast(a[2]) < ramBitCast(b[2]))|| (ramBitCast(a[2]) == ramBitCast(b[2])) && ((ramBitCast(a[3]) < ramBitCast(b[3]))))); } bool equal(const t_tuple& a, const t_tuple& b) const { return (ramBitCast(a[0]) == ramBitCast(b[0]))&&(ramBitCast(a[1]) == ramBitCast(b[1]))&&(ramBitCast(a[2]) == ramBitCast(b[2]))&&(ramBitCast(a[3]) == ramBitCast(b[3])); @@ -432,7 +430,7 @@ static inline std::string substr_wrapper(const std::string& str, std::size_t idx } public: // -- initialize symbol table -- -SymbolTableImpl symTable;// -- initialize record table -- +SymbolTable symTable;// -- initialize record table -- SpecializedRecordTable<0> recordTable{}; // -- Table: float_fact Own rel_1_float_fact = mk(); @@ -485,7 +483,7 @@ void runFunction(std::string inputDirectoryArg, // set default threads (in embedded mode) // if this is not set, and omp is used, the default omp setting of number of cores is used. #if defined(_OPENMP) - if (0 < getNumThreads()) { omp_set_num_threads(static_cast(getNumThreads())); } + if (0 < getNumThreads()) { omp_set_num_threads(getNumThreads()); } #endif signalHandler->set(); @@ -521,6 +519,10 @@ void runAll(std::string inputDirectoryArg = "", std::string outputDirectoryArg = } public: void printAll(std::string outputDirectoryArg = "") override { +try {std::map directiveMap({{"IO","file"},{"attributeNames","x"},{"auxArity","0"},{"name","float_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"x\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"f:float\"]}}"}}); +if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_1_float_fact); +} catch (std::exception& e) {std::cerr << e.what();exit(1);} try {std::map directiveMap({{"IO","file"},{"attributeNames","a\tb\tc\td"},{"auxArity","0"},{"name","large_record"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 4, \"params\": [\"a\", \"b\", \"c\", \"d\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 4, \"types\": [\"i:number\", \"i:number\", \"i:number\", \"i:number\"]}}"}}); if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_2_large_record); @@ -537,10 +539,6 @@ try {std::map directiveMap({{"IO","file"},{"attributeN if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_5_unsigned_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} -try {std::map directiveMap({{"IO","file"},{"attributeNames","x"},{"auxArity","0"},{"name","float_fact"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {}, \"relation\": {\"arity\": 1, \"params\": [\"x\"]}}"},{"types","{\"ADTs\": {}, \"records\": {}, \"relation\": {\"arity\": 1, \"types\": [\"f:float\"]}}"}}); -if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;} -IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_1_float_fact); -} catch (std::exception& e) {std::cerr << e.what();exit(1);} } public: void loadAll(std::string inputDirectoryArg = "") override { @@ -602,6 +600,12 @@ IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll( void dumpOutputs() override { try {std::map rwOperation; rwOperation["IO"] = "stdout"; +rwOperation["name"] = "float_fact"; +rwOperation["types"] = "{\"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"f:float\"]}}"; +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_1_float_fact); +} catch (std::exception& e) {std::cerr << e.what();exit(1);} +try {std::map rwOperation; +rwOperation["IO"] = "stdout"; rwOperation["name"] = "large_record"; rwOperation["types"] = "{\"relation\": {\"arity\": 4, \"auxArity\": 0, \"types\": [\"i:number\", \"i:number\", \"i:number\", \"i:number\"]}}"; IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_2_large_record); @@ -624,12 +628,6 @@ rwOperation["name"] = "unsigned_fact"; rwOperation["types"] = "{\"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"u:unsigned\"]}}"; IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_5_unsigned_fact); } catch (std::exception& e) {std::cerr << e.what();exit(1);} -try {std::map rwOperation; -rwOperation["IO"] = "stdout"; -rwOperation["name"] = "float_fact"; -rwOperation["types"] = "{\"relation\": {\"arity\": 1, \"auxArity\": 0, \"types\": [\"f:float\"]}}"; -IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_1_float_fact); -} catch (std::exception& e) {std::cerr << e.what();exit(1);} } public: SymbolTable& getSymbolTable() override {