YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/gutil/algorithm.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2006 Google Inc.
2
//
3
// Licensed to the Apache Software Foundation (ASF) under one
4
// or more contributor license agreements.  See the NOTICE file
5
// distributed with this work for additional information
6
// regarding copyright ownership.  The ASF licenses this file
7
// to you under the Apache License, Version 2.0 (the
8
// "License"); you may not use this file except in compliance
9
// with the License.  You may obtain a copy of the License at
10
//
11
//   http://www.apache.org/licenses/LICENSE-2.0
12
//
13
// Unless required by applicable law or agreed to in writing,
14
// software distributed under the License is distributed on an
15
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
// KIND, either express or implied.  See the License for the
17
// specific language governing permissions and limitations
18
// under the License.
19
//
20
// The following only applies to changes made to this file as part of YugaByte development.
21
//
22
// Portions Copyright (c) YugaByte, Inc.
23
//
24
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
25
// in compliance with the License.  You may obtain a copy of the License at
26
//
27
// http://www.apache.org/licenses/LICENSE-2.0
28
//
29
// Unless required by applicable law or agreed to in writing, software distributed under the License
30
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
31
// or implied.  See the License for the specific language governing permissions and limitations
32
// under the License.
33
//
34
// ---
35
//
36
//
37
// This file contains some Google extensions to the standard
38
// <algorithm> C++ header. Many of these algorithms were in the
39
// original STL before it was proposed for standardization.
40
41
#ifndef YB_GUTIL_ALGORITHM_H
42
#define YB_GUTIL_ALGORITHM_H
43
44
#include <algorithm>
45
#include <functional>
46
47
using std::copy;
48
using std::max;
49
using std::min;
50
using std::reverse;
51
using std::sort;
52
using std::swap;
53
using std::binary_function;
54
using std::less;
55
using std::back_insert_iterator;
56
using std::iterator_traits;
57
using std::make_pair;
58
using std::pair;
59
60
namespace util {
61
namespace gtl {
62
63
// Returns true if [first, last) contains an element equal to value.
64
// Complexity: linear.
65
template<typename InputIterator, typename EqualityComparable>
66
bool contains(InputIterator first, InputIterator last,
67
0
              const EqualityComparable& value) {
68
0
  return std::find(first, last, value) != last;
69
0
}
70
71
// There is no contains_if().  Use any() instead.
72
73
template<typename InputIterator, typename ForwardIterator>
74
bool contains_some_of(InputIterator first1, InputIterator last1,
75
                      ForwardIterator first2, ForwardIterator last2) {
76
  return std::find_first_of(first1, last1, first2, last2) != last1;
77
}
78
79
template<typename InputIterator, typename ForwardIterator, typename Predicate>
80
bool contains_some_of(InputIterator first1, InputIterator last1,
81
                      ForwardIterator first2, ForwardIterator last2,
82
                      Predicate pred) {
83
  return std::find_first_of(first1, last1, first2, last2, pred) != last1;
84
}
85
86
template<typename InputIterator, typename EqualityComparable>
87
typename std::iterator_traits<InputIterator>::pointer
88
find_or_null(InputIterator first, InputIterator last,
89
             const EqualityComparable& value) {
90
  const InputIterator it = std::find(first, last, value);
91
  return it != last ? &*it : NULL;
92
}
93
94
template<typename InputIterator, typename Predicate>
95
typename std::iterator_traits<InputIterator>::pointer
96
find_if_or_null(InputIterator first, InputIterator last, Predicate pred) {
97
  const InputIterator it = std::find_if(first, last, pred);
98
  return it != last ? &*it : NULL;
99
}
100
101
// Copies all elements that satisfy the predicate pred from [first,
102
// last) to out. This is the complement of remove_copy_if. Complexity:
103
// exactly last-first applications of pred.
104
template <typename InputIterator, typename OutputIterator, typename Predicate>
105
OutputIterator copy_if(InputIterator first, InputIterator last,
106
                       OutputIterator out,
107
                       Predicate pred) {
108
  for (; first != last; ++first) {
109
    if (pred(*first))
110
      *out++ = *first;
111
  }
112
  return out;
113
}
114
115
// Copies n elements to out.  Equivalent to copy(first, first + n, out) for
116
// random access iterators and a longer code block for lesser iterators.
117
template <typename InputIterator, typename Size, typename OutputIterator>
118
OutputIterator copy_n(InputIterator first, Size n, OutputIterator out) {
119
  while (n > 0) {
120
    *out = *first;
121
    ++out;
122
    ++first;
123
    --n;
124
  }
125
  return out;
126
}
127
128
// Returns true if pred is true for every element in [first, last). Complexity:
129
// at most last-first applications of pred.
130
template <typename InputIterator, typename Predicate>
131
bool all(InputIterator first, InputIterator last, Predicate pred) {
132
  for (; first != last; ++first) {
133
    if (!pred(*first))
134
      return false;
135
  }
136
  return true;
137
}
138
139
// Returns true if pred is false for every element in [first,
140
// last). Complexity: at most last-first applications of pred.
141
template <typename InputIterator, typename Predicate>
142
bool none(InputIterator first, InputIterator last, Predicate pred) {
143
  return find_if(first, last, pred) == last;
144
}
145
146
// Returns true if pred is true for at least one element in [first, last).
147
// Complexity: at most last-first applications of pred.
148
template <typename InputIterator, typename Predicate>
149
bool any(InputIterator first, InputIterator last, Predicate pred) {
150
  return !none(first, last, pred);
151
}
152
153
// Returns a pair of iterators p such that p.first points to the
154
// minimum element in the range and p.second points to the maximum,
155
// ordered by comp. Complexity: at most floor((3/2) (N-1))
156
// comparisons. Postcondition: If the return value is <min, max>, min is
157
// the first iterator i in [first, last) such that comp(*j, *i) is
158
// false for every other iterator j, and max is the last iterator i
159
// such that comp(*i, *j) is false for every other iterator j. Or less
160
// formally, min is the first minimum and max is the last maximum.
161
template <typename ForwardIter, typename Compare>
162
std::pair<ForwardIter, ForwardIter> minmax_element(ForwardIter first,
163
                                                   const ForwardIter last,
164
                                                   Compare comp) {
165
  // Initialization: for N<2, set min=max=first. For N >= 2, set min
166
  // to be the smaller of the first two and max to be the larger. (Taking
167
  // care that min is the first, and max the second, if the two compare
168
  // equivalent.)
169
  ForwardIter min(first);
170
  ForwardIter max(first);
171
172
  if (first != last) {
173
    ++first;
174
  }
175
176
  if (first != last) {
177
    max = first;
178
    if (comp(*max, *min))
179
      swap(min, max);
180
    ++first;
181
  }
182
183
  while (first != last) {
184
    ForwardIter next(first);
185
    ++next;
186
187
    if (next != last) {
188
      // We have two elements to look at that we haven't seen already,
189
      // *first and *next. Compare the smaller of them with the
190
      // current min, and the larger against the current max. The
191
      // subtle point: write all of the comparisons so that, if the
192
      // two things being compared are equivalent, we take the first
193
      // one as the smaller and the last as the larger.
194
      if (comp(*next, *first)) {
195
        if (comp(*next, *min))
196
          min = next;
197
        if (!comp(*first, *max))
198
          max = first;
199
      } else {
200
        if (comp(*first, *min))
201
          min = first;
202
        if (!comp(*next, *max))
203
          max = next;
204
      }
205
    } else {
206
      // There is only one element left that we haven't seen already, *first.
207
      // Adjust min or max, as appropriate, and exit the loop.
208
      if (comp(*first, *min)) {
209
        min = first;
210
      } else if (!comp(*first, *max)) {
211
        max = first;
212
      }
213
      break;
214
    }
215
216
    first = next;
217
    ++first;
218
  }
219
220
  return make_pair(min, max);
221
}
222
223
// Returns a pair of iterators p such that p.first points to the first
224
// minimum element in the range and p.second points to the last
225
// maximum, ordered by operator<.
226
template <typename ForwardIter>
227
inline std::pair<ForwardIter, ForwardIter> minmax_element(ForwardIter first,
228
                                                          ForwardIter last) {
229
  typedef typename std::iterator_traits<ForwardIter>::value_type value_type;
230
  return util::gtl::minmax_element(first, last, std::less<value_type>());
231
}
232
233
// Returns true if [first, last) is partitioned by pred, i.e. if all
234
// elements that satisfy pred appear before those that do
235
// not. Complexity: linear.
236
template <typename ForwardIterator, typename Predicate>
237
inline bool is_partitioned(ForwardIterator first, ForwardIterator last,
238
                           Predicate pred) {
239
  for (; first != last; ++first) {
240
    if (!pred(*first)) {
241
      ++first;
242
      return util::gtl::none(first, last, pred);
243
    }
244
  }
245
  return true;
246
}
247
248
// Precondition: is_partitioned(first, last, pred). Returns: the
249
// partition point p, i.e. an iterator mid satisfying the conditions
250
// all(first, mid, pred) and none(mid, last, pred).  Complexity:
251
// O(log(last-first)) applications of pred.
252
template <typename ForwardIterator, typename Predicate>
253
ForwardIterator partition_point(ForwardIterator first, ForwardIterator last,
254
                                Predicate pred) {
255
  typedef typename std::iterator_traits<ForwardIterator>::difference_type diff;
256
  diff n = distance(first, last);
257
258
  // Loop invariant: n == distance(first, last)
259
  while (first != last) {
260
    diff half = n/2;
261
    ForwardIterator mid = first;
262
    advance(mid, half);
263
    if (pred(*mid)) {
264
      first = mid;
265
      ++first;
266
      n -= half+1;
267
    } else {
268
      n = half;
269
      last = mid;
270
    }
271
  }
272
273
  return first;
274
}
275
276
// Copies all elements that satisfy pred to out_true and all elements
277
// that don't satisfy it to out_false. Returns: a pair p such that
278
// p.first is the end of the range beginning at out_t and p.second is
279
// the end of the range beginning at out_f. Complexity: exactly
280
// last-first applications of pred.
281
template <typename InputIterator,
282
          typename OutputIterator1, typename OutputIterator2,
283
          typename Predicate>
284
std::pair<OutputIterator1, OutputIterator2>
285
partition_copy(InputIterator first, InputIterator last,
286
               OutputIterator1 out_true, OutputIterator2 out_false,
287
               Predicate pred) {
288
  for (; first != last; ++first) {
289
    if (pred(*first))
290
      *out_true++ = *first;
291
    else
292
      *out_false++ = *first;
293
  }
294
  return make_pair(out_true, out_false);
295
}
296
297
// Reorders elements in [first, last), so that for each consecutive group
298
// of duplicate elements (according to eq predicate) the first one is left and
299
// others are moved at the end of the range. Returns: iterator middle such that
300
// [first, middle) contains no two consecutive elements that are duplicates and
301
// [middle, last) contains elements removed from all groups. It's stable for
302
// range [first, middle) meaning the order of elements are the same as order of
303
// their corresponding groups in input, but the order in range [middle, last)
304
// is not preserved. Function is similar to std::unique, but ensures that
305
// removed elements are properly copied and accessible at the range's end.
306
// Complexity: exactly last-first-1 applications of eq; at most middle-first-1
307
// swap operations.
308
template <typename ForwardIterator, typename Equals>
309
ForwardIterator unique_partition(ForwardIterator first, ForwardIterator last,
310
                                 Equals eq) {
311
  first = adjacent_find(first, last, eq);
312
  if (first == last)
313
    return last;
314
315
  // Points to right-most element within range of unique elements being built.
316
  ForwardIterator result = first;
317
318
  // 'first' iterator goes through the sequence starting from element after
319
  // first equal elements pair (found by adjacent_find above).
320
  ++first;
321
  while (++first != last) {
322
    // If we encounter an element that isn't equal to right-most element in
323
    // result, then extend the range and swap this element into it.
324
    // Otherwise just continue incrementing 'first'.
325
    if (!eq(*result, *first)) {
326
      swap(*++result, *first);
327
    }
328
  }
329
  // Return past-the-end upper-bound of the resulting range.
330
  return ++result;
331
}
332
333
// Reorders elements in [first, last) range moving duplicates for each
334
// consecutive group of elements to the end. Equality is checked using ==.
335
template <typename ForwardIterator>
336
inline ForwardIterator unique_partition(ForwardIterator first,
337
                                        ForwardIterator last) {
338
  typedef typename std::iterator_traits<ForwardIterator>::value_type T;
339
  return unique_partition(first, last, std::equal_to<T>());
340
}
341
342
// Samples k elements from the next n.
343
// Elements have the same order in the output stream as they did on input.
344
//
345
// This is Algorithm S from section 3.4.2 of Knuth, TAOCP, 2nd edition.
346
// My k corresponds to Knuth n-m.
347
// My n corrsponds to Knuth N-t.
348
//
349
// RngFunctor is any functor that can be called as:
350
//   size_t RngFunctor(size_t x)
351
// The return value is an integral value in the half-open range [0, x)
352
// such that all values are equally likely.  Behavior is unspecified if x==0.
353
// (This function never calls RngFunctor with x==0).
354
355
template <typename InputIterator, typename OutputIterator, typename RngFunctor>
356
inline void sample_k_of_n(InputIterator in, size_t k, size_t n,
357
                          RngFunctor& rng, OutputIterator out) { // NOLINT
358
  if (k > n) {
359
    k = n;
360
  }
361
  while (k > 0) {
362
    if (rng(n) < k) {
363
      *out++ = *in;
364
      k--;
365
    }
366
    ++in;
367
    --n;
368
  }
369
}
370
371
// Finds the longest prefix of a range that is a binary max heap with
372
// respect to a given StrictWeakOrdering.  If first == last, returns last.
373
// Otherwise, return an iterator it such that [first,it) is a heap but
374
// no longer prefix is -- in other words, first + i for the lowest i
375
// such that comp(first[(i-1)/2], first[i]) returns true.
376
template <typename RandomAccessIterator, typename StrictWeakOrdering>
377
RandomAccessIterator gtl_is_binary_heap_until(RandomAccessIterator first,
378
                                              RandomAccessIterator last,
379
                                              StrictWeakOrdering comp) {
380
  if (last - first < 2) return last;
381
  RandomAccessIterator parent = first;
382
  bool is_right_child = false;
383
  for (RandomAccessIterator child = first + 1; child != last; ++child) {
384
    if (comp(*parent, *child)) return child;
385
    if (is_right_child) ++parent;
386
    is_right_child = !is_right_child;
387
  }
388
  return last;
389
}
390
391
// Special case of gtl_is_binary_heap_until where the order is std::less,
392
// i.e., where we're working with a simple max heap.
393
template <typename RandomAccessIterator>
394
RandomAccessIterator gtl_is_binary_heap_until(RandomAccessIterator first,
395
                                              RandomAccessIterator last) {
396
  typedef typename std::iterator_traits<RandomAccessIterator>::value_type T;
397
  return gtl_is_binary_heap_until(first, last, std::less<T>());
398
}
399
400
// Checks whether a range of values is a binary heap, i.e., checks that
401
// no node is less (as defined by a StrictWeakOrdering) than a child.
402
template <typename RandomAccessIterator, typename StrictWeakOrdering>
403
bool gtl_is_binary_heap(RandomAccessIterator begin,
404
                        RandomAccessIterator end,
405
                        StrictWeakOrdering comp) {
406
  return gtl_is_binary_heap_until(begin, end, comp) == end;
407
}
408
409
// Special case of gtl_is_binary_heap where the order is std::less (i.e.,
410
// where we're working on a simple max heap).
411
template <typename RandomAccessIterator>
412
bool gtl_is_binary_heap(RandomAccessIterator begin,
413
                        RandomAccessIterator end) {
414
  return gtl_is_binary_heap_until(begin, end) == end;
415
}
416
417
// Unqualified calls to is_heap are ambiguous with some build types,
418
// namespace that can clash with names that C++11 added to ::std.
419
// By calling util::gtl::is_heap, clients can avoid those errors,
420
// and by using the underlying is_heap call we ensure consistency
421
// with the standard library's heap implementation just in case a
422
// standard library ever uses anything other than a binary heap.
423
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus > 199711L \
424
  || defined(LIBCXX) || _MSC_VER >= 1600 /* Visual Studio 2010 */
425
using std::is_heap;
426
#elif defined __GNUC__
427
/* using __gnu_cxx::is_heap; */
428
#elif defined _MSC_VER
429
// For old versions of MSVC++, we know by inspection that make_heap()
430
// traffics in binary max heaps, so gtl_is_binary_heap is an acceptable
431
// implementation for is_heap.
432
template <typename RandomAccessIterator>
433
bool is_heap(RandomAccessIterator begin, RandomAccessIterator end) {
434
  return gtl_is_binary_heap(begin, end);
435
}
436
437
template <typename RandomAccessIterator, typename StrictWeakOrdering>
438
bool is_heap(RandomAccessIterator begin,
439
             RandomAccessIterator end,
440
             StrictWeakOrdering comp) {
441
  return gtl_is_binary_heap(begin, end, comp);
442
}
443
#else
444
// We need an implementation of is_heap that matches the library's
445
// implementation of make_heap() and friends.  gtl_is_binary_heap will
446
// *probably* work, but let's be safe and not make that assumption.
447
#error No implementation of is_heap defined for this toolchain.
448
#endif
449
450
}  // namespace gtl
451
}  // namespace util
452
453
#endif  // YB_GUTIL_ALGORITHM_H