From c72f7f6887de816d9f2bda14c0c460e3d2386c47 Mon Sep 17 00:00:00 2001 From: Michael Lee Date: Wed, 10 Feb 2016 18:51:43 -0800 Subject: [PATCH] Switch stripLeftMargin to not use boost::regex 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 | 52 +++++++++++++++++++++++++++---------- folly/test/StringTest.cpp | 54 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/folly/String.cpp b/folly/String.cpp index 74ccb4ec..6692c783 100644 --- a/folly/String.cpp +++ b/folly/String.cpp @@ -16,7 +16,6 @@ #include -#include #include #include @@ -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 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::max(); auto indent = sentinel; - sregex_iterator it(s.cbegin(), s.cend(), kScan); - sregex_iterator itend; - for (; it != itend; ++it) { - indent = std::min(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(indent, needle - piece->begin()); + } else { + max_length = std::max(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 diff --git a/folly/test/StringTest.cpp b/folly/test/StringTest.cpp index 72e87521..4b6523e8 100644 --- a/folly/test/StringTest.cpp +++ b/folly/test/StringTest.cpp @@ -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) { -- 2.34.1