/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #define FOLLY_GEN_STRING_H_ #include <folly/Range.h> #include <folly/gen/Base.h> #include <folly/io/IOBuf.h> namespace folly { namespace gen { namespace detail { class StringResplitter; template <class Delimiter> class SplitStringSource; template <class Delimiter, class Output> class Unsplit; template <class Delimiter, class OutputBuffer> class UnsplitBuffer; template <class TargetContainer, class Delimiter, class... Targets> class SplitTo; } // namespace detail /** * Split the output from a generator into StringPiece "lines" delimited by * the given delimiter. Delimters are NOT included in the output. * * resplit() behaves as if the input strings were concatenated into one long * string and then split. * * Equivalently, you can use StreamSplitter outside of a folly::gen setting. */ // make this a template so we don't require StringResplitter to be complete // until use template <class S = detail::StringResplitter> S resplit(char delimiter, bool keepDelimiter = false) { … } template <class S = detail::SplitStringSource<char>> S split(const StringPiece source, char delimiter) { … } template <class S = detail::SplitStringSource<StringPiece>> S split(StringPiece source, StringPiece delimiter) { … } /** * EOL terms ("\r", "\n", or "\r\n"). */ class MixedNewlines { … }; /** * Split by EOL ("\r", "\n", or "\r\n"). * @see split(). */ template <class S = detail::SplitStringSource<MixedNewlines>> S lines(StringPiece source) { … } /* * Joins a sequence of tokens into a string, with the chosen delimiter. * * E.G. * fbstring result = split("a,b,c", ",") | unsplit(","); * assert(result == "a,b,c"); * * std::string result = split("a,b,c", ",") | unsplit<std::string>(" "); * assert(result == "a b c"); */ // NOTE: The template arguments are reversed to allow the user to cleanly // specify the output type while still inferring the type of the delimiter. template < class Output = folly::fbstring, class Delimiter, class Unsplit = detail::Unsplit<Delimiter, Output>> Unsplit unsplit(const Delimiter& delimiter) { … } template < class Output = folly::fbstring, class Unsplit = detail::Unsplit<fbstring, Output>> Unsplit unsplit(const char* delimiter) { … } /* * Joins a sequence of tokens into a string, appending them to the output * buffer. If the output buffer is empty, an initial delimiter will not be * inserted at the start. * * E.G. * std::string buffer; * split("a,b,c", ",") | unsplit(",", &buffer); * assert(buffer == "a,b,c"); * * std::string anotherBuffer("initial"); * split("a,b,c", ",") | unsplit(",", &anotherbuffer); * assert(anotherBuffer == "initial,a,b,c"); */ template < class Delimiter, class OutputBuffer, class UnsplitBuffer = detail::UnsplitBuffer<Delimiter, OutputBuffer>> UnsplitBuffer unsplit(Delimiter delimiter, OutputBuffer* outputBuffer) { … } template < class OutputBuffer, class UnsplitBuffer = detail::UnsplitBuffer<fbstring, OutputBuffer>> UnsplitBuffer unsplit(const char* delimiter, OutputBuffer* outputBuffer) { … } template <class... Targets> detail::Map<detail::SplitTo<std::tuple<Targets...>, char, Targets...>> eachToTuple(char delim) { … } template <class... Targets> detail::Map<detail::SplitTo<std::tuple<Targets...>, fbstring, Targets...>> eachToTuple(StringPiece delim) { … } template <class First, class Second> detail::Map<detail::SplitTo<std::pair<First, Second>, char, First, Second>> eachToPair(char delim) { … } template <class First, class Second> detail::Map<detail::SplitTo<std::pair<First, Second>, fbstring, First, Second>> eachToPair(StringPiece delim) { … } /** * Outputs exactly the same bytes as the input stream, in different chunks. * A chunk boundary occurs after each delimiter, or, if maxLength is * non-zero, after maxLength bytes, whichever comes first. Your callback * can return false to stop consuming the stream at any time. * * The splitter buffers the last incomplete chunk, so you must call flush() * to consume the piece of the stream after the final delimiter. This piece * may be empty. After a flush(), the splitter can be re-used for a new * stream. * * operator() and flush() return false iff your callback returns false. The * internal buffer is not flushed, so reusing such a splitter will have * indeterminate results. Same goes if your callback throws. Feel free to * fix these corner cases if needed. * * Tips: * - Create via streamSplitter() to take advantage of template deduction. * - If your callback needs an end-of-stream signal, test for "no * trailing delimiter **and** shorter than maxLength". * - You can fine-tune the initial capacity of the internal IOBuf. */ template <class Callback> class StreamSplitter { … }; template <class Callback> // Helper to enable template deduction StreamSplitter<Callback> streamSplitter( char delimiter, Callback&& pieceCb, uint64_t capacity = 0) { … } } // namespace gen } // namespace folly #include <folly/gen/String-inl.h>