2 * Copyright 2012 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef FOLLY_STRINGGEN_H_
18 #error This file may only be included from folly/experimental/StringGen.h
21 #include "folly/experimental/io/IOBuf.h"
27 inline bool splitPrefix(StringPiece& in, StringPiece& prefix, char delimiter) {
28 auto p = static_cast<const char*>(memchr(in.data(), delimiter, in.size()));
30 prefix.assign(in.data(), p);
31 in.assign(p + 1, in.end());
38 inline const char* ch(const unsigned char* p) {
39 return reinterpret_cast<const char*>(p);
42 class StringResplitter : public Operator<StringResplitter> {
45 explicit StringResplitter(char delimiter) : delimiter_(delimiter) { }
47 template <class Source>
48 class Generator : public GenImpl<StringPiece, Generator<Source>> {
52 Generator(Source source, char delimiter)
53 : source_(std::move(source)), delimiter_(delimiter) { }
56 bool apply(Body&& body) const {
57 std::unique_ptr<IOBuf> buffer;
59 auto fn = [&](StringPiece in) -> bool {
61 bool found = splitPrefix(in, prefix, this->delimiter_);
62 if (found && buffer && buffer->length() != 0) {
63 // Append to end of buffer, return line
64 if (!prefix.empty()) {
65 buffer->reserve(0, prefix.size());
66 memcpy(buffer->writableTail(), prefix.data(), prefix.size());
67 buffer->append(prefix.size());
69 if (!body(StringPiece(ch(buffer->data()), buffer->length()))) {
73 found = splitPrefix(in, prefix, this->delimiter_);
75 // Buffer is empty, return lines directly from input (no buffer)
80 found = splitPrefix(in, prefix, this->delimiter_);
83 // Incomplete line left, append to buffer
85 // Arbitrarily assume that we have half a line and get enough
86 // room for twice that.
87 constexpr size_t kDefaultLineSize = 256;
88 buffer = IOBuf::create(std::max(kDefaultLineSize, 2 * in.size()));
90 buffer->reserve(0, in.size());
91 memcpy(buffer->writableTail(), in.data(), in.size());
92 buffer->append(in.size());
98 if (!source_.apply(std::move(fn))) {
102 // Incomplete last line
103 if (buffer && buffer->length() != 0) {
104 if (!body(StringPiece(ch(buffer->data()), buffer->length()))) {
112 template<class Source,
114 class Gen = Generator<Source>>
115 Gen compose(GenImpl<Value, Source>&& source) const {
116 return Gen(std::move(source.self()), delimiter_);
119 template<class Source,
121 class Gen = Generator<Source>>
122 Gen compose(const GenImpl<Value, Source>& source) const {
123 return Gen(source.self(), delimiter_);
127 class SplitStringSource : public GenImpl<StringPiece, SplitStringSource> {
131 SplitStringSource(const StringPiece& source,
134 , delimiter_(delimiter) { }
136 template <class Body>
137 bool apply(Body&& body) const {
138 StringPiece rest(source_);
140 while (splitPrefix(rest, prefix, this->delimiter_)) {
155 } // namespace detail