LCOV - code coverage report
Current view: top level - src/backend - WasmOperator.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 9 312 2.9 %
Date: 2025-03-25 01:19:55 Functions: 5 336 1.5 %
Branches: 3 858 0.3 %

           Branch data     Line data    Source code
       1                 :            : #pragma once
       2                 :            : 
       3                 :            : #include "backend/WasmUtil.hpp"
       4                 :            : #include <mutable/IR/PhysicalOptimizer.hpp>
       5                 :            : #include <mutable/storage/DataLayoutFactory.hpp>
       6                 :            : #include <mutable/util/enum_ops.hpp>
       7                 :            : 
       8                 :            : 
       9                 :            : namespace m {
      10                 :            : 
      11                 :            : namespace wasm {
      12                 :            : 
      13                 :            : // forward declarations
      14                 :            : struct MatchBaseVisitor;
      15                 :            : struct ConstMatchBaseVisitor;
      16                 :            : 
      17                 :            : }
      18                 :            : 
      19                 :            : namespace option_configs {
      20                 :            : 
      21                 :            : /*----- algorithmic decisions ----------------------------------------------------------------------------------------*/
      22                 :            : enum class ScanImplementation : uint64_t {
      23                 :            :     ALL        = 0b11,
      24                 :            :     SCAN       = 0b01,
      25                 :            :     INDEX_SCAN = 0b10,
      26                 :            : };
      27                 :            : 
      28                 :            : enum class GroupingImplementation : uint64_t {
      29                 :            :     ALL        = 0b11,
      30                 :            :     HASH_BASED = 0b01,
      31                 :            :     ORDERED    = 0b10,
      32                 :            : };
      33                 :            : 
      34                 :            : enum class SortingImplementation : uint64_t {
      35                 :            :     ALL       = 0b11,
      36                 :            :     QUICKSORT = 0b01,
      37                 :            :     NOOP      = 0b10,
      38                 :            : };
      39                 :            : 
      40                 :            : enum class JoinImplementation : uint64_t {
      41                 :            :     ALL          = 0b111,
      42                 :            :     NESTED_LOOPS = 0b001,
      43                 :            :     SIMPLE_HASH  = 0b010,
      44                 :            :     SORT_MERGE   = 0b100,
      45                 :            : };
      46                 :            : 
      47                 :            : enum class IndexImplementation : uint64_t {
      48                 :            :     ALL   = 0b11,
      49                 :            :     ARRAY = 0b01,
      50                 :            :     RMI   = 0b10,
      51                 :            : };
      52                 :            : 
      53                 :            : enum class SoftPipelineBreakerStrategy : uint64_t {
      54                 :            :     AFTER_ALL                   = 0b1111111,
      55                 :            :     AFTER_SCAN                  = 0b0000001,
      56                 :            :     AFTER_FILTER                = 0b0000010,
      57                 :            :     AFTER_INDEX_SCAN            = 0b0000100,
      58                 :            :     AFTER_PROJECTION            = 0b0001000,
      59                 :            :     AFTER_NESTED_LOOPS_JOIN     = 0b0010000,
      60                 :            :     AFTER_SIMPLE_HASH_JOIN      = 0b0100000,
      61                 :            :     AFTER_HASH_BASED_GROUP_JOIN = 0b1000000,
      62                 :            :     NONE                        = 0b0000000,
      63                 :            : };
      64                 :            : 
      65                 :            : /*----- implementation decisions -------------------------------------------------------------------------------------*/
      66                 :            : enum class IndexScanStrategy : uint64_t {
      67                 :            :     COMPILATION    = 0b001,
      68                 :            :     INTERPRETATION = 0b010,
      69                 :            :     HYBRID         = 0b100,
      70                 :            : };
      71                 :            : 
      72                 :            : enum class IndexScanCompilationStrategy : uint64_t {
      73                 :            :     CALLBACK       = 0b01,
      74                 :            :     EXPOSED_MEMORY = 0b10,
      75                 :            : };
      76                 :            : 
      77                 :            : enum class IndexScanMaterializationStrategy : uint64_t {
      78                 :            :     INLINE = 0b01,
      79                 :            :     MEMORY = 0b10,
      80                 :            : };
      81                 :            : 
      82                 :            : enum class SelectionStrategy : uint64_t {
      83                 :            :     AUTO       = 0b11,
      84                 :            :     BRANCHING  = 0b01,
      85                 :            :     PREDICATED = 0b10,
      86                 :            : };
      87                 :            : 
      88                 :            : enum class HashTableImplementation : uint64_t {
      89                 :            :     ALL             = 0b11,
      90                 :            :     OPEN_ADDRESSING = 0b01,
      91                 :            :     CHAINED         = 0b10,
      92                 :            : };
      93                 :            : 
      94                 :            : enum class ProbingStrategy : uint64_t {
      95                 :            :     AUTO      = 0b11,
      96                 :            :     LINEAR    = 0b01,
      97                 :            :     QUADRATIC = 0b10,
      98                 :            : };
      99                 :            : 
     100                 :            : enum class StoringStrategy : uint64_t {
     101                 :            :     AUTO         = 0b11,
     102                 :            :     IN_PLACE     = 0b01,
     103                 :            :     OUT_OF_PLACE = 0b10,
     104                 :            : };
     105                 :            : 
     106                 :            : enum class OrderingStrategy : uint64_t {
     107                 :            :     AUTO           = 0b11,
     108                 :            :     BUILD_ON_LEFT  = 0b01,
     109                 :            :     BUILD_ON_RIGHT = 0b10,
     110                 :            : };
     111                 :            : 
     112                 :            : }
     113                 :            : 
     114                 :            : namespace options {
     115                 :            : 
     116                 :            : /*----- options ------------------------------------------------------------------------------------------------------*/
     117                 :            : /** Which implementations should be considered for a `ScanOperator`. */
     118                 :            : inline option_configs::ScanImplementation scan_implementations = option_configs::ScanImplementation::ALL;
     119                 :            : 
     120                 :            : /** Which implementations should be considered for a `GroupingOperator`. */
     121                 :            : inline option_configs::GroupingImplementation grouping_implementations = option_configs::GroupingImplementation::ALL;
     122                 :            : 
     123                 :            : /** Which implementations should be considered for a `SortingOperator`. */
     124                 :            : inline option_configs::SortingImplementation sorting_implementations = option_configs::SortingImplementation::ALL;
     125                 :            : 
     126                 :            : /** Which implementations should be considered for a `JoinOperator`. */
     127                 :            : inline option_configs::JoinImplementation join_implementations = option_configs::JoinImplementation::ALL;
     128                 :            : 
     129                 :            : /** Which index implementations should be considered for an `IndexScan`. */
     130                 :            : inline option_configs::IndexImplementation index_implementations = option_configs::IndexImplementation::ALL;
     131                 :            : 
     132                 :            : /** Which index scan strategy should be used for `wasm::IndexScan`. */
     133                 :            : inline option_configs::IndexScanStrategy index_scan_strategy = option_configs::IndexScanStrategy::INTERPRETATION;
     134                 :            : 
     135                 :            : /** Which compilation strategy should be used for `wasm::IndexScan`. */
     136                 :            : inline option_configs::IndexScanCompilationStrategy index_scan_compilation_strategy =
     137                 :            :     option_configs::IndexScanCompilationStrategy::CALLBACK;
     138                 :            : 
     139                 :            : /** Which materialization strategy should be used for `wasm::IndexScan`. */
     140                 :            : inline option_configs::IndexScanMaterializationStrategy index_scan_materialization_strategy =
     141                 :            :     option_configs::IndexScanMaterializationStrategy::MEMORY;
     142                 :            : 
     143                 :            : /** Which selection strategy should be used for `wasm::Filter`. */
     144                 :            : inline option_configs::SelectionStrategy filter_selection_strategy = option_configs::SelectionStrategy::AUTO;
     145                 :            : 
     146                 :            : /** Which selection strategy should be used for comparisons in `wasm::Quicksort`. */
     147                 :            : inline option_configs::SelectionStrategy quicksort_cmp_selection_strategy = option_configs::SelectionStrategy::AUTO;
     148                 :            : 
     149                 :            : /** Which selection strategy should be used for `wasm::NestedLoopsJoin`. */
     150                 :            : inline option_configs::SelectionStrategy nested_loops_join_selection_strategy = option_configs::SelectionStrategy::AUTO;
     151                 :            : 
     152                 :            : /** Which selection strategy should be used for `wasm::SimpleHashJoin`. */
     153                 :            : inline option_configs::SelectionStrategy simple_hash_join_selection_strategy = option_configs::SelectionStrategy::AUTO;
     154                 :            : 
     155                 :            : /** Which ordering strategy should be used for `wasm::SimpleHashJoin`. */
     156                 :            : inline option_configs::OrderingStrategy simple_hash_join_ordering_strategy = option_configs::OrderingStrategy::AUTO;
     157                 :            : 
     158                 :            : /** Which selection strategy should be used for `wasm::SortMergeJoin`. */
     159                 :            : inline option_configs::SelectionStrategy sort_merge_join_selection_strategy = option_configs::SelectionStrategy::AUTO;
     160                 :            : 
     161                 :            : /** Which selection strategy should be used for comparisons while sorting in `wasm::SortMergeJoin`. */
     162                 :            : inline option_configs::SelectionStrategy sort_merge_join_cmp_selection_strategy =
     163                 :            :     option_configs::SelectionStrategy::AUTO;
     164                 :            : 
     165                 :            : /** Which implementation should be used for `wasm::HashTable`s. */
     166                 :            : inline option_configs::HashTableImplementation hash_table_implementation = option_configs::HashTableImplementation::ALL;
     167                 :            : 
     168                 :            : /** Which probing strategy should be used for `wasm::OpenAddressingHashTable`s.  Does not have any effect if
     169                 :            :  * `wasm::ChainedHashTable`s are used. */
     170                 :            : inline option_configs::ProbingStrategy hash_table_probing_strategy = option_configs::ProbingStrategy::AUTO;
     171                 :            : 
     172                 :            : /** Which storing strategy should be used for `wasm::OpenAddressingHashTable`s.  Does not have any effect if
     173                 :            :  * `wasm::ChainedHashTable`s are used. */
     174                 :            : inline option_configs::StoringStrategy hash_table_storing_strategy = option_configs::StoringStrategy::AUTO;
     175                 :            : 
     176                 :            : /** Which maximal load factor should be used for `wasm::OpenAddressingHashTable`s.  Does not have any effect if
     177                 :            :  * `wasm::ChainedHashTable`s are used. */
     178                 :            : inline double load_factor_open_addressing = 0.8;
     179                 :            : 
     180                 :            : /** Which maximal load factor should be used for `wasm::ChainedHashTable`s.  Does not have any effect if
     181                 :            :  * `wasm::OpenAddressingHashTable`s are used. */
     182                 :            : inline double load_factor_chained = 1.5;
     183                 :            : 
     184                 :            : /** Which initial capacity should be used for `wasm::HashTable`s. */
     185                 :            : inline std::optional<uint32_t> hash_table_initial_capacity;
     186                 :            : 
     187                 :            : /** Whether to use `wasm::HashBasedGroupJoin` if possible. */
     188                 :            : inline bool hash_based_group_join = true;
     189                 :            : 
     190                 :            : /** Which layout factory should be used for hard pipeline breakers. */
     191                 :            : inline std::unique_ptr<const m::storage::DataLayoutFactory> hard_pipeline_breaker_layout =
     192                 :            :     std::make_unique<storage::RowLayoutFactory>();
     193                 :            : 
     194                 :            : /** Where soft pipeline breakers should be added. */
     195                 :            : inline option_configs::SoftPipelineBreakerStrategy soft_pipeline_breaker =
     196                 :            :     option_configs::SoftPipelineBreakerStrategy::NONE;
     197                 :            : 
     198                 :            : /** Which layout factory should be used for soft pipeline breakers. */
     199                 :            : inline std::unique_ptr<const m::storage::DataLayoutFactory> soft_pipeline_breaker_layout =
     200                 :            :     std::make_unique<storage::RowLayoutFactory>();
     201                 :            : 
     202                 :            : /** Which size in tuples should be used for soft pipeline breakers. */
     203                 :            : inline std::size_t soft_pipeline_breaker_num_tuples = 0;
     204                 :            : 
     205                 :            : /** The number of results from index sequential scan to be communicated between host and v8 per batch.  0 means that
     206                 :            :  * all results are communicated in a single batch. */
     207                 :            : inline std::size_t index_sequential_scan_batch_size = 1;
     208                 :            : 
     209                 :            : /** Which window size should be used for the result set. */
     210                 :            : inline std::size_t result_set_window_size = 0;
     211                 :            : 
     212                 :            : /** Whether to exploit uniqueness of build key in hash joins. */
     213                 :            : inline bool exploit_unique_build = true;
     214                 :            : 
     215                 :            : /** Whether to use SIMDfication. */
     216                 :            : inline bool simd = true;
     217                 :            : 
     218                 :            : /** Whether to use double pumping if SIMDfication is enabled. */
     219                 :            : inline bool double_pumping = true;
     220                 :            : 
     221                 :            : /** Which number of SIMD lanes to prefer. */
     222                 :            : inline std::size_t simd_lanes = 1;
     223                 :            : 
     224                 :            : /** Which attributes are assumed to be sorted.  For each entry, the first element is the name of the attribute and the
     225                 :            :  * second one is `true` iff the attribute is sorted ascending and vice versa. */
     226                 :            : inline std::vector<std::pair<m::Schema::Identifier, bool>> sorted_attributes;
     227                 :            : 
     228                 :            : }
     229                 :            : 
     230                 :            : }
     231                 :            : 
     232                 :            : namespace m {
     233                 :            : 
     234                 :            : #define M_WASM_OPERATOR_LIST_NON_TEMPLATED(X) \
     235                 :            :     X(NoOp) \
     236                 :            :     X(LazyDisjunctiveFilter) \
     237                 :            :     X(Projection) \
     238                 :            :     X(HashBasedGrouping) \
     239                 :            :     X(OrderedGrouping) \
     240                 :            :     X(Aggregation) \
     241                 :            :     X(NoOpSorting) \
     242                 :            :     X(Limit) \
     243                 :            :     X(HashBasedGroupJoin)
     244                 :            : #define M_WASM_OPERATOR_LIST_TEMPLATED(X) \
     245                 :            :     X(Callback<false>) \
     246                 :            :     X(Callback<true>) \
     247                 :            :     X(Print<false>) \
     248                 :            :     X(Print<true>) \
     249                 :            :     X(Scan<false>) \
     250                 :            :     X(Scan<true>) \
     251                 :            :     X(IndexScan<m::idx::IndexMethod::Array>) \
     252                 :            :     X(IndexScan<m::idx::IndexMethod::Rmi>) \
     253                 :            :     X(Filter<false>) \
     254                 :            :     X(Filter<true>) \
     255                 :            :     X(Quicksort<false>) \
     256                 :            :     X(Quicksort<true>) \
     257                 :            :     X(NestedLoopsJoin<false>) \
     258                 :            :     X(NestedLoopsJoin<true>) \
     259                 :            :     X(SimpleHashJoin<M_COMMA(false) false>) \
     260                 :            :     X(SimpleHashJoin<M_COMMA(false) true>) \
     261                 :            :     X(SimpleHashJoin<M_COMMA(true) false>) \
     262                 :            :     X(SimpleHashJoin<M_COMMA(true) true>) \
     263                 :            :     X(SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(false) false>) \
     264                 :            :     X(SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(false) true>) \
     265                 :            :     X(SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(true)  false>) \
     266                 :            :     X(SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(true)  true>) \
     267                 :            :     X(SortMergeJoin<M_COMMA(false) M_COMMA(true)  M_COMMA(false) false>) \
     268                 :            :     X(SortMergeJoin<M_COMMA(false) M_COMMA(true)  M_COMMA(false) true>) \
     269                 :            :     X(SortMergeJoin<M_COMMA(false) M_COMMA(true)  M_COMMA(true)  false>) \
     270                 :            :     X(SortMergeJoin<M_COMMA(false) M_COMMA(true)  M_COMMA(true)  true>) \
     271                 :            :     X(SortMergeJoin<M_COMMA(true)  M_COMMA(false) M_COMMA(false) false>) \
     272                 :            :     X(SortMergeJoin<M_COMMA(true)  M_COMMA(false) M_COMMA(false) true>) \
     273                 :            :     X(SortMergeJoin<M_COMMA(true)  M_COMMA(false) M_COMMA(true)  false>) \
     274                 :            :     X(SortMergeJoin<M_COMMA(true)  M_COMMA(false) M_COMMA(true)  true>) \
     275                 :            :     X(SortMergeJoin<M_COMMA(true)  M_COMMA(true)  M_COMMA(false) false>) \
     276                 :            :     X(SortMergeJoin<M_COMMA(true)  M_COMMA(true)  M_COMMA(false) true>) \
     277                 :            :     X(SortMergeJoin<M_COMMA(true)  M_COMMA(true)  M_COMMA(true)  false>) \
     278                 :            :     X(SortMergeJoin<M_COMMA(true)  M_COMMA(true)  M_COMMA(true)  true>)
     279                 :            : #define M_WASM_OPERATOR_LIST(X) \
     280                 :            :     M_WASM_OPERATOR_LIST_NON_TEMPLATED(X) \
     281                 :            :     M_WASM_OPERATOR_LIST_TEMPLATED(X)
     282                 :            : 
     283                 :            : 
     284                 :            : #define MAKE_WASM_MATCH_(OP) m::Match<m::wasm::OP>
     285                 :            : #define M_WASM_MATCH_LIST_NON_TEMPLATED(X) M_TRANSFORM_X_MACRO(X, M_WASM_OPERATOR_LIST_NON_TEMPLATED, MAKE_WASM_MATCH_)
     286                 :            : #define M_WASM_MATCH_LIST_TEMPLATED(X) \
     287                 :            :     X(m::Match<m::wasm::Callback<false>>) \
     288                 :            :     X(m::Match<m::wasm::Callback<true>>) \
     289                 :            :     X(m::Match<m::wasm::Print<false>>) \
     290                 :            :     X(m::Match<m::wasm::Print<true>>) \
     291                 :            :     X(m::Match<m::wasm::Scan<false>>) \
     292                 :            :     X(m::Match<m::wasm::Scan<true>>) \
     293                 :            :     X(m::Match<m::wasm::IndexScan<m::idx::IndexMethod::Array>>) \
     294                 :            :     X(m::Match<m::wasm::IndexScan<m::idx::IndexMethod::Rmi>>) \
     295                 :            :     X(m::Match<m::wasm::Filter<false>>) \
     296                 :            :     X(m::Match<m::wasm::Filter<true>>) \
     297                 :            :     X(m::Match<m::wasm::Quicksort<false>>) \
     298                 :            :     X(m::Match<m::wasm::Quicksort<true>>) \
     299                 :            :     X(m::Match<m::wasm::NestedLoopsJoin<false>>) \
     300                 :            :     X(m::Match<m::wasm::NestedLoopsJoin<true>>) \
     301                 :            :     X(m::Match<m::wasm::SimpleHashJoin<M_COMMA(false) false>>) \
     302                 :            :     X(m::Match<m::wasm::SimpleHashJoin<M_COMMA(false) true>>) \
     303                 :            :     X(m::Match<m::wasm::SimpleHashJoin<M_COMMA(true) false>>) \
     304                 :            :     X(m::Match<m::wasm::SimpleHashJoin<M_COMMA(true) true>>) \
     305                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(false) false>>) \
     306                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(false) true>>) \
     307                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(true)  false>>) \
     308                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(false) M_COMMA(true)  true>>) \
     309                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(true)  M_COMMA(false) false>>) \
     310                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(true)  M_COMMA(false) true>>) \
     311                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(true)  M_COMMA(true)  false>>) \
     312                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(false) M_COMMA(true)  M_COMMA(true)  true>>) \
     313                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true)  M_COMMA(false) M_COMMA(false) false>>) \
     314                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true)  M_COMMA(false) M_COMMA(false) true>>) \
     315                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true)  M_COMMA(false) M_COMMA(true)  false>>) \
     316                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true)  M_COMMA(false) M_COMMA(true)  true>>) \
     317                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true)  M_COMMA(true)  M_COMMA(false) false>>) \
     318                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true)  M_COMMA(true)  M_COMMA(false) true>>) \
     319                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true)  M_COMMA(true)  M_COMMA(true)  false>>) \
     320                 :            :     X(m::Match<m::wasm::SortMergeJoin<M_COMMA(true)  M_COMMA(true)  M_COMMA(true)  true>>)
     321                 :            : #define M_WASM_MATCH_LIST(X) \
     322                 :            :     M_WASM_MATCH_LIST_NON_TEMPLATED(X) \
     323                 :            :     M_WASM_MATCH_LIST_TEMPLATED(X)
     324                 :            : 
     325                 :            : // forward declarations
     326                 :            : #define DECLARE(OP) \
     327                 :            :     namespace wasm { struct OP; } \
     328                 :            :     template<> struct Match<wasm::OP>;
     329                 :            :     M_WASM_OPERATOR_LIST_NON_TEMPLATED(DECLARE)
     330                 :            : #undef DECLARE
     331                 :            : 
     332                 :            : namespace wasm { template<bool SIMDfied> struct Callback; }
     333                 :            : template<bool SIMDfied> struct Match<wasm::Callback<SIMDfied>>;
     334                 :            : 
     335                 :            : namespace wasm { template<bool SIMDfied> struct Print; }
     336                 :            : template<bool SIMDfied> struct Match<wasm::Print<SIMDfied>>;
     337                 :            : 
     338                 :            : namespace wasm { template<bool SIMDfied> struct Scan; }
     339                 :            : template<bool SIMDfied> struct Match<wasm::Scan<SIMDfied>>;
     340                 :            : 
     341                 :            : namespace wasm { template<idx::IndexMethod IndexMethod> struct IndexScan; }
     342                 :            : template<idx::IndexMethod IndexMethod> struct Match<wasm::IndexScan<IndexMethod>>;
     343                 :            : 
     344                 :            : namespace wasm { template<bool Predicated> struct Filter; }
     345                 :            : template<bool Predicated> struct Match<wasm::Filter<Predicated>>;
     346                 :            : 
     347                 :            : namespace wasm { template<bool CmpPredicated> struct Quicksort; }
     348                 :            : template<bool CmpPredicated> struct Match<wasm::Quicksort<CmpPredicated>>;
     349                 :            : 
     350                 :            : namespace wasm { template<bool Predicated> struct NestedLoopsJoin; }
     351                 :            : template<bool Predicated> struct Match<wasm::NestedLoopsJoin<Predicated>>;
     352                 :            : 
     353                 :            : namespace wasm { template<bool UniqueBuild, bool Predicated> struct SimpleHashJoin; }
     354                 :            : template<bool UniqueBuild, bool Predicated> struct Match<wasm::SimpleHashJoin<UniqueBuild, Predicated>>;
     355                 :            : 
     356                 :            : namespace wasm { template<bool SortLeft, bool SortRight, bool Predicated, bool CmpPredicated> struct SortMergeJoin; }
     357                 :            : template<bool SortLeft, bool SortRight, bool Predicated, bool CmpPredicated>
     358                 :            : struct Match<wasm::SortMergeJoin<SortLeft, SortRight, Predicated, CmpPredicated>>;
     359                 :            : 
     360                 :            : 
     361                 :            : namespace wasm {
     362                 :            : 
     363                 :            : struct NoOp : PhysicalOperator<NoOp, NoOpOperator>
     364                 :            : {
     365                 :            :     static void execute(const Match<NoOp> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     366                 :          0 :     static double cost(const Match<NoOp>&) { return 1.0; }
     367                 :            : };
     368                 :            : 
     369                 :            : template<bool SIMDfied>
     370                 :            : struct Callback : PhysicalOperator<Callback<SIMDfied>, CallbackOperator>
     371                 :            : {
     372                 :            :     static void execute(const Match<Callback> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     373                 :          0 :     static double cost(const Match<Callback>&) { return 1.0; }
     374                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     375                 :            :                                       const std::tuple<const CallbackOperator*> &partial_inner_nodes);
     376                 :            : };
     377                 :            : 
     378                 :            : template<bool SIMDfied>
     379                 :            : struct Print : PhysicalOperator<Print<SIMDfied>, PrintOperator>
     380                 :            : {
     381                 :            :     static void execute(const Match<Print> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     382                 :          0 :     static double cost(const Match<Print>&) { return 1.0; }
     383                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     384                 :            :                                       const std::tuple<const PrintOperator*> &partial_inner_nodes);
     385                 :            : };
     386                 :            : 
     387                 :            : template<bool SIMDfied>
     388                 :            : struct Scan : PhysicalOperator<Scan<SIMDfied>, ScanOperator>
     389                 :            : {
     390                 :            :     static void execute(const Match<Scan> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     391                 :          0 :     static double cost(const Match<Scan>&) { return M_CONSTEXPR_COND(SIMDfied, 1.0, 2.0); }
     392                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     393                 :            :                                       const std::tuple<const ScanOperator*> &partial_inner_nodes);
     394                 :            :     static ConditionSet post_condition(const Match<Scan> &M);
     395                 :            : };
     396                 :            : 
     397                 :            : template<idx::IndexMethod IndexMethod>
     398                 :            : struct IndexScan : PhysicalOperator<IndexScan<IndexMethod>, pattern_t<FilterOperator, ScanOperator>>
     399                 :            : {
     400                 :            :     static void execute(const Match<IndexScan> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     401                 :            :     static double cost(const Match<IndexScan> &M);
     402                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     403                 :            :                                       const std::tuple<const FilterOperator*, const ScanOperator*> &partial_inner_nodes);
     404                 :            :     static ConditionSet post_condition(const Match<IndexScan> &M);
     405                 :            : };
     406                 :            : 
     407                 :            : template<bool Predicated>
     408                 :            : struct Filter : PhysicalOperator<Filter<Predicated>, FilterOperator>
     409                 :            : {
     410                 :            :     static void execute(const Match<Filter> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     411                 :            :     static double cost(const Match<Filter>&);
     412                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     413                 :            :                                       const std::tuple<const FilterOperator*> &partial_inner_nodes);
     414                 :            :     static ConditionSet adapt_post_condition(const Match<Filter> &M, const ConditionSet &post_cond_child);
     415                 :            : };
     416                 :            : 
     417                 :            : struct LazyDisjunctiveFilter : PhysicalOperator<LazyDisjunctiveFilter, DisjunctiveFilterOperator>
     418                 :            : {
     419                 :            :     static void execute(const Match<LazyDisjunctiveFilter> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     420                 :            :     static double cost(const Match<LazyDisjunctiveFilter> &M);
     421                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     422                 :            :                                       const std::tuple<const FilterOperator*> &partial_inner_nodes);
     423                 :            : };
     424                 :            : 
     425                 :            : struct Projection : PhysicalOperator<Projection, ProjectionOperator>
     426                 :            : {
     427                 :            :     static void execute(const Match<Projection> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     428                 :          0 :     static double cost(const Match<Projection>&) { return 1.0; }
     429                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     430                 :            :                                       const std::tuple<const ProjectionOperator*> &partial_inner_nodes);
     431                 :            :     static ConditionSet adapt_post_condition(const Match<Projection> &M, const ConditionSet &post_cond_child);
     432                 :            : };
     433                 :            : 
     434                 :            : struct HashBasedGrouping : PhysicalOperator<HashBasedGrouping, GroupingOperator>
     435                 :            : {
     436                 :            :     static void execute(const Match<HashBasedGrouping> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     437                 :            :     static double cost(const Match<HashBasedGrouping>&);
     438                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     439                 :            :                                       const std::tuple<const GroupingOperator*> &partial_inner_nodes);
     440                 :            :     static ConditionSet post_condition(const Match<HashBasedGrouping> &M);
     441                 :            : };
     442                 :            : 
     443                 :            : struct OrderedGrouping : PhysicalOperator<OrderedGrouping, GroupingOperator>
     444                 :            : {
     445                 :            :     private:
     446                 :            :     template<bool IsGlobal, typename T>
     447                 :            :     using var_t_ = std::conditional_t<IsGlobal, Global<T>, Var<T>>;
     448                 :            :     template<bool IsGlobal>
     449                 :            :     using agg_t_ = std::variant<
     450                 :            :         var_t_<IsGlobal, I64x1>,
     451                 :            :         std::pair<var_t_<IsGlobal, I8x1>,     std::optional<var_t_<IsGlobal, Boolx1>>>,
     452                 :            :         std::pair<var_t_<IsGlobal, I16x1>,    std::optional<var_t_<IsGlobal, Boolx1>>>,
     453                 :            :         std::pair<var_t_<IsGlobal, I32x1>,    std::optional<var_t_<IsGlobal, Boolx1>>>,
     454                 :            :         std::pair<var_t_<IsGlobal, I64x1>,    std::optional<var_t_<IsGlobal, Boolx1>>>,
     455                 :            :         std::pair<var_t_<IsGlobal, Floatx1>,  std::optional<var_t_<IsGlobal, Boolx1>>>,
     456                 :            :         std::pair<var_t_<IsGlobal, Doublex1>, std::optional<var_t_<IsGlobal, Boolx1>>>
     457                 :            :     >;
     458                 :            :     template<bool IsGlobal>
     459                 :            :     using key_t_ = std::variant<
     460                 :            :         var_t_<IsGlobal, Ptr<Charx1>>,
     461                 :            :         std::pair<var_t_<IsGlobal, Boolx1>,      std::optional<var_t_<IsGlobal, Boolx1>>>,
     462                 :            :         std::pair<var_t_<IsGlobal, I8x1>,        std::optional<var_t_<IsGlobal, Boolx1>>>,
     463                 :            :         std::pair<var_t_<IsGlobal, I16x1>,       std::optional<var_t_<IsGlobal, Boolx1>>>,
     464                 :            :         std::pair<var_t_<IsGlobal, I32x1>,       std::optional<var_t_<IsGlobal, Boolx1>>>,
     465                 :            :         std::pair<var_t_<IsGlobal, I64x1>,       std::optional<var_t_<IsGlobal, Boolx1>>>,
     466                 :            :         std::pair<var_t_<IsGlobal, Floatx1>,     std::optional<var_t_<IsGlobal, Boolx1>>>,
     467                 :            :         std::pair<var_t_<IsGlobal, Doublex1>,    std::optional<var_t_<IsGlobal, Boolx1>>>
     468                 :            :     >;
     469                 :            : 
     470                 :            :     public:
     471                 :            :     static void execute(const Match<OrderedGrouping> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     472                 :            :     static double cost(const Match<OrderedGrouping>&);
     473                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     474                 :            :                                       const std::tuple<const GroupingOperator*> &partial_inner_nodes);
     475                 :            :     static ConditionSet adapt_post_condition(const Match<OrderedGrouping> &M, const ConditionSet &post_cond_child);
     476                 :            : };
     477                 :            : 
     478                 :            : struct Aggregation : PhysicalOperator<Aggregation, AggregationOperator>
     479                 :            : {
     480                 :            :     private:
     481                 :            :     template<bool IsGlobal, typename T>
     482                 :            :     using var_t_ = std::conditional_t<IsGlobal, Global<T>, Var<T>>;
     483                 :            :     template<bool IsGlobal, std::size_t L>
     484                 :            :     using agg_t_ = std::variant<
     485                 :            :         var_t_<IsGlobal, I64<L>>,
     486                 :            :         std::pair<var_t_<IsGlobal, I8<L>>,     var_t_<IsGlobal, Bool<L>>>,
     487                 :            :         std::pair<var_t_<IsGlobal, I16<L>>,    var_t_<IsGlobal, Bool<L>>>,
     488                 :            :         std::pair<var_t_<IsGlobal, I32<L>>,    var_t_<IsGlobal, Bool<L>>>,
     489                 :            :         std::pair<var_t_<IsGlobal, I64<L>>,    var_t_<IsGlobal, Bool<L>>>,
     490                 :            :         std::pair<var_t_<IsGlobal, Float<L>>,  var_t_<IsGlobal, Bool<L>>>,
     491                 :            :         std::pair<var_t_<IsGlobal, Double<L>>, var_t_<IsGlobal, Bool<L>>>
     492                 :            :     >;
     493                 :            : 
     494                 :            :     public:
     495                 :            :     static void execute(const Match<Aggregation> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     496                 :          0 :     static double cost(const Match<Aggregation>&) { return 1.0; }
     497                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     498                 :            :                                       const std::tuple<const AggregationOperator*> &partial_inner_nodes);
     499                 :            :     static ConditionSet post_condition(const Match<Aggregation> &M);
     500                 :            : };
     501                 :            : 
     502                 :            : template<bool CmpPredicated>
     503                 :            : struct Quicksort : PhysicalOperator<Quicksort<CmpPredicated>, SortingOperator>
     504                 :            : {
     505                 :            :     static void execute(const Match<Quicksort> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     506                 :          0 :     static double cost(const Match<Quicksort>&) { return M_CONSTEXPR_COND(CmpPredicated, 1.0, 1.1); }
     507                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     508                 :            :                                       const std::tuple<const SortingOperator*> &partial_inner_nodes);
     509                 :            :     static ConditionSet post_condition(const Match<Quicksort> &M);
     510                 :            : };
     511                 :            : 
     512                 :            : struct NoOpSorting : PhysicalOperator<NoOpSorting, SortingOperator>
     513                 :            : {
     514                 :            :     static void execute(const Match<NoOpSorting> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     515                 :          0 :     static double cost(const Match<NoOpSorting>&) { return 0.0; }
     516                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     517                 :            :                                       const std::tuple<const SortingOperator*> &partial_inner_nodes);
     518                 :            : };
     519                 :            : 
     520                 :            : template<bool Predicated>
     521                 :            : struct NestedLoopsJoin : PhysicalOperator<NestedLoopsJoin<Predicated>, JoinOperator>
     522                 :            : {
     523                 :            :     static void execute(const Match<NestedLoopsJoin> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     524                 :            :     static double cost(const Match<NestedLoopsJoin> &M);
     525                 :            :     static ConditionSet pre_condition(std::size_t child_idx, const std::tuple<const JoinOperator*> &partial_inner_nodes);
     526                 :            :     static ConditionSet
     527                 :            :     adapt_post_conditions(const Match<NestedLoopsJoin> &M,
     528                 :            :                           std::vector<std::reference_wrapper<const ConditionSet>> &&post_cond_children);
     529                 :            : };
     530                 :            : 
     531                 :            : template<bool UniqueBuild, bool Predicated>
     532                 :            : struct SimpleHashJoin
     533                 :            :     : PhysicalOperator<SimpleHashJoin<UniqueBuild, Predicated>, pattern_t<JoinOperator, Wildcard, Wildcard>>
     534                 :            : {
     535                 :            :     static void execute(const Match<SimpleHashJoin> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     536                 :            :     static double cost(const Match<SimpleHashJoin> &M);
     537                 :            :     static ConditionSet
     538                 :            :     pre_condition(std::size_t child_idx,
     539                 :            :                   const std::tuple<const JoinOperator*, const Wildcard*, const Wildcard*> &partial_inner_nodes);
     540                 :            :     static ConditionSet
     541                 :            :     adapt_post_conditions(const Match<SimpleHashJoin> &M,
     542                 :            :                           std::vector<std::reference_wrapper<const ConditionSet>> &&post_cond_children);
     543                 :            : };
     544                 :            : 
     545                 :            : template<bool SortLeft, bool SortRight, bool Predicated, bool CmpPredicated>
     546                 :            : struct SortMergeJoin
     547                 :            :     : PhysicalOperator<SortMergeJoin<SortLeft, SortRight, Predicated, CmpPredicated>,
     548                 :            :                        pattern_t<JoinOperator, Wildcard, Wildcard>>
     549                 :            : {
     550                 :            :     static void execute(const Match<SortMergeJoin> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     551                 :            :     static double cost(const Match<SortMergeJoin> &M);
     552                 :            :     static ConditionSet
     553                 :            :     pre_condition(std::size_t child_idx,
     554                 :            :                   const std::tuple<const JoinOperator*, const Wildcard*, const Wildcard*> &partial_inner_nodes);
     555                 :            :     static ConditionSet
     556                 :            :     adapt_post_conditions(const Match<SortMergeJoin> &M,
     557                 :            :                           std::vector<std::reference_wrapper<const ConditionSet>> &&post_cond_children);
     558                 :            : };
     559                 :            : 
     560                 :            : struct Limit : PhysicalOperator<Limit, LimitOperator>
     561                 :            : {
     562                 :            :     static void execute(const Match<Limit> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     563                 :          0 :     static double cost(const Match<Limit>&) { return 1.0; }
     564                 :            :     static ConditionSet pre_condition(std::size_t child_idx,
     565                 :            :                                       const std::tuple<const LimitOperator*> &partial_inner_nodes);
     566                 :            : };
     567                 :            : 
     568                 :            : struct HashBasedGroupJoin
     569                 :            :     : PhysicalOperator<HashBasedGroupJoin, pattern_t<GroupingOperator, pattern_t<JoinOperator, Wildcard, Wildcard>>>
     570                 :            : {
     571                 :            :     static void execute(const Match<HashBasedGroupJoin> &M, setup_t setup, pipeline_t pipeline, teardown_t teardown);
     572                 :            :     static double cost(const Match<HashBasedGroupJoin>&);
     573                 :            :     static ConditionSet
     574                 :            :     pre_condition(std::size_t child_idx,
     575                 :            :                   const std::tuple<const GroupingOperator*, const JoinOperator*, const Wildcard*, const Wildcard*>
     576                 :            :                       &partial_inner_nodes);
     577                 :            :     static ConditionSet post_condition(const Match<HashBasedGroupJoin> &M);
     578                 :            : };
     579                 :            : 
     580                 :            : }
     581                 :            : 
     582                 :            : /** Registers physical Wasm operators in \p phys_opt depending on the set CLI options. */
     583                 :            : void register_wasm_operators(PhysicalOptimizer &phys_opt);
     584                 :            : 
     585                 :            : template<typename T>
     586                 :          0 : void execute_buffered(const Match<T> &M, const Schema &schema,
     587                 :            :                       const std::unique_ptr<const storage::DataLayoutFactory> &buffer_factory,
     588                 :            :                       std::size_t buffer_num_tuples, setup_t setup, pipeline_t pipeline, teardown_t teardown)
     589                 :            : {
     590   [ #  #  #  #  :          0 :     if (buffer_factory) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     591   [ #  #  #  #  :          0 :         auto buffer_schema = schema.drop_constants().deduplicate();
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     592   [ #  #  #  #  :          0 :         if (buffer_schema.num_entries()) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     593                 :            :             /* Use global buffer since own operator may be executed partially in multiple function calls. */
     594   [ #  #  #  #  :          0 :             wasm::GlobalBuffer buffer(buffer_schema, *buffer_factory, wasm::CodeGenContext::Get().num_simd_lanes() > 1,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     595                 :          0 :                                       buffer_num_tuples, std::move(setup), std::move(pipeline), std::move(teardown));
     596   [ #  #  #  #  :          0 :             T::execute(
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     597                 :          0 :                 /* M=        */ M,
     598   [ #  #  #  #  :          0 :                 /* setup=    */ setup_t::Make_Without_Parent([&buffer](){ buffer.setup(); }),
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     599                 :          0 :                 /* pipeline= */ [&buffer](){ buffer.consume(); },
     600   [ #  #  #  #  :          0 :                 /* teardown= */ teardown_t::Make_Without_Parent([&buffer](){ buffer.teardown(); })
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     601                 :            :             );
     602   [ #  #  #  #  :          0 :             buffer.resume_pipeline();
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     603                 :          0 :         } else {
     604   [ #  #  #  #  :          0 :             T::execute(M, std::move(setup), std::move(pipeline), std::move(teardown));
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     605                 :            :         }
     606                 :          0 :     } else {
     607   [ #  #  #  #  :          0 :         T::execute(M, std::move(setup), std::move(pipeline), std::move(teardown));
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     608                 :            :     }
     609                 :          0 : }
     610                 :            : 
     611                 :            : namespace wasm {
     612                 :            : 
     613                 :            : /** An abstract `MatchBase` for the `WasmV8` backend.  Adds accept methods for respective visitor.  */
     614                 :            : struct MatchBase : m::MatchBase
     615                 :            : {
     616                 :            :     virtual void accept(MatchBaseVisitor &v) = 0;
     617                 :            :     virtual void accept(ConstMatchBaseVisitor &v) const = 0;
     618                 :            : };
     619                 :            : 
     620                 :            : /** Intermediate match type for leaves, i.e. physical operator matches without children. */
     621                 :            : struct MatchLeaf : wasm::MatchBase { };
     622                 :            : /** Intermediate match type for physical operator matches with a single child. */
     623                 :            : struct MatchSingleChild : wasm::MatchBase
     624                 :            : {
     625                 :            :     unsharable_shared_ptr<const wasm::MatchBase> child;
     626                 :            : 
     627                 :          0 :     MatchSingleChild(std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     628         [ #  # ]:          0 :         : child(as<const wasm::MatchBase>(std::move(children[0])))
     629                 :          0 :     {
     630         [ #  # ]:          0 :         M_insist(children.size() == 1);
     631                 :          0 :     }
     632                 :            : };
     633                 :            : /** Intermediate match type for physical operator matches with multiple children. */
     634                 :            : struct MatchMultipleChildren : wasm::MatchBase
     635                 :            : {
     636                 :            :     std::vector<unsharable_shared_ptr<const wasm::MatchBase>> children;
     637                 :            : 
     638                 :          0 :     MatchMultipleChildren(std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     639         [ #  # ]:          0 :         : children([&children](){
     640                 :          0 :             std::vector<unsharable_shared_ptr<const wasm::MatchBase>> res;
     641         [ #  # ]:          0 :             for (auto &c : children)
     642   [ #  #  #  # ]:          0 :                 res.push_back(as<const wasm::MatchBase>(std::move(c)));
     643                 :          0 :             return res;
     644         [ #  # ]:          0 :         }())
     645                 :          0 :     {
     646         [ #  # ]:          0 :         M_insist(children.size() >= 2);
     647                 :          0 :     }
     648                 :            : };
     649                 :            : 
     650                 :            : };
     651                 :            : 
     652                 :            : template<>
     653                 :            : struct Match<wasm::NoOp> : wasm::MatchSingleChild
     654                 :            : {
     655                 :            :     const NoOpOperator &noop;
     656                 :            : 
     657                 :          0 :     Match(const NoOpOperator *noop, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     658                 :          0 :         : wasm::MatchSingleChild(std::move(children))
     659                 :          0 :         , noop(*noop)
     660                 :          0 :     { }
     661                 :            : 
     662                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     663         [ #  # ]:          0 :         wasm::NoOp::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
     664                 :          0 :     }
     665                 :            : 
     666                 :          0 :     const Operator & get_matched_root() const override { return noop; }
     667                 :            : 
     668                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     669                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     670                 :            : 
     671                 :            :     protected:
     672                 :            :     void print(std::ostream &out, unsigned level) const override;
     673                 :            : };
     674                 :            : 
     675                 :            : template<bool SIMDfied>
     676                 :            : struct Match<wasm::Callback<SIMDfied>> : wasm::MatchSingleChild
     677                 :            : {
     678                 :            :     const CallbackOperator &callback;
     679                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> result_set_factory =
     680   [ #  #  #  #  :          0 :         M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
             #  #  #  # ]
     681                 :          0 :     std::size_t result_set_window_size = options::result_set_window_size;
     682                 :            : 
     683                 :          0 :     Match(const CallbackOperator *callback, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     684                 :          0 :         : wasm::MatchSingleChild(std::move(children))
     685                 :          0 :         , callback(*callback)
     686                 :          0 :     { }
     687                 :            : 
     688                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     689   [ #  #  #  # ]:          0 :         wasm::Callback<SIMDfied>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
     690                 :          0 :     }
     691                 :            : 
     692                 :          0 :     const Operator & get_matched_root() const override { return callback; }
     693                 :            : 
     694                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     695                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     696                 :            : 
     697                 :            :     protected:
     698                 :            :     void print(std::ostream &out, unsigned level) const override;
     699                 :            : };
     700                 :            : 
     701                 :            : template<bool SIMDfied>
     702                 :            : struct Match<wasm::Print<SIMDfied>> : wasm::MatchSingleChild
     703                 :            : {
     704                 :            :     const PrintOperator &print_op;
     705                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> result_set_factory =
     706   [ #  #  #  #  :          0 :         M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
             #  #  #  # ]
     707                 :          0 :     std::size_t result_set_window_size = options::result_set_window_size;
     708                 :            : 
     709                 :          0 :     Match(const PrintOperator *print, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     710                 :          0 :         : wasm::MatchSingleChild(std::move(children))
     711                 :          0 :         , print_op(*print)
     712                 :          0 :     { }
     713                 :            : 
     714                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     715   [ #  #  #  # ]:          0 :         wasm::Print<SIMDfied>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
     716                 :          0 :     }
     717                 :            : 
     718                 :          0 :     const Operator & get_matched_root() const override { return print_op; }
     719                 :            : 
     720                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     721                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     722                 :            : 
     723                 :            :     protected:
     724                 :            :     void print(std::ostream &out, unsigned level) const override;
     725                 :            : };
     726                 :            : 
     727                 :            : template<bool SIMDfied>
     728                 :            : struct Match<wasm::Scan<SIMDfied>> : wasm::MatchLeaf
     729                 :            : {
     730                 :            :     const ScanOperator &scan;
     731                 :            :     private:
     732                 :         10 :     std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
     733   [ +  -  -  +  :         10 :         bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_SCAN)
             #  #  #  # ]
     734   [ #  #  #  #  :          0 :             ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
             #  #  #  # ]
     735                 :         10 :             : std::unique_ptr<storage::DataLayoutFactory>();
     736                 :         10 :     std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
     737                 :            : 
     738                 :            :     public:
     739                 :         10 :     Match(const ScanOperator *scan, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     740                 :         10 :         : scan(*scan)
     741                 :         10 :     {
     742   [ -  +  #  # ]:         10 :         M_insist(children.empty());
     743                 :         10 :     }
     744                 :            : 
     745                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     746   [ #  #  #  # ]:          0 :         if (buffer_factory_) {
     747   [ #  #  #  # ]:          0 :             auto buffer_schema = scan.schema().drop_constants().deduplicate();
     748   [ #  #  #  #  :          0 :             if (buffer_schema.num_entries()) {
             #  #  #  # ]
     749                 :            :                 /* Use local buffer since scan loop will not be executed partially in multiple function calls. */
     750   [ #  #  #  #  :          0 :                 wasm::LocalBuffer buffer(buffer_schema, *buffer_factory_, SIMDfied or options::simd, buffer_num_tuples_,
             #  #  #  # ]
     751                 :          0 :                                          std::move(setup), std::move(pipeline), std::move(teardown));
     752   [ #  #  #  # ]:          0 :                 wasm::Scan<SIMDfied>::execute(
     753                 :            :                     /* M=        */ *this,
     754   [ #  #  #  # ]:          0 :                     /* setup=    */ setup_t::Make_Without_Parent([&buffer](){ buffer.setup(); }),
     755                 :          0 :                     /* pipeline= */ [&buffer](){ buffer.consume(); },
     756   [ #  #  #  # ]:          0 :                     /* teardown= */ teardown_t::Make_Without_Parent([&buffer](){
     757                 :          0 :                         buffer.resume_pipeline(); // must be placed before teardown method for local buffers
     758                 :          0 :                         buffer.teardown();
     759                 :          0 :                     })
     760                 :            :                 );
     761                 :          0 :             } else {
     762   [ #  #  #  # ]:          0 :                 wasm::Scan<SIMDfied>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
     763                 :            :             }
     764                 :          0 :         } else {
     765   [ #  #  #  # ]:          0 :             wasm::Scan<SIMDfied>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
     766                 :            :         }
     767                 :          0 :     }
     768                 :            : 
     769                 :          0 :     const Operator & get_matched_root() const override { return scan; }
     770                 :            : 
     771                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     772                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     773                 :            : 
     774                 :            :     protected:
     775                 :            :     void print(std::ostream &out, unsigned level) const override;
     776                 :            : };
     777                 :            : 
     778                 :            : template<idx::IndexMethod IndexMethod>
     779                 :            : struct Match<wasm::IndexScan<IndexMethod>> : wasm::MatchLeaf
     780                 :            : {
     781                 :            :     const ScanOperator &scan;
     782                 :            :     const FilterOperator &filter;
     783                 :          0 :     std::size_t batch_size = options::index_sequential_scan_batch_size;
     784                 :            :     private:
     785                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
     786   [ #  #  #  #  :          0 :         bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_INDEX_SCAN)
             #  #  #  # ]
     787   [ #  #  #  #  :          0 :             ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
             #  #  #  # ]
     788                 :          0 :             : std::unique_ptr<storage::DataLayoutFactory>();
     789                 :          0 :     std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
     790                 :            : 
     791                 :            :     public:
     792                 :          0 :     Match(const FilterOperator *filter, const ScanOperator *scan,
     793                 :            :           std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     794                 :          0 :         : scan(*scan)
     795                 :          0 :         , filter(*filter)
     796                 :          0 :     {
     797   [ #  #  #  # ]:          0 :         M_insist(children.empty());
     798                 :          0 :     }
     799                 :            : 
     800                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     801   [ #  #  #  #  :          0 :         execute_buffered(*this, filter.schema(), buffer_factory_, buffer_num_tuples_,
             #  #  #  # ]
     802                 :          0 :                          std::move(setup), std::move(pipeline), std::move(teardown));
     803                 :          0 :     }
     804                 :            : 
     805                 :          0 :     const Operator & get_matched_root() const override { return filter; }
     806                 :            : 
     807                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     808                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     809                 :            : 
     810                 :            :     protected:
     811                 :            :     void print(std::ostream &out, unsigned level) const override;
     812                 :            : };
     813                 :            : 
     814                 :            : template<bool Predicated>
     815                 :            : struct Match<wasm::Filter<Predicated>> : wasm::MatchSingleChild
     816                 :            : {
     817                 :            :     const FilterOperator &filter;
     818                 :            :     private:
     819                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
     820   [ #  #  #  #  :          0 :         bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_FILTER)
             #  #  #  # ]
     821   [ #  #  #  #  :          0 :             ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
             #  #  #  # ]
     822                 :          0 :             : std::unique_ptr<storage::DataLayoutFactory>();
     823                 :          0 :     std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
     824                 :            : 
     825                 :            :     public:
     826                 :          0 :     Match(const FilterOperator *filter, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     827                 :          0 :         : wasm::MatchSingleChild(std::move(children))
     828                 :          0 :         , filter(*filter)
     829                 :          0 :     { }
     830                 :            : 
     831                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     832   [ #  #  #  #  :          0 :         execute_buffered(*this, filter.schema(), buffer_factory_, buffer_num_tuples_,
             #  #  #  # ]
     833                 :          0 :                          std::move(setup), std::move(pipeline), std::move(teardown));
     834                 :          0 :     }
     835                 :            : 
     836                 :          0 :     const Operator & get_matched_root() const override { return filter; }
     837                 :            : 
     838                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     839                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     840                 :            : 
     841                 :            :     protected:
     842                 :            :     void print(std::ostream &out, unsigned level) const override;
     843                 :            : };
     844                 :            : 
     845                 :            : template<>
     846                 :            : struct Match<wasm::LazyDisjunctiveFilter> : wasm::MatchSingleChild
     847                 :            : {
     848                 :            :     const DisjunctiveFilterOperator &filter;
     849                 :            :     private:
     850                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
     851         [ #  # ]:          0 :         bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_FILTER)
     852   [ #  #  #  # ]:          0 :             ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
     853                 :          0 :             : std::unique_ptr<storage::DataLayoutFactory>();
     854                 :          0 :     std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
     855                 :            : 
     856                 :            :     public:
     857                 :          0 :     Match(const DisjunctiveFilterOperator *filter, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     858                 :          0 :         : wasm::MatchSingleChild(std::move(children))
     859                 :          0 :         , filter(*filter)
     860                 :          0 :     { }
     861                 :            : 
     862                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     863   [ #  #  #  # ]:          0 :         execute_buffered(*this, filter.schema(), buffer_factory_, buffer_num_tuples_,
     864                 :          0 :                          std::move(setup), std::move(pipeline), std::move(teardown));
     865                 :          0 :     }
     866                 :            : 
     867                 :          0 :     const Operator & get_matched_root() const override { return filter; }
     868                 :            : 
     869                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     870                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     871                 :            : 
     872                 :            :     protected:
     873                 :            :     void print(std::ostream &out, unsigned level) const override;
     874                 :            : };
     875                 :            : 
     876                 :            : template<>
     877                 :            : struct Match<wasm::Projection> : wasm::MatchBase
     878                 :            : {
     879                 :            :     const ProjectionOperator &projection;
     880                 :            :     std::optional<unsharable_shared_ptr<const wasm::MatchBase>> child;
     881                 :            :     private:
     882                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
     883         [ #  # ]:          0 :         bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_PROJECTION)
     884   [ #  #  #  # ]:          0 :             ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
     885                 :          0 :             : std::unique_ptr<storage::DataLayoutFactory>();
     886                 :          0 :     std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
     887                 :            : 
     888                 :            :     public:
     889                 :          0 :     Match(const ProjectionOperator *projection, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     890                 :          0 :         : projection(*projection)
     891                 :          0 :     {
     892         [ #  # ]:          0 :         if (not children.empty()) {
     893         [ #  # ]:          0 :             M_insist(children.size() == 1);
     894         [ #  # ]:          0 :             child = as<const wasm::MatchBase>(std::move(children[0]));
     895                 :          0 :         }
     896                 :          0 :     }
     897                 :            : 
     898                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     899   [ #  #  #  # ]:          0 :         execute_buffered(*this, projection.schema(), buffer_factory_, buffer_num_tuples_,
     900                 :          0 :                          std::move(setup), std::move(pipeline), std::move(teardown));
     901                 :          0 :     }
     902                 :            : 
     903                 :          0 :     const Operator & get_matched_root() const override { return projection; }
     904                 :            : 
     905                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     906                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     907                 :            : 
     908                 :            :     protected:
     909                 :            :     void print(std::ostream &out, unsigned level) const override;
     910                 :            : };
     911                 :            : 
     912                 :            : template<>
     913                 :            : struct Match<wasm::HashBasedGrouping> : wasm::MatchSingleChild
     914                 :            : {
     915                 :            :     const GroupingOperator &grouping;
     916                 :          0 :     bool use_open_addressing_hashing =
     917                 :          0 :         bool(options::hash_table_implementation bitand option_configs::HashTableImplementation::OPEN_ADDRESSING);
     918                 :          0 :     bool use_in_place_values = bool(options::hash_table_storing_strategy bitand option_configs::StoringStrategy::IN_PLACE);
     919                 :          0 :     bool use_quadratic_probing = bool(options::hash_table_probing_strategy bitand option_configs::ProbingStrategy::QUADRATIC);
     920                 :          0 :     double load_factor =
     921         [ #  # ]:          0 :         use_open_addressing_hashing ? options::load_factor_open_addressing : options::load_factor_chained;
     922                 :            : 
     923                 :          0 :     Match(const GroupingOperator *grouping, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     924                 :          0 :         : wasm::MatchSingleChild(std::move(children))
     925                 :          0 :         , grouping(*grouping)
     926                 :          0 :     { }
     927                 :            : 
     928                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     929         [ #  # ]:          0 :         wasm::HashBasedGrouping::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
     930                 :          0 :     }
     931                 :            : 
     932                 :          0 :     const Operator & get_matched_root() const override { return grouping; }
     933                 :            : 
     934                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     935                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     936                 :            : 
     937                 :            :     protected:
     938                 :            :     void print(std::ostream &out, unsigned level) const override;
     939                 :            : };
     940                 :            : 
     941                 :            : template<>
     942                 :            : struct Match<wasm::OrderedGrouping> : wasm::MatchSingleChild
     943                 :            : {
     944                 :            :     const GroupingOperator &grouping;
     945                 :            : 
     946                 :          0 :     Match(const GroupingOperator *grouping, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     947                 :          0 :         : wasm::MatchSingleChild(std::move(children))
     948                 :          0 :         , grouping(*grouping)
     949                 :          0 :     { }
     950                 :            : 
     951                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     952         [ #  # ]:          0 :         wasm::OrderedGrouping::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
     953                 :          0 :     }
     954                 :            : 
     955                 :          0 :     const Operator & get_matched_root() const override { return grouping; }
     956                 :            : 
     957                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     958                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     959                 :            : 
     960                 :            :     protected:
     961                 :            :     void print(std::ostream &out, unsigned level) const override;
     962                 :            : };
     963                 :            : 
     964                 :            : template<>
     965                 :            : struct Match<wasm::Aggregation> : wasm::MatchSingleChild
     966                 :            : {
     967                 :            :     const AggregationOperator &aggregation;
     968                 :            : 
     969                 :          0 :     Match(const AggregationOperator *aggregation, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     970                 :          0 :         : wasm::MatchSingleChild(std::move(children))
     971                 :          0 :         , aggregation(*aggregation)
     972                 :          0 :     { }
     973                 :            : 
     974                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
     975         [ #  # ]:          0 :         wasm::Aggregation::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
     976                 :          0 :     }
     977                 :            : 
     978                 :          0 :     const Operator & get_matched_root() const override { return aggregation; }
     979                 :            : 
     980                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
     981                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
     982                 :            : 
     983                 :            :     protected:
     984                 :            :     void print(std::ostream &out, unsigned level) const override;
     985                 :            : };
     986                 :            : 
     987                 :            : template<bool CmpPredicated>
     988                 :            : struct Match<wasm::Quicksort<CmpPredicated>> : wasm::MatchSingleChild
     989                 :            : {
     990                 :            :     const SortingOperator &sorting;
     991                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> materializing_factory =
     992   [ #  #  #  #  :          0 :         M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
             #  #  #  # ]
     993                 :            : 
     994                 :          0 :     Match(const SortingOperator *sorting, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
     995                 :          0 :         : wasm::MatchSingleChild(std::move(children))
     996                 :          0 :         , sorting(*sorting)
     997                 :          0 :     { }
     998                 :            : 
     999                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
    1000   [ #  #  #  # ]:          0 :         wasm::Quicksort<CmpPredicated>::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
    1001                 :          0 :     }
    1002                 :            : 
    1003                 :          0 :     const Operator & get_matched_root() const override { return sorting; }
    1004                 :            : 
    1005                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
    1006                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
    1007                 :            : 
    1008                 :            :     protected:
    1009                 :            :     void print(std::ostream &out, unsigned level) const override;
    1010                 :            : };
    1011                 :            : 
    1012                 :            : template<>
    1013                 :            : struct Match<wasm::NoOpSorting> : wasm::MatchSingleChild
    1014                 :            : {
    1015                 :            :     const SortingOperator &sorting;
    1016                 :            : 
    1017                 :          0 :     Match(const SortingOperator *sorting, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
    1018                 :          0 :         : wasm::MatchSingleChild(std::move(children))
    1019                 :          0 :         , sorting(*sorting)
    1020                 :          0 :     { }
    1021                 :            : 
    1022                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
    1023         [ #  # ]:          0 :         wasm::NoOpSorting::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
    1024                 :          0 :     }
    1025                 :            : 
    1026                 :          0 :     const Operator & get_matched_root() const override { return sorting; }
    1027                 :            : 
    1028                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
    1029                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
    1030                 :            : 
    1031                 :            :     protected:
    1032                 :            :     void print(std::ostream &out, unsigned level) const override;
    1033                 :            : };
    1034                 :            : 
    1035                 :            : template<bool Predicated>
    1036                 :            : struct Match<wasm::NestedLoopsJoin<Predicated>> : wasm::MatchMultipleChildren
    1037                 :            : {
    1038                 :            :     const JoinOperator &join;
    1039                 :            :     std::vector<std::unique_ptr<const storage::DataLayoutFactory>> materializing_factories_;
    1040                 :            :     private:
    1041                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
    1042   [ #  #  #  #  :          0 :         bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_NESTED_LOOPS_JOIN)
             #  #  #  # ]
    1043   [ #  #  #  #  :          0 :             ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
             #  #  #  # ]
    1044                 :          0 :             : std::unique_ptr<storage::DataLayoutFactory>();
    1045                 :          0 :     std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
    1046                 :            : 
    1047                 :            :     public:
    1048                 :          0 :     Match(const JoinOperator *join, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
    1049                 :          0 :         : wasm::MatchMultipleChildren(std::move(children))
    1050                 :          0 :         , join(*join)
    1051                 :          0 :     {
    1052   [ #  #  #  # ]:          0 :         for (std::size_t i = 0; i < children.size() - 1; ++i)
    1053   [ #  #  #  #  :          0 :             materializing_factories_.push_back(M_notnull(options::hard_pipeline_breaker_layout.get())->clone());
          #  #  #  #  #  
                #  #  # ]
    1054                 :          0 :     }
    1055                 :            : 
    1056                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
    1057   [ #  #  #  #  :          0 :         execute_buffered(*this, join.schema(), buffer_factory_, buffer_num_tuples_,
             #  #  #  # ]
    1058                 :          0 :                          std::move(setup), std::move(pipeline), std::move(teardown));
    1059                 :          0 :     }
    1060                 :            : 
    1061                 :          0 :     const Operator & get_matched_root() const override { return join; }
    1062                 :            : 
    1063                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
    1064                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
    1065                 :            : 
    1066                 :            :     protected:
    1067                 :            :     void print(std::ostream &out, unsigned level) const override;
    1068                 :            : };
    1069                 :            : 
    1070                 :            : template<bool UniqueBuild, bool Predicated>
    1071                 :            : struct Match<wasm::SimpleHashJoin<UniqueBuild, Predicated>> : wasm::MatchMultipleChildren
    1072                 :            : {
    1073                 :            :     const JoinOperator &join;
    1074                 :            :     const Wildcard &build;
    1075                 :            :     const Wildcard &probe;
    1076                 :          0 :     bool use_open_addressing_hashing =
    1077   [ #  #  #  #  :          0 :         bool(options::hash_table_implementation bitand option_configs::HashTableImplementation::OPEN_ADDRESSING);
             #  #  #  # ]
    1078   [ #  #  #  #  :          0 :     bool use_in_place_values = bool(options::hash_table_storing_strategy bitand option_configs::StoringStrategy::IN_PLACE);
             #  #  #  # ]
    1079   [ #  #  #  #  :          0 :     bool use_quadratic_probing = bool(options::hash_table_probing_strategy bitand option_configs::ProbingStrategy::QUADRATIC);
             #  #  #  # ]
    1080                 :          0 :     double load_factor =
    1081   [ #  #  #  #  :          0 :         use_open_addressing_hashing ? options::load_factor_open_addressing : options::load_factor_chained;
             #  #  #  # ]
    1082                 :            :     private:
    1083                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
    1084   [ #  #  #  #  :          0 :         bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_SIMPLE_HASH_JOIN)
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1085   [ #  #  #  #  :          0 :             ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1086                 :          0 :             : std::unique_ptr<storage::DataLayoutFactory>();
    1087                 :          0 :     std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
    1088                 :            : 
    1089                 :            :     public:
    1090                 :          0 :     Match(const JoinOperator *join, const Wildcard *build, const Wildcard *probe,
    1091                 :            :           std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
    1092                 :          0 :         : wasm::MatchMultipleChildren(std::move(children))
    1093                 :          0 :         , join(*join)
    1094                 :          0 :         , build(*build)
    1095                 :          0 :         , probe(*probe)
    1096                 :          0 :     {
    1097   [ #  #  #  #  :          0 :         M_insist(children.size() == 2);
             #  #  #  # ]
    1098                 :          0 :     }
    1099                 :            : 
    1100                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
    1101   [ #  #  #  #  :          0 :         execute_buffered(*this, join.schema(), buffer_factory_, buffer_num_tuples_,
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1102                 :          0 :                          std::move(setup), std::move(pipeline), std::move(teardown));
    1103                 :          0 :     }
    1104                 :            : 
    1105                 :          0 :     const Operator & get_matched_root() const override { return join; }
    1106                 :            : 
    1107                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
    1108                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
    1109                 :            : 
    1110                 :            :     protected:
    1111                 :            :     void print(std::ostream &out, unsigned level) const override;
    1112                 :            : };
    1113                 :            : 
    1114                 :            : template<bool SortLeft, bool SortRight, bool Predicated, bool CmpPredicated>
    1115                 :            : struct Match<wasm::SortMergeJoin<SortLeft, SortRight, Predicated, CmpPredicated>> : wasm::MatchMultipleChildren
    1116                 :            : {
    1117                 :            :     const JoinOperator &join;
    1118                 :            :     const Wildcard &parent; ///< the referenced relation with unique join attributes
    1119                 :            :     const Wildcard &child; ///< the relation referencing the parent relation
    1120                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> left_materializing_factory =
    1121   [ #  #  #  #  :          0 :         M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1122                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> right_materializing_factory =
    1123   [ #  #  #  #  :          0 :         M_notnull(options::hard_pipeline_breaker_layout.get())->clone();
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1124                 :            : 
    1125                 :          0 :     Match(const JoinOperator *join, const Wildcard *parent, const Wildcard *child,
    1126                 :            :           std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
    1127                 :          0 :         : wasm::MatchMultipleChildren(std::move(children))
    1128                 :          0 :         , join(*join)
    1129                 :          0 :         , parent(*parent)
    1130                 :          0 :         , child(*child)
    1131                 :          0 :     {
    1132   [ #  #  #  #  :          0 :         M_insist(children.size() == 2);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1133                 :          0 :     }
    1134                 :            : 
    1135                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
    1136   [ #  #  #  #  :          0 :         wasm::SortMergeJoin<SortLeft, SortRight, Predicated, CmpPredicated>::execute(
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
    1137                 :          0 :             *this, std::move(setup), std::move(pipeline), std::move(teardown)
    1138                 :            :         );
    1139                 :          0 :     }
    1140                 :            : 
    1141                 :          0 :     const Operator & get_matched_root() const override { return join; }
    1142                 :            : 
    1143                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
    1144                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
    1145                 :            : 
    1146                 :            :     protected:
    1147                 :            :     void print(std::ostream &out, unsigned level) const override;
    1148                 :            : };
    1149                 :            : 
    1150                 :            : template<>
    1151                 :            : struct Match<wasm::Limit> : wasm::MatchSingleChild
    1152                 :            : {
    1153                 :            :     const LimitOperator &limit;
    1154                 :            : 
    1155                 :          0 :     Match(const LimitOperator *limit, std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
    1156                 :          0 :         : wasm::MatchSingleChild(std::move(children))
    1157                 :          0 :         , limit(*limit)
    1158                 :          0 :     { }
    1159                 :            : 
    1160                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
    1161         [ #  # ]:          0 :         wasm::Limit::execute(*this, std::move(setup), std::move(pipeline), std::move(teardown));
    1162                 :          0 :     }
    1163                 :            : 
    1164                 :          0 :     const Operator & get_matched_root() const override { return limit; }
    1165                 :            : 
    1166                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
    1167                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
    1168                 :            : 
    1169                 :            :     protected:
    1170                 :            :     void print(std::ostream &out, unsigned level) const override;
    1171                 :            : };
    1172                 :            : 
    1173                 :            : template<>
    1174                 :            : struct Match<wasm::HashBasedGroupJoin> : wasm::MatchMultipleChildren
    1175                 :            : {
    1176                 :            :     const GroupingOperator &grouping;
    1177                 :            :     const JoinOperator &join;
    1178                 :            :     const Wildcard &build;
    1179                 :            :     const Wildcard &probe;
    1180                 :          0 :     bool use_open_addressing_hashing =
    1181                 :          0 :         bool(options::hash_table_implementation bitand option_configs::HashTableImplementation::OPEN_ADDRESSING);
    1182                 :          0 :     bool use_in_place_values = bool(options::hash_table_storing_strategy bitand option_configs::StoringStrategy::IN_PLACE);
    1183                 :          0 :     bool use_quadratic_probing = bool(options::hash_table_probing_strategy bitand option_configs::ProbingStrategy::QUADRATIC);
    1184                 :          0 :     double load_factor =
    1185         [ #  # ]:          0 :         use_open_addressing_hashing ? options::load_factor_open_addressing : options::load_factor_chained;
    1186                 :            :     private:
    1187                 :          0 :     std::unique_ptr<const storage::DataLayoutFactory> buffer_factory_ =
    1188         [ #  # ]:          0 :         bool(options::soft_pipeline_breaker bitand option_configs::SoftPipelineBreakerStrategy::AFTER_HASH_BASED_GROUP_JOIN)
    1189   [ #  #  #  # ]:          0 :             ? M_notnull(options::soft_pipeline_breaker_layout.get())->clone()
    1190                 :          0 :             : std::unique_ptr<storage::DataLayoutFactory>();
    1191                 :          0 :     std::size_t buffer_num_tuples_ = options::soft_pipeline_breaker_num_tuples;
    1192                 :            : 
    1193                 :            :     public:
    1194                 :          0 :     Match(const GroupingOperator* grouping, const JoinOperator *join, const Wildcard *build, const Wildcard *probe,
    1195                 :            :           std::vector<unsharable_shared_ptr<const m::MatchBase>> &&children)
    1196                 :          0 :         : wasm::MatchMultipleChildren(std::move(children))
    1197                 :          0 :         , grouping(*grouping)
    1198                 :          0 :         , join(*join)
    1199                 :          0 :         , build(*build)
    1200                 :          0 :         , probe(*probe)
    1201                 :          0 :     {
    1202         [ #  # ]:          0 :         M_insist(children.size() == 2);
    1203                 :          0 :     }
    1204                 :            : 
    1205                 :          0 :     void execute(setup_t setup, pipeline_t pipeline, teardown_t teardown) const override {
    1206   [ #  #  #  # ]:          0 :         execute_buffered(*this, grouping.schema(), buffer_factory_, buffer_num_tuples_,
    1207                 :          0 :                          std::move(setup), std::move(pipeline), std::move(teardown));
    1208                 :          0 :     }
    1209                 :            : 
    1210                 :          0 :     const Operator & get_matched_root() const override { return grouping; }
    1211                 :            : 
    1212                 :            :     void accept(wasm::MatchBaseVisitor &v) override;
    1213                 :            :     void accept(wasm::ConstMatchBaseVisitor &v) const override;
    1214                 :            : 
    1215                 :            :     protected:
    1216                 :            :     void print(std::ostream &out, unsigned level) const override;
    1217                 :            : };
    1218                 :            : 
    1219                 :            : namespace wasm {
    1220                 :            : 
    1221                 :            : #define M_WASM_VISITABLE_MATCH_LIST(X) \
    1222                 :            :     M_WASM_MATCH_LIST(X) \
    1223                 :            :     X(MatchLeaf) \
    1224                 :            :     X(MatchSingleChild) \
    1225                 :            :     X(MatchMultipleChildren)
    1226                 :            : 
    1227                 :            : M_DECLARE_VISITOR(MatchBaseVisitor, wasm::MatchBase, M_WASM_VISITABLE_MATCH_LIST)
    1228                 :            : M_DECLARE_VISITOR(ConstMatchBaseVisitor, const wasm::MatchBase, M_WASM_VISITABLE_MATCH_LIST)
    1229                 :            : 
    1230                 :            : /** A generic base class for implementing recursive `wasm::MatchBase` visitors. */
    1231                 :            : template<bool C>
    1232                 :            : struct TheRecursiveMatchBaseVisitorBase : std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>
    1233                 :            : {
    1234                 :            :     using super = std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>;
    1235                 :            :     template<typename T> using Const = typename super::template Const<T>;
    1236                 :            : 
    1237                 :          0 :     virtual ~TheRecursiveMatchBaseVisitorBase() { }
    1238                 :            : 
    1239                 :            :     /* omit using super::operator() to convert to intermediate match classes and call recursive implementation */
    1240                 :          0 :     void operator()(Const<MatchBase> &M) override { super::operator()(M); }
    1241                 :          0 :     void operator()(Const<MatchLeaf>&) override { /* nothing to be done */ }
    1242                 :          0 :     void operator()(Const<MatchSingleChild> &M) override { (*this)(*M.child); }
    1243         [ #  # ]:          0 :     void operator()(Const<Match<Projection>> &M) override { if (M.child) (*this)(**M.child); }
    1244         [ #  # ]:          0 :     void operator()(Const<MatchMultipleChildren> &M) override { for (auto &c : M.children) (*this)(*c); }
    1245                 :            : };
    1246                 :            : 
    1247                 :            : using RecursiveConstMatchBaseVisitorBase = TheRecursiveMatchBaseVisitorBase<true>;
    1248                 :            : 
    1249                 :            : template<bool C>
    1250                 :            : struct ThePreOrderMatchBaseVisitor : std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>
    1251                 :            : {
    1252                 :            :     using super = std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>;
    1253                 :            :     template<typename T> using Const = typename super::template Const<T>;
    1254                 :            : 
    1255                 :          0 :     virtual ~ThePreOrderMatchBaseVisitor() { }
    1256                 :            : 
    1257                 :            :     void operator()(Const<MatchBase>&);
    1258                 :            : };
    1259                 :            : 
    1260                 :            : template<bool C>
    1261                 :            : struct ThePostOrderMatchBaseVisitor : std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>
    1262                 :            : {
    1263                 :            :     using super = std::conditional_t<C, ConstMatchBaseVisitor, MatchBaseVisitor>;
    1264                 :            :     template<typename T> using Const = typename super::template Const<T>;
    1265                 :            : 
    1266                 :          0 :     virtual ~ThePostOrderMatchBaseVisitor() { }
    1267                 :            : 
    1268                 :            :     void operator()(Const<MatchBase>&);
    1269                 :            : };
    1270                 :            : 
    1271                 :            : using ConstPreOrderMatchBaseVisitor = ThePreOrderMatchBaseVisitor<true>;
    1272                 :            : using ConstPostOrderMatchBaseVisitor = ThePostOrderMatchBaseVisitor<true>;
    1273                 :            : 
    1274                 :            : M_MAKE_STL_VISITABLE(ConstPreOrderMatchBaseVisitor, const wasm::MatchBase, M_WASM_VISITABLE_MATCH_LIST)
    1275                 :            : M_MAKE_STL_VISITABLE(ConstPostOrderMatchBaseVisitor, const wasm::MatchBase, M_WASM_VISITABLE_MATCH_LIST)
    1276                 :            : 
    1277                 :            : #undef M_WASM_VISITABLE_MATCH_LIST
    1278                 :            : 
    1279                 :            : }
    1280                 :            : 
    1281                 :            : // delayed definitions (must occur *before* explicit instantiation below)
    1282                 :            : #define ACCEPT(CLASS) \
    1283                 :            :     inline void CLASS::accept(wasm::MatchBaseVisitor &v)            { v(*this); } \
    1284                 :            :     inline void CLASS::accept(wasm::ConstMatchBaseVisitor &v) const { v(*this); }
    1285                 :          0 : M_WASM_MATCH_LIST_NON_TEMPLATED(ACCEPT)
    1286                 :            : #undef ACCEPT
    1287                 :            : 
    1288                 :            : #define ACCEPT(CLASS) \
    1289                 :            :     template<> inline void CLASS::accept(wasm::MatchBaseVisitor &v)            { v(*this); } \
    1290                 :            :     template<> inline void CLASS::accept(wasm::ConstMatchBaseVisitor &v) const { v(*this); }
    1291                 :          0 : M_WASM_MATCH_LIST_TEMPLATED(ACCEPT)
    1292                 :            : #undef ACCEPT
    1293                 :            : 
    1294                 :            : }
    1295                 :            : 
    1296                 :            : 
    1297                 :            : // explicit instantiation declarations
    1298                 :            : #define DECLARE(CLASS) \
    1299                 :            :     extern template struct m::wasm::CLASS; \
    1300                 :            :     extern template struct m::Match<m::wasm::CLASS>;
    1301                 :            : M_WASM_OPERATOR_LIST_TEMPLATED(DECLARE)
    1302                 :            : #undef DECLARE

Generated by: LCOV version 1.16