Codemod: use #include angle brackets in folly and thrift
[folly.git] / folly / gen / String-inl.h
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef FOLLY_GEN_STRING_H
18 #error This file may only be included from folly/gen/String.h
19 #endif
20
21 #include <folly/Conv.h>
22 #include <folly/String.h>
23 #include <folly/io/IOBuf.h>
24
25 namespace folly {
26 namespace gen {
27 namespace detail {
28
29 inline bool splitPrefix(StringPiece& in,
30                         StringPiece& prefix,
31                         StringPiece delimiter) {
32   auto p = in.find(delimiter);
33   if (p != std::string::npos) {
34     prefix.assign(in.data(), in.data() + p);
35     in.advance(p + delimiter.size());
36     return true;
37   }
38   prefix.clear();
39   return false;
40 }
41
42 /**
43  * Split by any of the EOL terms: \r, \n, or \r\n.
44  */
45 inline bool splitPrefix(StringPiece& in,
46                         StringPiece& prefix,
47                         MixedNewlines) {
48   auto newline = "\r\n";
49   auto p = in.find_first_of(newline);
50   if (p != std::string::npos) {
51     prefix.assign(in.data(), in.data() + p);
52     in.advance(p);
53     if (!in.removePrefix(newline)) {
54       in.advance(1);
55     }
56     return true;
57   }
58   prefix.clear();
59   return false;
60 }
61
62 inline bool splitPrefix(StringPiece& in, StringPiece& prefix, char delimiter) {
63   auto p = static_cast<const char*>(memchr(in.data(), delimiter, in.size()));
64   if (p) {
65     prefix.assign(in.data(), p);
66     in.assign(p + 1, in.end());
67     return true;
68   }
69   prefix.clear();
70   return false;
71 }
72
73 inline const char* ch(const unsigned char* p) {
74   return reinterpret_cast<const char*>(p);
75 }
76
77 class StringResplitter : public Operator<StringResplitter> {
78   char delimiter_;
79  public:
80   explicit StringResplitter(char delimiter) : delimiter_(delimiter) { }
81
82   template <class Source>
83   class Generator : public GenImpl<StringPiece, Generator<Source>> {
84     Source source_;
85     char delimiter_;
86    public:
87     Generator(Source source, char delimiter)
88       : source_(std::move(source)), delimiter_(delimiter) { }
89
90     template <class Body>
91     bool apply(Body&& body) const {
92       std::unique_ptr<IOBuf> buffer;
93
94       auto fn = [&](StringPiece in) -> bool {
95         StringPiece prefix;
96         bool found = splitPrefix(in, prefix, this->delimiter_);
97         if (found && buffer && buffer->length() != 0) {
98           // Append to end of buffer, return line
99           if (!prefix.empty()) {
100             buffer->reserve(0, prefix.size());
101             memcpy(buffer->writableTail(), prefix.data(), prefix.size());
102             buffer->append(prefix.size());
103           }
104           if (!body(StringPiece(ch(buffer->data()), buffer->length()))) {
105             return false;
106           }
107           buffer->clear();
108           found = splitPrefix(in, prefix, this->delimiter_);
109         }
110         // Buffer is empty, return lines directly from input (no buffer)
111         while (found) {
112           if (!body(prefix)) {
113             return false;
114           }
115           found = splitPrefix(in, prefix, this->delimiter_);
116         }
117         if (!in.empty()) {
118           // Incomplete line left, append to buffer
119           if (!buffer) {
120             // Arbitrarily assume that we have half a line and get enough
121             // room for twice that.
122             constexpr size_t kDefaultLineSize = 256;
123             buffer = IOBuf::create(std::max(kDefaultLineSize, 2 * in.size()));
124           }
125           buffer->reserve(0, in.size());
126           memcpy(buffer->writableTail(), in.data(), in.size());
127           buffer->append(in.size());
128         }
129         return true;
130       };
131
132       // Iterate
133       if (!source_.apply(std::move(fn))) {
134         return false;
135       }
136
137       // Incomplete last line
138       if (buffer && buffer->length() != 0) {
139         if (!body(StringPiece(ch(buffer->data()), buffer->length()))) {
140           return false;
141         }
142       }
143       return true;
144     }
145
146     static constexpr bool infinite = Source::infinite;
147   };
148
149   template<class Source,
150            class Value,
151            class Gen = Generator<Source>>
152   Gen compose(GenImpl<Value, Source>&& source) const {
153     return Gen(std::move(source.self()), delimiter_);
154   }
155
156   template<class Source,
157            class Value,
158            class Gen = Generator<Source>>
159   Gen compose(const GenImpl<Value, Source>& source) const {
160     return Gen(source.self(), delimiter_);
161   }
162 };
163
164 template <class DelimiterType = char>
165 class SplitStringSource
166     : public GenImpl<StringPiece, SplitStringSource<DelimiterType>> {
167   StringPiece source_;
168   DelimiterType delimiter_;
169  public:
170   SplitStringSource(const StringPiece& source,
171                     DelimiterType delimiter)
172     : source_(source)
173     , delimiter_(std::move(delimiter)) { }
174
175   template <class Body>
176   bool apply(Body&& body) const {
177     StringPiece rest(source_);
178     StringPiece prefix;
179     while (splitPrefix(rest, prefix, this->delimiter_)) {
180       if (!body(prefix)) {
181         return false;
182       }
183     }
184     if (!rest.empty()) {
185       if (!body(rest)) {
186         return false;
187       }
188     }
189     return true;
190   }
191 };
192
193 /**
194  * Unsplit - For joining tokens from a generator into a string.  This is
195  * the inverse of `split` above.
196  *
197  * This type is primarily used through the 'unsplit' function.
198  */
199 template<class Delimiter,
200          class Output>
201 class Unsplit : public Operator<Unsplit<Delimiter, Output>> {
202   Delimiter delimiter_;
203  public:
204   explicit Unsplit(const Delimiter& delimiter)
205     : delimiter_(delimiter) {
206   }
207
208   template<class Source,
209            class Value>
210   Output compose(const GenImpl<Value, Source>& source) const {
211     Output outputBuffer;
212     UnsplitBuffer<Delimiter, Output> unsplitter(delimiter_, &outputBuffer);
213     unsplitter.compose(source);
214     return outputBuffer;
215   }
216 };
217
218 /**
219  * UnsplitBuffer - For joining tokens from a generator into a string,
220  * and inserting them into a custom buffer.
221  *
222  * This type is primarily used through the 'unsplit' function.
223  */
224 template<class Delimiter,
225          class OutputBuffer>
226 class UnsplitBuffer : public Operator<UnsplitBuffer<Delimiter, OutputBuffer>> {
227   Delimiter delimiter_;
228   OutputBuffer* outputBuffer_;
229  public:
230   UnsplitBuffer(const Delimiter& delimiter, OutputBuffer* outputBuffer)
231     : delimiter_(delimiter)
232     , outputBuffer_(outputBuffer) {
233     CHECK(outputBuffer);
234   }
235
236   template<class Source,
237            class Value>
238   void compose(const GenImpl<Value, Source>& source) const {
239     // If the output buffer is empty, we skip inserting the delimiter for the
240     // first element.
241     bool skipDelim = outputBuffer_->empty();
242     source | [&](Value v) {
243       if (skipDelim) {
244         skipDelim = false;
245         toAppend(std::forward<Value>(v), outputBuffer_);
246       } else {
247         toAppend(delimiter_, std::forward<Value>(v), outputBuffer_);
248       }
249     };
250   }
251 };
252
253
254 /**
255  * Hack for static for-like constructs
256  */
257 template<class Target, class=void>
258 inline Target passthrough(Target target) { return target; }
259
260 #pragma GCC diagnostic push
261 #ifdef __clang__
262 // Clang isn't happy with eatField() hack below.
263 #pragma GCC diagnostic ignored "-Wreturn-stack-address"
264 #endif  // __clang__
265
266 /**
267  * ParseToTuple - For splitting a record and immediatlely converting it to a
268  * target tuple type. Primary used through the 'eachToTuple' helper, like so:
269  *
270  *  auto config
271  *    = split("1:a 2:b", ' ')
272  *    | eachToTuple<int, string>()
273  *    | as<vector<tuple<int, string>>>();
274  *
275  */
276 template<class TargetContainer,
277          class Delimiter,
278          class... Targets>
279 class SplitTo {
280   Delimiter delimiter_;
281  public:
282   explicit SplitTo(Delimiter delimiter)
283     : delimiter_(delimiter) {}
284
285   TargetContainer operator()(StringPiece line) const {
286     int i = 0;
287     StringPiece fields[sizeof...(Targets)];
288     // HACK(tjackson): Used for referencing fields[] corresponding to variadic
289     // template parameters.
290     auto eatField = [&]() -> StringPiece& { return fields[i++]; };
291     if (!split(delimiter_,
292                line,
293                detail::passthrough<StringPiece&, Targets>(eatField())...)) {
294       throw std::runtime_error("field count mismatch");
295     }
296     i = 0;
297     return TargetContainer(To<Targets>()(eatField())...);
298   }
299 };
300
301 #pragma GCC diagnostic pop
302
303 }  // namespace detail
304
305 }  // namespace gen
306 }  // namespace folly