• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / jonathan.reams_3577

21 Jan 2025 05:41PM UTC coverage: 91.105% (-0.02%) from 91.124%
jonathan.reams_3577

Pull #8064

Evergreen

jbreams
fix test
Pull Request #8064: Sync access token refreshes shouldn't extend SyncSession lifetime

102714 of 181514 branches covered (56.59%)

73 of 73 new or added lines in 3 files covered. (100.0%)

109 existing lines in 18 files now uncovered.

217338 of 238558 relevant lines covered (91.1%)

5558106.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.05
/src/realm/string_data.cpp
1
/*************************************************************************
2
 *
3
 * Copyright 2017 Realm Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 * http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 **************************************************************************/
18

19
#include "string_data.hpp"
20

21
#include <vector>
22

23
using namespace realm;
24

25
namespace {
26

27
template <bool has_alternate_pattern>
28
REALM_FORCEINLINE bool matchlike(const StringData& text, const StringData& pattern,
29
                                 const StringData* alternate_pattern = nullptr) noexcept
30
{
23,106✔
31
    // If alternate_pattern is provided, it is assumed to differ from `pattern` only in case.
32
    REALM_ASSERT_DEBUG(has_alternate_pattern == bool(alternate_pattern));
23,106✔
33
    REALM_ASSERT_DEBUG(!alternate_pattern || pattern.size() == alternate_pattern->size());
23,106!
34

35
    std::vector<size_t> textpos;
23,106✔
36
    std::vector<size_t> patternpos;
23,106✔
37
    size_t p1 = 0; // position in text (haystack)
23,106✔
38
    size_t p2 = 0; // position in pattern (needle)
23,106✔
39

40
    while (true) {
667,584✔
41
        if (p1 == text.size()) {
667,584✔
42
            // We're at the end of the text. This is a match if:
43
            // - we're also at the end of the pattern; or
44
            if (p2 == pattern.size())
19,464✔
45
                return true;
18,828✔
46

47
            // - we're at the last character of the pattern, and it's a multi-character wildcard.
48
            if (p2 == pattern.size() - 1 && pattern[p2] == '*')
636✔
49
                return true;
72✔
50

51
            goto no_match;
564✔
52
        }
636✔
53

54
        if (p2 == pattern.size()) {
648,120✔
55
            // We've hit the end of the pattern without matching the entirety of the text.
56
            goto no_match;
3,588✔
57
        }
3,588✔
58

59
        if (pattern[p2] == '*') {
644,532✔
60
            // Multi-character wildcard. Remember our position in case we need to backtrack.
61
            textpos.push_back(p1);
2,208✔
62
            patternpos.push_back(++p2);
2,208✔
63
            continue;
2,208✔
64
        }
2,208✔
65

66
        if (pattern[p2] == '?') {
642,324✔
67
            // utf-8 encoded characters may take up multiple bytes
68
            if ((text[p1] & 0x80) == 0) {
702✔
69
                ++p1;
630✔
70
                ++p2;
630✔
71
                continue;
630✔
72
            }
630✔
73
            else {
72✔
74
                size_t p = 1;
72✔
75
                while (p1 + p != text.size() && (text[p1 + p] & 0xc0) == 0x80)
180✔
76
                    ++p;
108✔
77
                p1 += p;
72✔
78
                ++p2;
72✔
79
                continue;
72✔
80
            }
72✔
81
        }
702✔
82

83
        if (pattern[p2] == text[p1]) {
641,622✔
84
            ++p1;
616,560✔
85
            ++p2;
616,560✔
86
            continue;
616,560✔
87
        }
616,560✔
88

89
        if (has_alternate_pattern && (*alternate_pattern)[p2] == text[p1]) {
25,062!
90
            ++p1;
19,644✔
91
            ++p2;
19,644✔
92
            continue;
19,644✔
93
        }
19,644✔
94

95
    no_match:
9,570✔
96
        if (textpos.empty()) {
9,570✔
97
            // We were performing the outermost level of matching, so if we made it here the text did not match.
98
            return false;
4,050✔
99
        }
4,050✔
100

101
        if (p1 == text.size()) {
5,520✔
102
            // We've hit the end of the text without a match, so backtrack.
103
            textpos.pop_back();
180✔
104
            patternpos.pop_back();
180✔
105
        }
180✔
106

107
        if (textpos.empty()) {
5,520✔
108
            // We finished our last backtrack attempt without finding a match, so the text did not match.
109
            return false;
156✔
110
        }
156✔
111

112
        // Reattempt the match from the next character.
113
        p1 = ++textpos.back();
5,364✔
114
        p2 = patternpos.back();
5,364✔
115
    }
5,364✔
116
}
23,106✔
117

118
} // unnamed namespace
119

120
bool StringData::matchlike(const realm::StringData& text, const realm::StringData& pattern) noexcept
121
{
10,620✔
122
    return ::matchlike<false>(text, pattern);
10,620✔
123
}
10,620✔
124

125
bool StringData::matchlike_ins(const StringData& text, const StringData& pattern_upper,
126
                               const StringData& pattern_lower) noexcept
127
{
12,486✔
128
    return ::matchlike<true>(text, pattern_upper, &pattern_lower);
12,486✔
129
}
12,486✔
130

131

132
namespace {
133
template <size_t = sizeof(void*)>
134
struct Murmur2OrCityHash;
135

136
template <>
137
struct Murmur2OrCityHash<8> {
138
    inline uint_least64_t operator()(const unsigned char* data, size_t len) const noexcept
139
    {
902,388✔
140
        return cityhash_64(data, len);
902,388✔
141
    }
902,388✔
142
};
143

144
template <>
145
struct Murmur2OrCityHash<4> {
146
    inline uint_least32_t operator()(const unsigned char* data, size_t len) const noexcept
147
    {
×
148
        return murmur2_32(data, len);
×
149
    }
×
150
};
151

152
inline uint_least32_t load4(const unsigned char* data)
153
{
14,112✔
154
    uint_least32_t word = 0;
14,112✔
155
    std::memcpy(&word, data, 4);
14,112✔
156
    return word;
14,112✔
157
}
14,112✔
158

159
inline uint_least64_t load8(const unsigned char* data)
160
{
1,748,496✔
161
    uint_least64_t word = 0;
1,748,496✔
162
    std::memcpy(&word, data, 8);
1,748,496✔
163
    return word;
1,748,496✔
164
}
1,748,496✔
165

166
} // unnamed namespace
167

168

169
size_t realm::murmur2_or_cityhash(const unsigned char* data, size_t len) noexcept
170
{
902,388✔
171
    return size_t(Murmur2OrCityHash<>{}(data, len));
902,388✔
172
}
902,388✔
173

174
uint_least32_t realm::murmur2_32(const unsigned char* data, size_t len) noexcept
175
{
6✔
176
    // This implementation is copied from libc++.
177
    // See: https://github.com/llvm-mirror/libcxx/blob/master/include/utility
178

179
    REALM_ASSERT_DEBUG(len <= std::numeric_limits<uint_least32_t>::max());
6✔
180

181
    const uint_least32_t m = 0x5bd1e995UL;
6✔
182
    const uint_least32_t r = 24;
6✔
183
    uint_least32_t h = uint_least32_t(len);
6✔
184

185
    for (; len >= 4; data += 4, len -= 4) {
24✔
186
        uint_least32_t k = load4(data);
18✔
187
        k *= m;
18✔
188
        k ^= k >> r;
18✔
189
        k *= m;
18✔
190
        h *= m;
18✔
191
        h ^= k;
18✔
192
    }
18✔
193

194
    switch (len) {
6✔
195
        case 3:
✔
196
            h ^= data[2] << 16;
×
197
            REALM_FALLTHROUGH;
×
198
        case 2:
✔
199
            h ^= data[1] << 8;
×
200
            REALM_FALLTHROUGH;
×
201
        case 1:
6✔
202
            h ^= data[0];
6✔
203
            h *= m;
6✔
204
    }
6✔
205
    h ^= h >> 13;
6✔
206
    h *= m;
6✔
207
    h ^= h >> 15;
6✔
208
    return h;
6✔
209
}
6✔
210

211
namespace {
212
struct CityHash64 {
213
    // This implementation is copied from libc++.
214
    // See: https://github.com/llvm-mirror/libcxx/blob/master/include/utility
215

216
    static const uint_least64_t k0 = 0xc3a5c85c97cb3127ULL;
217
    static const uint_least64_t k1 = 0xb492b66fbe98f273ULL;
218
    static const uint_least64_t k2 = 0x9ae16a3b2f90404fULL;
219
    static const uint_least64_t k3 = 0xc949d7c7509e6557ULL;
220
    using pair = std::pair<uint_least64_t, uint_least64_t>;
221

222
    uint_least64_t operator()(const unsigned char* data, size_t len) const noexcept
223
    {
902,478✔
224
        if (len <= 32) {
902,478✔
225
            if (len <= 16) {
902,439✔
226
                return hash_len_0_to_16(data, len);
902,427✔
227
            }
902,427✔
228
            else {
12✔
229
                return hash_len_17_to_32(data, len);
12✔
230
            }
12✔
231
        }
902,439✔
232
        else if (len <= 64) {
39✔
233
            return hash_len_33_to_64(data, len);
39✔
234
        }
39✔
UNCOV
235
        uint_least64_t x = load8(data + len - 40);
×
UNCOV
236
        uint_least64_t y = load8(data + len - 16) + load8(data + len - 56);
×
UNCOV
237
        uint_least64_t z = hash_len_16(load8(data + len - 48) + len, load8(data + len - 24));
×
UNCOV
238
        pair v = weak_hash_len_32_with_seeds(data + len - 64, len, z);
×
UNCOV
239
        pair w = weak_hash_len_32_with_seeds(data + len - 32, y + k1, x);
×
UNCOV
240
        x = x * k1 + load8(data);
×
241

242
        // Decrease len to the nearest multiple of 64, and operate on 64-byte
243
        // chunks.
UNCOV
244
        len = (len - 1) & ~static_cast<uint_least64_t>(63);
×
UNCOV
245
        do {
×
UNCOV
246
            x = rotate(x + y + v.first + load8(data + 8), 37) * k1;
×
UNCOV
247
            y = rotate(y + v.second + load8(data + 48), 42) * k1;
×
UNCOV
248
            x ^= w.second;
×
UNCOV
249
            y += v.first + load8(data + 40);
×
UNCOV
250
            z = rotate(z + w.first, 33) * k1;
×
UNCOV
251
            v = weak_hash_len_32_with_seeds(data, v.second * k1, x + w.first);
×
UNCOV
252
            w = weak_hash_len_32_with_seeds(data + 32, z + w.second, y + load8(data + 16));
×
UNCOV
253
            std::swap(z, x);
×
UNCOV
254
            data += 64;
×
UNCOV
255
            len -= 64;
×
UNCOV
256
        } while (len != 0);
×
UNCOV
257
        return hash_len_16(hash_len_16(v.first, w.first) + shift_mix(y) * k1 + z,
×
UNCOV
258
                           hash_len_16(v.second, w.second) + x);
×
259
    }
902,478✔
260

261
    static uint_least64_t hash_len_0_to_16(const unsigned char* data, size_t len) noexcept
262
    {
902,427✔
263
        if (len > 8) {
902,427✔
264
            const auto a = load8(data);
874,029✔
265
            const auto b = load8(data + len - 8);
874,029✔
266
            return hash_len_16(a, rotate_by_at_least_1(b + len, int(len))) ^ b;
874,029✔
267
        }
874,029✔
268
        if (len >= 4) {
28,398✔
269
            const auto a = load4(data);
7,047✔
270
            const auto b = load4(data + len - 4);
7,047✔
271
            return hash_len_16(len + (a << 3), b);
7,047✔
272
        }
7,047✔
273
        if (len > 0) {
21,351✔
274
            const auto a = data[0];
21,066✔
275
            const auto b = data[len >> 1];
21,066✔
276
            const auto c = data[len - 1];
21,066✔
277
            const auto y = static_cast<uint_least32_t>(a) + (static_cast<uint_least32_t>(b) << 8);
21,066✔
278
            const auto z = static_cast<uint_least32_t>(len) + (static_cast<uint_least32_t>(c) << 2);
21,066✔
279
            return shift_mix(y * k2 ^ z * k3) * k2;
21,066✔
280
        }
21,066✔
281
        return k2;
285✔
282
    }
21,351✔
283

284
    static uint_least64_t hash_len_17_to_32(const unsigned char* data, size_t len) noexcept
285
    {
12✔
286
        const auto a = load8(data) * k1;
12✔
287
        const auto b = load8(data + 8);
12✔
288
        const auto c = load8(data + len - 8) * k2;
12✔
289
        const auto d = load8(data + len - 16) * k0;
12✔
290
        return hash_len_16(rotate(a - b, 43) + rotate(c, 30) + d, a + rotate(b ^ k3, 20) - c + len);
12✔
291
    }
12✔
292

293
    static uint_least64_t hash_len_33_to_64(const unsigned char* data, size_t len) noexcept
294
    {
39✔
295
        uint_least64_t z = load8(data + 24);
39✔
296
        uint_least64_t a = load8(data) + (len + load8(data + len - 16)) * k0;
39✔
297
        uint_least64_t b = rotate(a + z, 52);
39✔
298
        uint_least64_t c = rotate(a, 37);
39✔
299
        a += load8(data + 8);
39✔
300
        c += rotate(a, 7);
39✔
301
        a += load8(data + 16);
39✔
302
        uint_least64_t vf = a + z;
39✔
303
        uint_least64_t vs = b + rotate(a, 31) + c;
39✔
304
        a = load8(data + 16) + load8(data + len - 32);
39✔
305
        z += load8(data + len - 8);
39✔
306
        b = rotate(a + z, 52);
39✔
307
        c = rotate(a, 37);
39✔
308
        a += load8(data + len - 24);
39✔
309
        c += rotate(a, 7);
39✔
310
        a += load8(data + len - 16);
39✔
311
        uint_least64_t wf = a + z;
39✔
312
        uint_least64_t ws = b + rotate(a, 31) + c;
39✔
313
        uint_least64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0);
39✔
314
        return shift_mix(r * k0 + vs) * k2;
39✔
315
    }
39✔
316

317
    static uint_least64_t hash_len_16(uint_least64_t u, uint_least64_t v) noexcept
318
    {
881,088✔
319
        const uint_least64_t mul = 0x9ddfea08eb382d69ULL;
881,088✔
320
        uint_least64_t a = (u ^ v) * mul;
881,088✔
321
        a ^= (a >> 47);
881,088✔
322
        uint_least64_t b = (v ^ a) * mul;
881,088✔
323
        b ^= (b >> 47);
881,088✔
324
        b *= mul;
881,088✔
325
        return b;
881,088✔
326
    }
881,088✔
327

328
    static pair weak_hash_len_32_with_seeds(uint_least64_t w, uint_least64_t x, uint_least64_t y, uint_least64_t z,
329
                                            uint_least64_t a, uint_least64_t b) noexcept
330
    {
×
331
        a += w;
×
332
        b = rotate(b + a + z, 21);
×
333
        const uint_least64_t c = a;
×
334
        a += x;
×
335
        a += y;
×
336
        b += rotate(a, 44);
×
337
        return pair{a + z, b + c};
×
338
    }
×
339

340
    static pair weak_hash_len_32_with_seeds(const unsigned char* data, uint_least64_t a, uint_least64_t b) noexcept
341
    {
×
342
        return weak_hash_len_32_with_seeds(load8(data), load8(data + 8), load8(data + 16), load8(data + 24), a, b);
×
343
    }
×
344

345
    static inline uint_least64_t rotate(uint_least64_t val, int shift) noexcept
346
    {
348✔
347
        return shift == 0 ? val : rotate_by_at_least_1(val, shift);
348✔
348
    }
348✔
349

350
    static inline uint_least64_t rotate_by_at_least_1(uint_least64_t val, int shift) noexcept
351
    {
874,377✔
352
        return (val >> shift) | (val << (64 - shift));
874,377✔
353
    }
874,377✔
354

355
    static inline uint_least64_t shift_mix(uint_least64_t val) noexcept
356
    {
21,144✔
357
        return val ^ (val >> 47);
21,144✔
358
    }
21,144✔
359
};
360
} // unnamed namespace
361

362
uint_least64_t realm::cityhash_64(const unsigned char* data, size_t len) noexcept
363
{
902,478✔
364
    return CityHash64{}(data, len);
902,478✔
365
}
902,478✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc