<commit_before>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "schema.hh"
#include "bytes.hh"
#include "types.hh"

//
// This header defines type system for primary key holders.
//
// We distinguish partition keys and clustering keys. API-wise they are almost
// the same, but they're separate type hierarchies.
//
// Clustering keys are further divided into prefixed and non-prefixed (full).
// Non-prefixed keys always have full component set, as defined by schema.
// Prefixed ones can have any number of trailing components missing. They may
// differ in underlying representation.
//
// The main classes are:
//
//   partition_key           - full partition key
//   clustering_key          - full clustering key
//   clustering_key_prefix   - clustering key prefix
//
// These classes wrap only the minimum information required to store the key
// (the key value itself). Any information which can be inferred from schema
// is not stored. Therefore accessors need to be provided with a pointer to
// schema, from which information about structure is extracted.

class partition_key;
class clustering_key;
class clustering_key_prefix;

// Abstracts serialized tuple, managed by tuple_type.
template <typename TopLevel>
class tuple_wrapper {
protected:
    bytes _bytes;
protected:
    tuple_wrapper(bytes&& b) : _bytes(std::move(b)) {}

    static inline auto get_tuple_type(const schema& s) {
        return TopLevel::get_tuple_type(s);
    }
public:
    static TopLevel make_empty(const schema& s) {
        std::vector<bytes> v;
        v.resize(get_tuple_type(s)->types().size());
        return from_exploded(s, v);
    }

    static TopLevel from_exploded(const schema& s, const std::vector<bytes>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value(v));
    }

    // We don't allow optional values, but provide this method as an efficient adaptor
    static TopLevel from_optional_exploded(const schema& s, const std::vector<bytes_opt>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_optionals(v));
    }

    static TopLevel from_deeply_exploded(const schema& s, const std::vector<boost::any>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value_deep(v));
    }

    static TopLevel from_single_value(const schema& s, bytes v) {
        // FIXME: optimize
        std::vector<bytes> values;
        values.emplace_back(std::move(v));
        return from_exploded(s, values);
    }

    // FIXME: return views
    std::vector<bytes> explode(const schema& s) const {
        return get_tuple_type(s)->deserialize_value(_bytes);
    }

    struct less_compare {
        typename TopLevel::tuple _t;
        less_compare(const schema& s) : _t(get_tuple_type(s)) {}
        bool operator()(const TopLevel& k1, const TopLevel& k2) const {
            return _t->less(k1, k2);
        }
    };

    struct hashing {
        typename TopLevel::tuple _t;
        hashing(const schema& s) : _t(get_tuple_type(s)) {}
        size_t operator()(const TopLevel& o) const {
            return _t->hash(o);
        }
    };

    struct equality {
        typename TopLevel::tuple _t;
        equality(const schema& s) : _t(get_tuple_type(s)) {}
        bool operator()(const TopLevel& o1, const TopLevel& o2) const {
            return _t->equal(o1, o2);
        }
    };

    bool equal(const schema& s, const TopLevel& other) const {
        return get_tuple_type(s)->equal(*this, other);
    }

    operator bytes_view() const {
        return _bytes;
    }
};

template <typename TopLevel, typename PrefixTopLevel>
class prefix_view_on_full_tuple {
public:
    using iterator = typename tuple_type<false>::iterator;
private:
    bytes_view _b;
    unsigned _prefix_len;
    iterator _begin;
    iterator _end;
public:
    prefix_view_on_full_tuple(const schema& s, bytes_view b, unsigned prefix_len)
        : _b(b)
        , _prefix_len(prefix_len)
        , _begin(TopLevel::get_tuple_type(s)->begin(_b))
        , _end(_begin)
    {
        std::advance(_end, prefix_len);
    }

    iterator begin() const { return _begin; }
    iterator end() const { return _end; }

    struct less_compare_with_prefix {
        typename PrefixTopLevel::tuple prefix_type;

        less_compare_with_prefix(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
        { }

        bool operator()(const prefix_view_on_full_tuple& k1, const PrefixTopLevel& k2) const {
            return lexicographical_compare(prefix_type->types().begin(),
                k1.begin(), k1.end(),
                prefix_type->begin(k2), prefix_type->end(k2),
                less_compare);
        }

        bool operator()(const PrefixTopLevel& k1, const prefix_view_on_full_tuple& k2) const {
            return lexicographical_compare(prefix_type->types().begin(),
                prefix_type->begin(k1), prefix_type->end(k1),
                k2.begin(), k2.end(),
                less_compare);
        }
    };
};

template <typename TopLevel, typename PrefixTopLevel>
class prefixable_full_tuple : public tuple_wrapper<TopLevel> {
    using base = tuple_wrapper<TopLevel>;
protected:
    prefixable_full_tuple(bytes&& b) : base(std::move(b)) {}
public:
    using prefix_view_type = prefix_view_on_full_tuple<TopLevel, PrefixTopLevel>;

    bool is_prefixed_by(const schema& s, const PrefixTopLevel& prefix) const {
        auto t = base::get_tuple_type(s);
        auto prefix_type = PrefixTopLevel::get_tuple_type(s);
        return ::is_prefixed_by(t->types().begin(),
            t->begin(*this), t->end(*this),
            prefix_type->begin(prefix), prefix_type->end(prefix),
            ::equal);
    }

    struct less_compare_with_prefix {
        typename PrefixTopLevel::tuple prefix_type;
        typename TopLevel::tuple full_type;

        less_compare_with_prefix(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
            , full_type(TopLevel::get_tuple_type(s))
        { }

        bool operator()(const TopLevel& k1, const PrefixTopLevel& k2) const {
            return lexicographical_compare(prefix_type->types().begin(),
                full_type->begin(k1), full_type->end(k1),
                prefix_type->begin(k2), prefix_type->end(k2),
                less_compare);
        }

        bool operator()(const PrefixTopLevel& k1, const TopLevel& k2) const {
            return lexicographical_compare(prefix_type->types().begin(),
                prefix_type->begin(k1), prefix_type->end(k1),
                full_type->begin(k2), full_type->end(k2),
                less_compare);
        }
    };

    auto prefix_view(const schema& s, unsigned prefix_len) const {
        return prefix_view_type(s, *this, prefix_len);
    }
};

template <typename TopLevel, typename FullTopLevel>
class prefix_tuple_wrapper : public tuple_wrapper<TopLevel> {
    using base = tuple_wrapper<TopLevel>;
protected:
    prefix_tuple_wrapper(bytes&& b) : base(std::move(b)) {}
public:
    bool is_full(const schema& s) const {
        return TopLevel::get_tuple_type(s)->is_full(base::_bytes);
    }
<commit_msg>keys: Use trichotomic comparators where possible<commit_after>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "schema.hh"
#include "bytes.hh"
#include "types.hh"

//
// This header defines type system for primary key holders.
//
// We distinguish partition keys and clustering keys. API-wise they are almost
// the same, but they're separate type hierarchies.
//
// Clustering keys are further divided into prefixed and non-prefixed (full).
// Non-prefixed keys always have full component set, as defined by schema.
// Prefixed ones can have any number of trailing components missing. They may
// differ in underlying representation.
//
// The main classes are:
//
//   partition_key           - full partition key
//   clustering_key          - full clustering key
//   clustering_key_prefix   - clustering key prefix
//
// These classes wrap only the minimum information required to store the key
// (the key value itself). Any information which can be inferred from schema
// is not stored. Therefore accessors need to be provided with a pointer to
// schema, from which information about structure is extracted.

class partition_key;
class clustering_key;
class clustering_key_prefix;

// Abstracts serialized tuple, managed by tuple_type.
template <typename TopLevel>
class tuple_wrapper {
protected:
    bytes _bytes;
protected:
    tuple_wrapper(bytes&& b) : _bytes(std::move(b)) {}

    static inline auto get_tuple_type(const schema& s) {
        return TopLevel::get_tuple_type(s);
    }
public:
    static TopLevel make_empty(const schema& s) {
        std::vector<bytes> v;
        v.resize(get_tuple_type(s)->types().size());
        return from_exploded(s, v);
    }

    static TopLevel from_exploded(const schema& s, const std::vector<bytes>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value(v));
    }

    // We don't allow optional values, but provide this method as an efficient adaptor
    static TopLevel from_optional_exploded(const schema& s, const std::vector<bytes_opt>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_optionals(v));
    }

    static TopLevel from_deeply_exploded(const schema& s, const std::vector<boost::any>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value_deep(v));
    }

    static TopLevel from_single_value(const schema& s, bytes v) {
        // FIXME: optimize
        std::vector<bytes> values;
        values.emplace_back(std::move(v));
        return from_exploded(s, values);
    }

    // FIXME: return views
    std::vector<bytes> explode(const schema& s) const {
        return get_tuple_type(s)->deserialize_value(_bytes);
    }

    struct less_compare {
        typename TopLevel::tuple _t;
        less_compare(const schema& s) : _t(get_tuple_type(s)) {}
        bool operator()(const TopLevel& k1, const TopLevel& k2) const {
            return _t->less(k1, k2);
        }
    };

    struct hashing {
        typename TopLevel::tuple _t;
        hashing(const schema& s) : _t(get_tuple_type(s)) {}
        size_t operator()(const TopLevel& o) const {
            return _t->hash(o);
        }
    };

    struct equality {
        typename TopLevel::tuple _t;
        equality(const schema& s) : _t(get_tuple_type(s)) {}
        bool operator()(const TopLevel& o1, const TopLevel& o2) const {
            return _t->equal(o1, o2);
        }
    };

    bool equal(const schema& s, const TopLevel& other) const {
        return get_tuple_type(s)->equal(*this, other);
    }

    operator bytes_view() const {
        return _bytes;
    }
};

template <typename TopLevel, typename PrefixTopLevel>
class prefix_view_on_full_tuple {
public:
    using iterator = typename tuple_type<false>::iterator;
private:
    bytes_view _b;
    unsigned _prefix_len;
    iterator _begin;
    iterator _end;
public:
    prefix_view_on_full_tuple(const schema& s, bytes_view b, unsigned prefix_len)
        : _b(b)
        , _prefix_len(prefix_len)
        , _begin(TopLevel::get_tuple_type(s)->begin(_b))
        , _end(_begin)
    {
        std::advance(_end, prefix_len);
    }

    iterator begin() const { return _begin; }
    iterator end() const { return _end; }

    struct less_compare_with_prefix {
        typename PrefixTopLevel::tuple prefix_type;

        less_compare_with_prefix(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
        { }

        bool operator()(const prefix_view_on_full_tuple& k1, const PrefixTopLevel& k2) const {
            return lexicographical_tri_compare(prefix_type->types().begin(),
                k1.begin(), k1.end(),
                prefix_type->begin(k2), prefix_type->end(k2),
                tri_compare) < 0;
        }

        bool operator()(const PrefixTopLevel& k1, const prefix_view_on_full_tuple& k2) const {
            return lexicographical_tri_compare(prefix_type->types().begin(),
                prefix_type->begin(k1), prefix_type->end(k1),
                k2.begin(), k2.end(),
                tri_compare) < 0;
        }
    };
};

template <typename TopLevel, typename PrefixTopLevel>
class prefixable_full_tuple : public tuple_wrapper<TopLevel> {
    using base = tuple_wrapper<TopLevel>;
protected:
    prefixable_full_tuple(bytes&& b) : base(std::move(b)) {}
public:
    using prefix_view_type = prefix_view_on_full_tuple<TopLevel, PrefixTopLevel>;

    bool is_prefixed_by(const schema& s, const PrefixTopLevel& prefix) const {
        auto t = base::get_tuple_type(s);
        auto prefix_type = PrefixTopLevel::get_tuple_type(s);
        return ::is_prefixed_by(t->types().begin(),
            t->begin(*this), t->end(*this),
            prefix_type->begin(prefix), prefix_type->end(prefix),
            ::equal);
    }

    struct less_compare_with_prefix {
        typename PrefixTopLevel::tuple prefix_type;
        typename TopLevel::tuple full_type;

        less_compare_with_prefix(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
            , full_type(TopLevel::get_tuple_type(s))
        { }

        bool operator()(const TopLevel& k1, const PrefixTopLevel& k2) const {
            return lexicographical_tri_compare(prefix_type->types().begin(),
                full_type->begin(k1), full_type->end(k1),
                prefix_type->begin(k2), prefix_type->end(k2),
                tri_compare) < 0;
        }

        bool operator()(const PrefixTopLevel& k1, const TopLevel& k2) const {
            return lexicographical_tri_compare(prefix_type->types().begin(),
                prefix_type->begin(k1), prefix_type->end(k1),
                full_type->begin(k2), full_type->end(k2),
                tri_compare) < 0;
        }
    };

    auto prefix_view(const schema& s, unsigned prefix_len) const {
        return prefix_view_type(s, *this, prefix_len);
    }
};

template <typename TopLevel, typename FullTopLevel>
class prefix_tuple_wrapper : public tuple_wrapper<TopLevel> {
    using base = tuple_wrapper<TopLevel>;
protected:
    prefix_tuple_wrapper(bytes&& b) : base(std::move(b)) {}
public:
    bool is_full(const schema& s) const {
        return TopLevel::get_tuple_type(s)->is_full(base::_bytes);
    }

{'fraction_non_alphanumeric': 0.11067826086956521, 'fraction_numerical': 0.005286956521739131, 'mean_word_length': 2.991116046640755, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6896064', 'n_tokens_mistral': 4409, 'n_tokens_neox': 4277, 'n_words': 1065}