Generate type struct of a direct indexed relation. 
  192     const auto& inds = getIndices();
 
  193     size_t numIndexes = inds.size();
 
  194     std::map<MinIndexSelection::LexOrder, int> indexToNumMap;
 
  198     out << 
"static constexpr Relation::arity_type Arity = " << 
arity << 
";\n";
 
  201     out << 
"using t_tuple = Tuple<RamDomain, " << 
arity << 
">;\n";
 
  205         out << 
"struct updater_" << 
getTypeName() << 
" {\n";
 
  206         out << 
"void update(t_tuple& old_t, const t_tuple& new_t) {\n";
 
  209             out << 
"old_t[" << 
i << 
"] = new_t[" << 
i << 
"];\n";
 
  217     for (
size_t i = 0; 
i < inds.size(); 
i++) {
 
  220         if (
i < getMinIndexSelection().getAllOrders().
size()) {
 
  221             indexToNumMap[getMinIndexSelection().getAllOrders()[
i]] = 
i;
 
  224         std::vector<std::string> typecasts;
 
  225         typecasts.reserve(
types.size());
 
  229                 case 'f': typecasts.push_back(
"ramBitCast<RamFloat>"); 
break;
 
  230                 case 'u': typecasts.push_back(
"ramBitCast<RamUnsigned>"); 
break;
 
  231                 default: typecasts.push_back(
"ramBitCast<RamSigned>");
 
  235         auto genstruct = [&](std::string 
name, 
size_t bound) {
 
  236             out << 
"struct " << 
name << 
"{\n";
 
  237             out << 
" int operator()(const t_tuple& a, const t_tuple& b) const {\n";
 
  239             std::function<void(
size_t)> gencmp = [&](
size_t i) {
 
  240                 size_t attrib = ind[
i];
 
  241                 const auto& typecast = typecasts[attrib];
 
  243                 out << 
"(" << typecast << 
"(a[" << attrib << 
"]) < " << typecast << 
"(b[" << attrib
 
  244                     << 
"])) ? -1 : (" << typecast << 
"(a[" << attrib << 
"]) > " << typecast << 
"(b[" << attrib
 
  255             out << 
"bool less(const t_tuple& a, const t_tuple& b) const {\n";
 
  257             std::function<void(
size_t)> genless = [&](
size_t i) {
 
  258                 size_t attrib = ind[
i];
 
  259                 const auto& typecast = typecasts[attrib];
 
  261                 out << 
"(" << typecast << 
"(a[" << attrib << 
"]) < " << typecast << 
"(b[" << attrib << 
"]))";
 
  263                     out << 
"|| (" << typecast << 
"(a[" << attrib << 
"]) == " << typecast << 
"(b[" << attrib
 
  271             out << 
"bool equal(const t_tuple& a, const t_tuple& b) const {\n";
 
  273             std::function<void(
size_t)> geneq = [&](
size_t i) {
 
  274                 size_t attrib = ind[
i];
 
  275                 const auto& typecast = typecasts[attrib];
 
  277                 out << 
"(" << typecast << 
"(a[" << attrib << 
"]) == " << typecast << 
"(b[" << attrib << 
"]))";
 
  288         std::string 
comparator = 
"t_comparator_" + std::to_string(
i);
 
  295             std::string comparator_aux;
 
  296             if (provenanceIndexNumbers.find(
i) == provenanceIndexNumbers.end()) {
 
  298                 comparator_aux = 
"t_comparator_" + std::to_string(
i) + 
"_aux";
 
  304             out << 
"using t_ind_" << 
i << 
" = btree_set<t_tuple," << 
comparator 
  305                 << 
",std::allocator<t_tuple>,256,typename " 
  306                    "souffle::detail::default_strategy<t_tuple>::type," 
  307                 << comparator_aux << 
",updater_" << 
getTypeName() << 
">;\n";
 
  309             if (ind.size() == 
arity) {
 
  310                 out << 
"using t_ind_" << 
i << 
" = btree_set<t_tuple," << 
comparator << 
">;\n";
 
  313                 out << 
"using t_ind_" << 
i << 
" = btree_multiset<t_tuple," << 
comparator << 
">;\n";
 
  316         out << 
"t_ind_" << 
i << 
" ind_" << 
i << 
";\n";
 
  320     out << 
"using iterator = t_ind_" << masterIndex << 
"::iterator;\n";
 
  323     out << 
"struct context {\n";
 
  324     for (
size_t i = 0; 
i < numIndexes; 
i++) {
 
  325         out << 
"t_ind_" << 
i << 
"::operation_hints hints_" << 
i << 
"_lower" 
  327         out << 
"t_ind_" << 
i << 
"::operation_hints hints_" << 
i << 
"_upper" 
  331     out << 
"context createContext() { return context(); }\n";
 
  334     out << 
"bool insert(const t_tuple& t) {\n";
 
  335     out << 
"context h;\n";
 
  336     out << 
"return insert(t, h);\n";
 
  339     out << 
"bool insert(const t_tuple& t, context& h) {\n";
 
  340     out << 
"if (ind_" << masterIndex << 
".insert(t, h.hints_" << masterIndex << 
"_lower" 
  342     for (
size_t i = 0; 
i < numIndexes; 
i++) {
 
  343         if (
i != masterIndex && provenanceIndexNumbers.find(
i) == provenanceIndexNumbers.end()) {
 
  344             out << 
"ind_" << 
i << 
".insert(t, h.hints_" << 
i << 
"_lower" 
  348     out << 
"return true;\n";
 
  349     out << 
"} else return false;\n";
 
  352     out << 
"bool insert(const RamDomain* ramDomain) {\n";
 
  353     out << 
"RamDomain data[" << 
arity << 
"];\n";
 
  354     out << 
"std::copy(ramDomain, ramDomain + " << 
arity << 
", data);\n";
 
  355     out << 
"const t_tuple& tuple = reinterpret_cast<const t_tuple&>(data);\n";
 
  356     out << 
"context h;\n";
 
  357     out << 
"return insert(tuple, h);\n";
 
  360     std::vector<std::string> decls;
 
  361     std::vector<std::string> params;
 
  362     for (
size_t i = 0; 
i < 
arity; 
i++) {
 
  363         decls.push_back(
"RamDomain a" + std::to_string(
i));
 
  364         params.push_back(
"a" + std::to_string(
i));
 
  366     out << 
"bool insert(" << 
join(decls, 
",") << 
") {\n";
 
  367     out << 
"RamDomain data[" << 
arity << 
"] = {" << 
join(params, 
",") << 
"};\n";
 
  368     out << 
"return insert(data);\n";
 
  372     out << 
"bool contains(const t_tuple& t, context& h) const {\n";
 
  373     out << 
"return ind_" << masterIndex << 
".contains(t, h.hints_" << masterIndex << 
"_lower" 
  377     out << 
"bool contains(const t_tuple& t) const {\n";
 
  378     out << 
"context h;\n";
 
  379     out << 
"return contains(t, h);\n";
 
  383     out << 
"std::size_t size() const {\n";
 
  384     out << 
"return ind_" << masterIndex << 
".size();\n";
 
  388     out << 
"iterator find(const t_tuple& t, context& h) const {\n";
 
  389     out << 
"return ind_" << masterIndex << 
".find(t, h.hints_" << masterIndex << 
"_lower" 
  393     out << 
"iterator find(const t_tuple& t) const {\n";
 
  394     out << 
"context h;\n";
 
  395     out << 
"return find(t, h);\n";
 
  399     out << 
"range<iterator> lowerUpperRange_" << SearchSignature(
arity)
 
  400         << 
"(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const " 
  403     out << 
"return range<iterator>(ind_" << masterIndex << 
".begin(),ind_" << masterIndex << 
".end());\n";
 
  406     out << 
"range<iterator> lowerUpperRange_" << SearchSignature(
arity)
 
  407         << 
"(const t_tuple& /* lower */, const t_tuple& /* upper */) const {\n";
 
  409     out << 
"return range<iterator>(ind_" << masterIndex << 
".begin(),ind_" << masterIndex << 
".end());\n";
 
  413     for (
auto search : getMinIndexSelection().getSearches()) {
 
  414         auto& lexOrder = getMinIndexSelection().getLexOrder(search);
 
  415         size_t indNum = indexToNumMap[lexOrder];
 
  417         out << 
"range<t_ind_" << indNum << 
"::iterator> lowerUpperRange_" << search;
 
  418         out << 
"(const t_tuple& lower, const t_tuple& upper, context& h) const {\n";
 
  422         for (
size_t column = 0; column < 
arity; column++) {
 
  423             if (search[column] == analysis::AttributeConstraint::Equal) {
 
  428         out << 
"t_comparator_" << indNum << 
" comparator;\n";
 
  429         out << 
"int cmp = comparator(lower, upper);\n";
 
  432         if (eqSize == 
arity) {
 
  434             out << 
"if (cmp == 0) {\n";
 
  435             out << 
"    auto pos = ind_" << indNum << 
".find(lower, h.hints_" << indNum << 
"_lower);\n";
 
  436             out << 
"    auto fin = ind_" << indNum << 
".end();\n";
 
  437             out << 
"    if (pos != fin) {fin = pos; ++fin;}\n";
 
  438             out << 
"    return make_range(pos, fin);\n";
 
  442         out << 
"if (cmp > 0) {\n";
 
  443         out << 
"    return make_range(ind_" << indNum << 
".end(), ind_" << indNum << 
".end());\n";
 
  446         out << 
"return make_range(ind_" << indNum << 
".lower_bound(lower, h.hints_" << indNum << 
"_lower" 
  447             << 
"), ind_" << indNum << 
".upper_bound(upper, h.hints_" << indNum << 
"_upper" 
  452         out << 
"range<t_ind_" << indNum << 
"::iterator> lowerUpperRange_" << search;
 
  453         out << 
"(const t_tuple& lower, const t_tuple& upper) const {\n";
 
  455         out << 
"context h;\n";
 
  456         out << 
"return lowerUpperRange_" << search << 
"(lower,upper,h);\n";
 
  461     out << 
"bool empty() const {\n";
 
  462     out << 
"return ind_" << masterIndex << 
".empty();\n";
 
  466     out << 
"std::vector<range<iterator>> partition() const {\n";
 
  467     out << 
"return ind_" << masterIndex << 
".getChunks(400);\n";
 
  471     out << 
"void purge() {\n";
 
  472     for (
size_t i = 0; 
i < numIndexes; 
i++) {
 
  473         out << 
"ind_" << 
i << 
".clear();\n";
 
  478     out << 
"iterator begin() const {\n";
 
  479     out << 
"return ind_" << masterIndex << 
".begin();\n";
 
  482     out << 
"iterator end() const {\n";
 
  483     out << 
"return ind_" << masterIndex << 
".end();\n";
 
  487     if (!provenanceIndexNumbers.empty()) {
 
  488         out << 
"void copyIndex() {\n";
 
  489         out << 
"for (auto const &cur : ind_" << masterIndex << 
") {\n";
 
  490         for (
auto const i : provenanceIndexNumbers) {
 
  491             out << 
"ind_" << 
i << 
".insert(cur);\n";
 
  498     out << 
"void printStatistics(std::ostream& o) const {\n";
 
  499     for (
size_t i = 0; 
i < numIndexes; 
i++) {
 
  500         out << 
"o << \" arity " << 
arity << 
" direct b-tree index " << 
i << 
" lex-order " << inds[
i]
 
  502         out << 
"ind_" << 
i << 
".printStats(o);\n";