/**
* Convenience method that calls `split_step()` and passes the result to a
- * functor, returning whatever the functor does.
+ * functor, returning whatever the functor does. Any additional arguments
+ * `args` passed to this function are perfectly forwarded to the functor.
*
* Say you have a functor with this signature:
*
* // ...
* }
*
+ * struct Foo {
+ * void parse(folly::StringPiece s) {
+ * s.split_step(' ', parse_field, bar, 10);
+ * s.split_step('\t', parse_field, baz, 20);
+ *
+ * auto const kludge = [](folly::StringPiece x, int &out, int def) {
+ * if (x == "null") {
+ * out = 0;
+ * } else {
+ * parse_field(x, out, def);
+ * }
+ * };
+ *
+ * s.split_step('\t', kludge, gaz);
+ * s.split_step(' ', kludge, foo);
+ * }
+ *
+ * private:
+ * int bar;
+ * int baz;
+ * int gaz;
+ * int foo;
+ *
+ * static parse_field(folly::StringPiece s, int &out, int def) {
+ * try {
+ * out = folly::to<int>(s);
+ * } catch (std::exception const &) {
+ * value = def;
+ * }
+ * }
+ * };
+ *
* @author: Marcelo Juchem <marcelo@fb.com>
*/
- template <typename TProcess>
- auto split_step(value_type delimiter, TProcess &&process)
- -> decltype(process(std::declval<Range>()))
- { return process(split_step(delimiter)); }
-
- template <typename TProcess>
- auto split_step(Range delimiter, TProcess &&process)
- -> decltype(process(std::declval<Range>()))
- { return process(split_step(delimiter)); }
+ template <typename TProcess, typename... Args>
+ auto split_step(value_type delimiter, TProcess &&process, Args &&...args)
+ -> decltype(process(std::declval<Range>(), std::forward<Args>(args)...))
+ { return process(split_step(delimiter), std::forward<Args>(args)...); }
+
+ template <typename TProcess, typename... Args>
+ auto split_step(Range delimiter, TProcess &&process, Args &&...args)
+ -> decltype(process(std::declval<Range>(), std::forward<Args>(args)...))
+ { return process(split_step(delimiter), std::forward<Args>(args)...); }
private:
Iter b_, e_;
folly::StringPiece p(s);
EXPECT_EQ(s, p.begin());
EXPECT_EQ(e, p.end());
+ EXPECT_EQ(s, p);
auto x = p.split_step(' ');
EXPECT_EQ(std::next(s, 5), p.begin());
folly::StringPiece p(s);
EXPECT_EQ(s, p.begin());
EXPECT_EQ(e, p.end());
+ EXPECT_EQ(s, p);
auto x = p.split_step(" ");
EXPECT_EQ(std::next(s, 6), p.begin());
folly::StringPiece p(s);
EXPECT_EQ(s, p.begin());
EXPECT_EQ(e, p.end());
+ EXPECT_EQ(s, p);
EXPECT_EQ(1, (p.split_step(' ', [&](folly::StringPiece x) {
EXPECT_EQ(std::next(s, 5), p.begin());
folly::StringPiece p(s);
EXPECT_EQ(s, p.begin());
EXPECT_EQ(e, p.end());
+ EXPECT_EQ(s, p);
EXPECT_EQ(1, (p.split_step(" ", [&](folly::StringPiece x) {
EXPECT_EQ(std::next(s, 6), p.begin());
EXPECT_NO_THROW(p.split_step(' ', split_step_with_process_noop));
}
+TEST(StringPiece, split_step_with_process_char_delimiter_additional_args) {
+ // 0 1 2
+ // 012345678901234567890123456
+ auto const s = "this is just a test string";
+ auto const e = std::next(s, std::strlen(s));
+ auto const delimiter = ' ';
+ EXPECT_EQ('\0', *e);
+
+ folly::StringPiece p(s);
+ EXPECT_EQ(s, p.begin());
+ EXPECT_EQ(e, p.end());
+ EXPECT_EQ(s, p);
+
+ auto const functor = [](
+ folly::StringPiece s,
+ folly::StringPiece expected
+ ) {
+ EXPECT_EQ(expected, s);
+ return expected;
+ };
+
+ auto const checker = [&](folly::StringPiece expected) {
+ EXPECT_EQ(expected, p.split_step(delimiter, functor, expected));
+ };
+
+ checker("this");
+ checker("is");
+ checker("just");
+ checker("");
+ checker("a");
+ checker("test");
+ checker("string");
+ checker("");
+ checker("");
+
+ EXPECT_TRUE(p.empty());
+}
+
+TEST(StringPiece, split_step_with_process_range_delimiter_additional_args) {
+ // 0 1 2 3
+ // 0123456789012345678901234567890123
+ auto const s = "this is just a test string";
+ auto const e = std::next(s, std::strlen(s));
+ auto const delimiter = " ";
+ EXPECT_EQ('\0', *e);
+
+ folly::StringPiece p(s);
+ EXPECT_EQ(s, p.begin());
+ EXPECT_EQ(e, p.end());
+ EXPECT_EQ(s, p);
+
+ auto const functor = [](
+ folly::StringPiece s,
+ folly::StringPiece expected
+ ) {
+ EXPECT_EQ(expected, s);
+ return expected;
+ };
+
+ auto const checker = [&](folly::StringPiece expected) {
+ EXPECT_EQ(expected, p.split_step(delimiter, functor, expected));
+ };
+
+ checker("this");
+ checker("is");
+ checker("just");
+ checker("");
+ checker("a");
+ checker(" test");
+ checker("string");
+ checker("");
+ checker("");
+
+ EXPECT_TRUE(p.empty());
+}
+
TEST(qfind, UInt32_Ranges) {
vector<uint32_t> a({1, 2, 3, 260, 5});
vector<uint32_t> b({2, 3, 4});