summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_string.h
blob: 90e64f98a25874f27c7bd40169cfac3a1f5ebcf9 (plain)
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab ft=cpp

#ifndef CEPH_RGW_STRING_H
#define CEPH_RGW_STRING_H

#include <errno.h>
#include <stdlib.h>
#include <limits.h>
#include <string_view>
#include <string>
#include <stdexcept>

#include <boost/container/small_vector.hpp>

struct ltstr_nocase
{
  bool operator()(const std::string& s1, const std::string& s2) const
  {
    return strcasecmp(s1.c_str(), s2.c_str()) < 0;
  }
};

static inline int stringcasecmp(const std::string& s1, const std::string& s2)
{
  return strcasecmp(s1.c_str(), s2.c_str());
}

static inline int stringcasecmp(const std::string& s1, const char *s2)
{
  return strcasecmp(s1.c_str(), s2);
}

static inline int stringcasecmp(const std::string& s1, int ofs, int size, const std::string& s2)
{
  return strncasecmp(s1.c_str() + ofs, s2.c_str(), size);
}

static inline int stringtoll(const std::string& s, int64_t *val)
{
  char *end;

  long long result = strtoll(s.c_str(), &end, 10);
  if (result == LLONG_MAX)
    return -EINVAL;

  if (*end)
    return -EINVAL;

  *val = (int64_t)result;

  return 0;
}

static inline int stringtoull(const std::string& s, uint64_t *val)
{
  char *end;

  unsigned long long result = strtoull(s.c_str(), &end, 10);
  if (result == ULLONG_MAX)
    return -EINVAL;

  if (*end)
    return -EINVAL;

  *val = (uint64_t)result;

  return 0;
}

static inline int stringtol(const std::string& s, int32_t *val)
{
  char *end;

  long result = strtol(s.c_str(), &end, 10);
  if (result == LONG_MAX)
    return -EINVAL;

  if (*end)
    return -EINVAL;

  *val = (int32_t)result;

  return 0;
}

static inline int stringtoul(const std::string& s, uint32_t *val)
{
  char *end;

  unsigned long result = strtoul(s.c_str(), &end, 10);
  if (result == ULONG_MAX)
    return -EINVAL;

  if (*end)
    return -EINVAL;

  *val = (uint32_t)result;

  return 0;
}

/* A converter between std::string_view and null-terminated C-strings.
 * It copies memory while trying to utilize the local memory instead of
 * issuing dynamic allocations. */
template<std::size_t N = 128>
static inline boost::container::small_vector<char, N>
sview2cstr(const std::string_view& sv)
{
  boost::container::small_vector<char, N> cstr;
  cstr.reserve(sv.size() + sizeof('\0'));

  cstr.assign(std::begin(sv), std::end(sv));
  cstr.push_back('\0');

  return cstr;
}

/* std::strlen() isn't guaranteed to be computable at compile-time. Although
 * newer GCCs actually do that, Clang doesn't. Please be aware this function
 * IS NOT A DROP-IN REPLACEMENT FOR STRLEN -- it returns a different result
 * for strings having \0 in the middle. */
template<size_t N>
static inline constexpr size_t sarrlen(const char (&arr)[N]) {
  return N - 1;
}

namespace detail {

// variadic sum() to add up string lengths for reserve()
static inline constexpr size_t sum() { return 0; }
template <typename... Args>
constexpr size_t sum(size_t v, Args... args) { return v + sum(args...); }

// traits for string_size()
template <typename T>
struct string_traits {
  static constexpr size_t size(const T& s) { return s.size(); }
};
// specializations for char*/const char* use strlen()
template <>
struct string_traits<const char*> {
  static size_t size(const char* s) { return std::strlen(s); }
};
template <>
struct string_traits<char*> : string_traits<const char*> {};
// constexpr specializations for char[]/const char[]
template <std::size_t N>
struct string_traits<const char[N]> {
  static constexpr size_t size_(const char* s, size_t i) {
    return i < N ? (*(s + i) == '\0' ? i : size_(s, i + 1))
        : throw std::invalid_argument("Unterminated string constant.");
  }
  static constexpr size_t size(const char(&s)[N]) { return size_(s, 0); }
};
template <std::size_t N>
struct string_traits<char[N]> : string_traits<const char[N]> {};

// helpers for string_cat_reserve()
static inline void append_to(std::string& s) {}
template <typename... Args>
void append_to(std::string& s, const std::string_view& v, const Args&... args)
{
  s.append(v.begin(), v.end());
  append_to(s, args...);
}

// helpers for string_join_reserve()
static inline void join_next(std::string& s, const std::string_view& d) {}
template <typename... Args>
void join_next(std::string& s, const std::string_view& d,
               const std::string_view& v, const Args&... args)
{
  s.append(d.begin(), d.end());
  s.append(v.begin(), v.end());
  join_next(s, d, args...);
}

static inline void join(std::string& s, const std::string_view& d) {}
template <typename... Args>
void join(std::string& s, const std::string_view& d,
          const std::string_view& v, const Args&... args)
{
  s.append(v.begin(), v.end());
  join_next(s, d, args...);
}

} // namespace detail

/// return the length of a c string, string literal, or string type
template <typename T>
constexpr size_t string_size(const T& s)
{
  return detail::string_traits<T>::size(s);
}

/// concatenates the given string arguments, returning as a std::string that
/// gets preallocated with reserve()
template <typename... Args>
std::string string_cat_reserve(const Args&... args)
{
  size_t total_size = detail::sum(string_size(args)...);
  std::string result;
  result.reserve(total_size);
  detail::append_to(result, args...);
  return result;
}

/// joins the given string arguments with a delimiter, returning as a
/// std::string that gets preallocated with reserve()
template <typename... Args>
std::string string_join_reserve(const std::string_view& delim,
                                const Args&... args)
{
  size_t delim_size = delim.size() * std::max<ssize_t>(0, sizeof...(args) - 1);
  size_t total_size = detail::sum(string_size(args)...) + delim_size;
  std::string result;
  result.reserve(total_size);
  detail::join(result, delim, args...);
  return result;
}
template <typename... Args>
std::string string_join_reserve(char delim, const Args&... args)
{
  return string_join_reserve(std::string_view{&delim, 1}, args...);
}


/// use case-insensitive comparison in match_wildcards()
static constexpr uint32_t MATCH_CASE_INSENSITIVE = 0x01;

/// attempt to match the given input string with the pattern, which may contain
/// the wildcard characters * and ?
extern bool match_wildcards(std::string_view pattern,
                            std::string_view input,
                            uint32_t flags = 0);

#endif