aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/datastore/unique_store_comparator.h
blob: 267245bc215d53cebe8f134bf5a8eb0b3ea7ea58 (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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include "entry_comparator.h"
#include "unique_store_entry.h"
#include "datastore.h"
#include <vespa/vespalib/stllike/hash_fun.h>
#include <cmath>

namespace vespalib::datastore {

/**
 * Helper class for comparing elements in unique store.
 */
template <typename EntryT>
class UniqueStoreComparatorHelper {
public:
    static bool less(const EntryT& lhs, const EntryT& rhs) {
        return lhs < rhs;
    }
    static bool equal(const EntryT& lhs, const EntryT& rhs) {
        return lhs == rhs;
    }
    static size_t hash(const EntryT& rhs) {
        vespalib::hash<EntryT> hasher;
        return hasher(rhs);
    }
};

/**
 * Helper class for comparing floating point elements in unique store with
 * special handling of NAN.
 */
template <typename EntryT>
class UniqueStoreFloatingPointComparatorHelper
{
public:
    static bool less(EntryT lhs, const EntryT rhs) {
        if (std::isnan(lhs)) {
            return !std::isnan(rhs);
        } else if (std::isnan(rhs)) {
            return false;
        } else {
            return (lhs < rhs);
        }
    }
    static bool equal(EntryT lhs, const EntryT rhs) {
        if (std::isnan(lhs)) {
            return std::isnan(rhs);
        } else if (std::isnan(rhs)) {
            return false;
        } else {
            return (lhs == rhs);
        }
    }
    static size_t hash(EntryT rhs) {
        if (std::isnan(rhs)) {
            return 0;
        } else {
            union U { EntryT f; std::conditional_t<std::is_same_v<double, EntryT>, uint64_t, uint32_t> i; };
            U t;
            t.f = rhs;
            return t.i;
        }
    }
};

/**
 * Specialized helper class for comparing float elements in unique store with
 * special handling of NAN.
 */
template <>
class UniqueStoreComparatorHelper<float> : public UniqueStoreFloatingPointComparatorHelper<float> {
};

/**
 * Specialized helper class for comparing double elements in unique store with
 * special handling of NAN.
 */
template <>
class UniqueStoreComparatorHelper<double> : public UniqueStoreFloatingPointComparatorHelper<double> {
};

/**
 * Compare two entries based on entry refs.
 *
 * Valid entry ref is mapped to an entry in a data store.
 * Invalid entry ref is mapped to a temporary entry owned by comparator instance.
 */
template <typename EntryT, typename RefT>
class UniqueStoreComparator : public EntryComparator {
protected:
    using EntryType = EntryT;
    using WrappedEntryType = UniqueStoreEntry<EntryType>;
    using RefType = RefT;
    using DataStoreType = DataStoreT<RefT>;
    const DataStoreType &_store;
    const EntryType _lookup_value;

    inline const EntryType &get(EntryRef ref) const {
        if (ref.valid()) {
            RefType iRef(ref);
            return _store.template getEntry<WrappedEntryType>(iRef)->value();
        } else {
            return _lookup_value;
        }
    }
    UniqueStoreComparator(const DataStoreType &store, const EntryType &lookup_value)
        : _store(store),
          _lookup_value(lookup_value)
    {
    }
public:
    UniqueStoreComparator(const DataStoreType &store)
        : _store(store),
          _lookup_value()
    {
    }

    bool less(const EntryRef lhs, const EntryRef rhs) const override {
        const EntryType &lhsValue = get(lhs);
        const EntryType &rhsValue = get(rhs);
        return UniqueStoreComparatorHelper<EntryT>::less(lhsValue, rhsValue);
    }
    bool equal(const EntryRef lhs, const EntryRef rhs) const override {
        const EntryType &lhsValue = get(lhs);
        const EntryType &rhsValue = get(rhs);
        return UniqueStoreComparatorHelper<EntryT>::equal(lhsValue, rhsValue);
    }
    size_t hash(const EntryRef rhs) const override {
        const EntryType &rhsValue = get(rhs);
        return UniqueStoreComparatorHelper<EntryT>::hash(rhsValue);
    }

    UniqueStoreComparator<EntryT, RefT> make_for_lookup(const EntryType& lookup_value) const {
        return UniqueStoreComparator<EntryT, RefT>(_store, lookup_value);
    }
};

}