made toAppendDelim better
authorMarcin Pawlowski <mpawlowski@fb.com>
Wed, 20 Aug 2014 05:25:05 +0000 (22:25 -0700)
committerSara Golemon <sgolemon@fb.com>
Tue, 9 Sep 2014 21:22:22 +0000 (14:22 -0700)
Summary:
preallocate once and for all, so that we
are really malloc efficient in toAppendDelim

Test Plan: unit tests

Reviewed By: marcelo.juchem@fb.com

FB internal diff: D1496310

Tasks: 4886092

folly/Conv.h

index 83b36be801e5bd3af40a6def49269b44776e67c6..c624b1994cbb0899759640b470b3babb6f005579 100644 (file)
@@ -655,7 +655,14 @@ size_t estimateSpaceToReserve(size_t sofar, const T& v) {
 
 template<class...Ts>
 void reserveInTarget(const Ts&...vs) {
-  getLastElement(vs...)->reserve(detail::estimateSpaceToReserve(0, vs...));
+  getLastElement(vs...)->reserve(estimateSpaceToReserve(0, vs...));
+}
+
+template<class Delimiter, class...Ts>
+void reserveInTargetDelim(const Delimiter& d, const Ts&...vs) {
+  static_assert(sizeof...(vs) >= 2, "Needs at least 2 args");
+  size_t fordelim = (sizeof...(vs) - 2) * estimateSpaceToReserve(0, d);
+  getLastElement(vs...)->reserve(estimateSpaceToReserve(fordelim, vs...));
 }
 
 /**
@@ -679,6 +686,29 @@ toAppendStrImpl(const T& v, const Ts&... vs) {
   toAppend(v, getLastElement(vs...));
   toAppendStrImpl(vs...);
 }
+
+template <class Delimiter, class T, class Tgt>
+typename std::enable_if<
+  IsSomeString<typename std::remove_pointer<Tgt>::type>
+  ::value>::type
+toAppendDelimStrImpl(const Delimiter& delim, const T& v, Tgt result) {
+  toAppend(v, result);
+}
+
+template <class Delimiter, class T, class... Ts>
+typename std::enable_if<sizeof...(Ts) >= 2
+  && IsSomeString<
+  typename std::remove_pointer<
+    typename detail::last_element<Ts...>::type
+  >::type>::value>::type
+toAppendDelimStrImpl(const Delimiter& delim, const T& v, const Ts&... vs) {
+  // we are really careful here, calling toAppend with just one element does
+  // not try to estimate space needed (as we already did that). If we call
+  // toAppend(v, delim, ....) we would do unnecesary size calculation
+  toAppend(v, detail::getLastElement(vs...));
+  toAppend(delim, detail::getLastElement(vs...));
+  toAppendDelimStrImpl(delim, vs...);
+}
 } // folly::detail
 
 
@@ -726,15 +756,15 @@ toAppendDelim(const Delimiter& delim, const T& v, Tgt* tgt) {
 /**
  * Append to string with a delimiter in between elements.
  */
-template <class Delimiter, class T, class... Ts>
-typename std::enable_if<sizeof...(Ts) >= 2
+template <class Delimiter, class... Ts>
+typename std::enable_if<sizeof...(Ts) >= 3
   && IsSomeString<
   typename std::remove_pointer<
     typename detail::last_element<Ts...>::type
   >::type>::value>::type
-toAppendDelim(const Delimiter& delim, const T& v, const Ts&... vs) {
-  toAppend(v, delim, detail::getLastElement(vs...));
-  toAppendDelim(delim, vs...);
+toAppendDelim(const Delimiter& delim, const Ts&... vs) {
+  detail::reserveInTargetDelim(delim, vs...);
+  detail::toAppendDelimStrImpl(delim, vs...);
 }
 
 /**