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 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>> {
51 static constexpr size_t kDefaultLineSize = 256;
53 Generator(Source source, char delimiter)
54 : source_(std::move(source)), delimiter_(delimiter) { }
57 bool apply(Body&& body) const {
58 std::unique_ptr<IOBuf> buffer;
60 auto fn = [&](StringPiece in) -> bool {
62 bool found = splitPrefix(in, prefix, this->delimiter_);
63 if (found && buffer && buffer->length() != 0) {
64 // Append to end of buffer, return line
65 if (!prefix.empty()) {
66 buffer->reserve(0, prefix.size());
67 memcpy(buffer->writableTail(), prefix.data(), prefix.size());
68 buffer->append(prefix.size());
70 if (!body(StringPiece(ch(buffer->data()), buffer->length()))) {
74 found = splitPrefix(in, prefix, this->delimiter_);
76 // Buffer is empty, return lines directly from input (no buffer)
81 found = splitPrefix(in, prefix, this->delimiter_);
84 // Incomplete line left, append to buffer
86 // Arbitrarily assume that we have half a line and get enough
87 // room for twice that.
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