aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/vespa/searchlib/attribute/enumcomparator.h
blob: cfff8d286a564cd6e968b24b20b0e0da4bd5dd67 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include "i_enum_store.h"
#include <vespa/vespalib/datastore/entry_comparator.h>
#include <vespa/vespalib/datastore/unique_store_comparator.h>
#include <vespa/vespalib/datastore/unique_store_string_comparator.h>

namespace search {

/**
 * Less-than comparator used for comparing values of type EntryT stored in an enum store.
 */
template <typename EntryT>
class EnumStoreComparator : public vespalib::datastore::UniqueStoreComparator<EntryT, IEnumStore::InternalIndex> {
public:
    using ParentType = vespalib::datastore::UniqueStoreComparator<EntryT, IEnumStore::InternalIndex>;
    using DataStoreType = typename ParentType::DataStoreType;

    EnumStoreComparator(const DataStoreType& data_store)
        : ParentType(data_store)
    {}

private:
    EnumStoreComparator(const DataStoreType& data_store, const EntryT& lookup_value)
        : ParentType(data_store, lookup_value)
    {}

public:
    static bool equal_helper(const EntryT& lhs, const EntryT& rhs);

    EnumStoreComparator<EntryT> make_folded() const {
        return *this;
    }
    EnumStoreComparator<EntryT> make_for_lookup(const EntryT& lookup_value) const {
        return EnumStoreComparator<EntryT>(this->_store, lookup_value);
    }
};

/**
 * Less-than comparator used for comparing strings stored in an enum store.
 *
 * The input string values are first folded, then compared.
 * If they are equal, then it falls back to comparing without folding.
 */
class EnumStoreStringComparator : public vespalib::datastore::UniqueStoreStringComparator<IEnumStore::InternalIndex> {
protected:
    using ParentType = vespalib::datastore::UniqueStoreStringComparator<IEnumStore::InternalIndex>;
    using DataStoreType = ParentType::DataStoreType;
private:
    using ParentType::get;

    /*
     * CompareStrategy determines how to compare string values:
     *
     * UNCASED_THEN_CASED compares the values ignoring case (i.e.
     * performs case folding during the first compare). If the values
     * are equal then they are compared again using case.
     *
     * UNCASED compares the values ignoring case.
     *
     * CASED compares the value, using case.
     *
     * Only UNCASED_THEN_CASED or CASED can be used for sorting.
     * UNCASED can be used for lookup during search when sort order is
     * UNCASED_THEN_CASED.
     *
     * UNCASED_THEN_CASED sort order: ["BAR", "bar", "FOO", "foo"]
     * CASED sort order:              ["BAR", "FOO", "bar", "foo"]
     */
    enum class CompareStrategy : uint8_t {
        UNCASED_THEN_CASED,
        UNCASED,
        CASED
    };

public:
    EnumStoreStringComparator(const DataStoreType& data_store, bool cased)
        : EnumStoreStringComparator(data_store, cased ? CompareStrategy::CASED : CompareStrategy::UNCASED_THEN_CASED)
    {}

private:
    EnumStoreStringComparator(const DataStoreType& data_store, CompareStrategy compare_strategy);

    /**
     * Creates a comparator using the given low-level data store and that uses the
     * given value during compare if the enum index is invalid.
     */
    EnumStoreStringComparator(const DataStoreType& data_store, CompareStrategy compare_strategy, const char* lookup_value);
    EnumStoreStringComparator(const DataStoreType& data_store, CompareStrategy compare_strategy, const char* lookup_value, bool prefix);

public:
    bool less(const vespalib::datastore::EntryRef lhs, const vespalib::datastore::EntryRef rhs) const override;
    EnumStoreStringComparator make_folded() const {
        return EnumStoreStringComparator(_store, _compare_strategy == CompareStrategy::UNCASED_THEN_CASED ? CompareStrategy::UNCASED : _compare_strategy);
    }
    EnumStoreStringComparator make_for_lookup(const char* lookup_value) const {
        return EnumStoreStringComparator(_store, _compare_strategy, lookup_value);
    }
    EnumStoreStringComparator make_for_prefix_lookup(const char* lookup_value) const {
        return EnumStoreStringComparator(_store, _compare_strategy, lookup_value, true);
    }
private:
    inline bool use_prefix() const noexcept { return _prefix; }
    const CompareStrategy _compare_strategy;
    const bool _prefix;
    uint32_t   _prefix_len;
};

extern template class EnumStoreComparator<int8_t>;
extern template class EnumStoreComparator<int16_t>;
extern template class EnumStoreComparator<int32_t>;
extern template class EnumStoreComparator<int64_t>;
extern template class EnumStoreComparator<float>;
extern template class EnumStoreComparator<double>;

}