+template <bool exact, class Delim, class... OutputTypes>
+typename std::enable_if<
+ StrictConjunction<IsConvertible<OutputTypes>...>::value &&
+ sizeof...(OutputTypes) >= 1,
+ bool>::type
+split(const Delim& delimiter, StringPiece input, OutputTypes&... outputs) {
+ return detail::splitFixed<exact>(
+ detail::prepareDelim(delimiter), input, outputs...);
+}
+
+namespace detail {
+
+/*
+ * If a type can have its string size determined cheaply, we can more
+ * efficiently append it in a loop (see internalJoinAppend). Note that the
+ * struct need not conform to the std::string api completely (ex. does not need
+ * to implement append()).
+ */
+template <class T> struct IsSizableString {
+ enum { value = IsSomeString<T>::value
+ || std::is_same<T, StringPiece>::value };
+};
+
+template <class Iterator>
+struct IsSizableStringContainerIterator :
+ IsSizableString<typename std::iterator_traits<Iterator>::value_type> {
+};
+
+template <class Delim, class Iterator, class String>
+void internalJoinAppend(Delim delimiter,
+ Iterator begin,
+ Iterator end,
+ String& output) {
+ assert(begin != end);
+ if (std::is_same<Delim, StringPiece>::value &&
+ delimSize(delimiter) == 1) {
+ internalJoinAppend(delimFront(delimiter), begin, end, output);
+ return;
+ }
+ toAppend(*begin, &output);
+ while (++begin != end) {
+ toAppend(delimiter, *begin, &output);
+ }
+}
+
+template <class Delim, class Iterator, class String>
+typename std::enable_if<IsSizableStringContainerIterator<Iterator>::value>::type
+internalJoin(Delim delimiter,
+ Iterator begin,
+ Iterator end,
+ String& output) {
+ output.clear();
+ if (begin == end) {
+ return;
+ }
+ const size_t dsize = delimSize(delimiter);
+ Iterator it = begin;
+ size_t size = it->size();
+ while (++it != end) {
+ size += dsize + it->size();
+ }
+ output.reserve(size);
+ internalJoinAppend(delimiter, begin, end, output);
+}
+
+template <class Delim, class Iterator, class String>
+typename
+std::enable_if<!IsSizableStringContainerIterator<Iterator>::value>::type
+internalJoin(Delim delimiter,
+ Iterator begin,
+ Iterator end,
+ String& output) {
+ output.clear();
+ if (begin == end) {
+ return;
+ }
+ internalJoinAppend(delimiter, begin, end, output);
+}
+
+} // namespace detail
+
+template <class Delim, class Iterator, class String>
+void join(const Delim& delimiter,
+ Iterator begin,
+ Iterator end,
+ String& output) {
+ detail::internalJoin(
+ detail::prepareDelim(delimiter),
+ begin,
+ end,
+ output);
+}
+
+template <class OutputString>
+void backslashify(
+ folly::StringPiece input,
+ OutputString& output,
+ bool hex_style) {