Switch stripLeftMargin to not use boost::regex
authorMichael Lee <mzlee@fb.com>
Thu, 11 Feb 2016 02:51:43 +0000 (18:51 -0800)
committerfacebook-github-bot-1 <folly-bot@fb.com>
Thu, 11 Feb 2016 03:20:27 +0000 (19:20 -0800)
Summary: Remove boost regex from `stripLeftMargin`. We can shrink some binaries by not including it in the core folly library.

Reviewed By: yfeldblum

Differential Revision: D2922415

fb-gh-sync-id: cee89164c650706f0e5c07eed3d40500831918cd
shipit-source-id: cee89164c650706f0e5c07eed3d40500831918cd

folly/String.cpp
folly/test/StringTest.cpp

index 74ccb4ecf82312c5f58e0dff050bdee28bbdd664..6692c78337a11bd161378d6f1ce9a24037b87531 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <folly/String.h>
 
-#include <boost/regex.hpp>
 #include <folly/Format.h>
 #include <folly/ScopeGuard.h>
 
@@ -550,22 +549,47 @@ size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
 } // namespace detail
 
 std::string stripLeftMargin(std::string s) {
-  using namespace boost;
-  static const auto kPre = regex(R"(\A[ \t]*\n)");
-  static const auto kPost = regex(R"([ \t]+\z)");
-  static const auto kScan = regex(R"(^[ \t]*(?=\S))");
-  s = regex_replace(s, kPre, "");
-  s = regex_replace(s, kPost, "");
+  std::vector<StringPiece> pieces;
+  split("\n", s, pieces);
+  auto piecer = range(pieces);
+
+  auto piece = (piecer.end() - 1);
+  auto needle = std::find_if(piece->begin(),
+                             piece->end(),
+                             [](char c) { return c != ' ' && c != '\t'; });
+  if (needle == piece->end()) {
+    (piecer.end() - 1)->clear();
+  }
+  piece = piecer.begin();
+  needle = std::find_if(piece->begin(),
+                        piece->end(),
+                        [](char c) { return c != ' ' && c != '\t'; });
+  if (needle == piece->end()) {
+    piecer.erase(piecer.begin(), piecer.begin() + 1);
+  }
+
   const auto sentinel = std::numeric_limits<size_t>::max();
   auto indent = sentinel;
-  sregex_iterator it(s.cbegin(), s.cend(), kScan);
-  sregex_iterator itend;
-  for (; it != itend; ++it) {
-    indent = std::min<size_t>(indent, it->length());
+  size_t max_length = 0;
+  for (auto piece = piecer.begin(); piece != piecer.end(); piece++) {
+    needle = std::find_if(piece->begin(),
+                          piece->end(),
+                          [](char c) { return c != ' ' && c != '\t'; });
+    if (needle != piece->end()) {
+      indent = std::min<size_t>(indent, needle - piece->begin());
+    } else {
+      max_length = std::max<size_t>(piece->size(), max_length);
+    }
+  }
+  indent = indent == sentinel ? max_length : indent;
+  for (auto& piece : piecer) {
+    if (piece.size() < indent) {
+      piece.clear();
+    } else {
+      piece.erase(piece.begin(), piece.begin() + indent);
+    }
   }
-  indent = indent == sentinel ? 0 : indent;
-  s = regex_replace(s, regex(sformat(R"(^[ \t]{{0,{0}}})", indent)), "");
-  return s;
+  return join("\n", piecer);
 }
 
 }   // namespace folly
index 72e87521582cd3777f85599d6ad755a45315233f..4b6523e859b34827e684ed6603315ea8a458fa14 100644 (file)
@@ -1135,6 +1135,12 @@ TEST(String, whitespace) {
   EXPECT_EQ("", rtrimWhitespace("\r   "));
 }
 
+TEST(String, stripLeftMargin_really_empty) {
+  auto input = "";
+  auto expected = "";
+  EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
 TEST(String, stripLeftMargin_empty) {
   auto input = R"TEXT(
   )TEXT";
@@ -1142,6 +1148,30 @@ TEST(String, stripLeftMargin_empty) {
   EXPECT_EQ(expected, stripLeftMargin(input));
 }
 
+TEST(String, stripLeftMargin_only_whitespace) {
+  //  using ~ as a marker
+  string input = R"TEXT(
+    ~
+  )TEXT";
+  input = boost::regex_replace(input, boost::regex("~"), "");
+  EXPECT_EQ("\n    \n  ", input);
+  auto expected = "\n";
+  EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_only_uneven_whitespace) {
+  //  using ~ as a marker1
+  string input = R"TEXT(
+    ~
+      ~
+  )TEXT";
+  input = boost::regex_replace(input, boost::regex("~"), "");
+  EXPECT_EQ("\n    \n      \n  ", input);
+  auto expected = "\n\n";
+
+  EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
 TEST(String, stripLeftMargin_one_line) {
   auto input = R"TEXT(
     hi there bob!
@@ -1241,6 +1271,30 @@ TEST(String, stripLeftMargin_interstitial_indented_whiteline) {
   EXPECT_EQ(expected, stripLeftMargin(input));
 }
 
+TEST(String, stripLeftMargin_no_pre_whitespace) {
+  //  using ~ as a marker
+  string input = R"TEXT(      hi there bob!
+        ~
+      so long!
+  )TEXT";
+  input = boost::regex_replace(input, boost::regex("~"), "");
+  EXPECT_EQ("      hi there bob!\n        \n      so long!\n  ", input);
+  auto expected = "hi there bob!\n  \nso long!\n";
+  EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_no_post_whitespace) {
+  //  using ~ as a marker
+  string input = R"TEXT(
+      hi there bob!
+        ~
+      so long!  )TEXT";
+  input = boost::regex_replace(input, boost::regex("~"), "");
+  EXPECT_EQ("\n      hi there bob!\n        \n      so long!  ", input);
+  auto expected = "hi there bob!\n  \nso long!  ";
+  EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
 const folly::StringPiece kTestUTF8 = "This is \U0001F602 stuff!";
 
 TEST(UTF8StringPiece, valid_utf8) {