summaryrefslogtreecommitdiff
path: root/contrib/pzstd/utils/Range.h
blob: fedb5d786c6865751b2cecee0b4dd0ff1aa3ff10 (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
/*
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under both the BSD-style license (found in the
 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
 * in the COPYING file in the root directory of this source tree).
 */
 
/**
 * A subset of `folly/Range.h`.
 * All code copied verbatim modulo formatting
 */
#pragma once

#include "utils/Likely.h"

#include <cstddef>
#include <cstring>
#include <stdexcept>
#include <string>
#include <type_traits>

namespace pzstd {

namespace detail {
/*
 *Use IsCharPointer<T>::type to enable const char* or char*.
 *Use IsCharPointer<T>::const_type to enable only const char*.
*/
template <class T>
struct IsCharPointer {};

template <>
struct IsCharPointer<char*> {
  typedef int type;
};

template <>
struct IsCharPointer<const char*> {
  typedef int const_type;
  typedef int type;
};

} // namespace detail

template <typename Iter>
class Range {
  Iter b_;
  Iter e_;

 public:
  using size_type = std::size_t;
  using iterator = Iter;
  using const_iterator = Iter;
  using value_type = typename std::remove_reference<
      typename std::iterator_traits<Iter>::reference>::type;
  using reference = typename std::iterator_traits<Iter>::reference;

  constexpr Range() : b_(), e_() {}
  constexpr Range(Iter begin, Iter end) : b_(begin), e_(end) {}

  constexpr Range(Iter begin, size_type size) : b_(begin), e_(begin + size) {}

  template <class T = Iter, typename detail::IsCharPointer<T>::type = 0>
  /* implicit */ Range(Iter str) : b_(str), e_(str + std::strlen(str)) {}

  template <class T = Iter, typename detail::IsCharPointer<T>::const_type = 0>
  /* implicit */ Range(const std::string& str)
      : b_(str.data()), e_(b_ + str.size()) {}

  // Allow implicit conversion from Range<From> to Range<To> if From is
  // implicitly convertible to To.
  template <
      class OtherIter,
      typename std::enable_if<
          (!std::is_same<Iter, OtherIter>::value &&
           std::is_convertible<OtherIter, Iter>::value),
          int>::type = 0>
  constexpr /* implicit */ Range(const Range<OtherIter>& other)
      : b_(other.begin()), e_(other.end()) {}

  Range(const Range&) = default;
  Range(Range&&) = default;

  Range& operator=(const Range&) & = default;
  Range& operator=(Range&&) & = default;

  constexpr size_type size() const {
    return e_ - b_;
  }
  bool empty() const {
    return b_ == e_;
  }
  Iter data() const {
    return b_;
  }
  Iter begin() const {
    return b_;
  }
  Iter end() const {
    return e_;
  }

  void advance(size_type n) {
    if (UNLIKELY(n > size())) {
      throw std::out_of_range("index out of range");
    }
    b_ += n;
  }

  void subtract(size_type n) {
    if (UNLIKELY(n > size())) {
      throw std::out_of_range("index out of range");
    }
    e_ -= n;
  }

  Range subpiece(size_type first, size_type length = std::string::npos) const {
    if (UNLIKELY(first > size())) {
      throw std::out_of_range("index out of range");
    }

    return Range(b_ + first, std::min(length, size() - first));
  }
};

using ByteRange = Range<const unsigned char*>;
using MutableByteRange = Range<unsigned char*>;
using StringPiece = Range<const char*>;
}