From: Marcelo Juchem Date: Tue, 3 Jun 2014 21:40:29 +0000 (-0700) Subject: Allowing additional arguments to be passed to split_step's functor X-Git-Tag: v0.22.0~518 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=3ed4f961b8a78a0806246254c140eef467aab202;p=folly.git Allowing additional arguments to be passed to split_step's functor Summary: more flexibility for using functors with split_step Test Plan: unit tests added + arc unit Reviewed By: ldbrandy@fb.com Subscribers: folly@lists FB internal diff: D1362644 --- diff --git a/folly/Range.h b/folly/Range.h index 0043c703..3d9e8d51 100644 --- a/folly/Range.h +++ b/folly/Range.h @@ -611,7 +611,8 @@ public: /** * 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: * @@ -636,17 +637,49 @@ public: * // ... * } * + * 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(s); + * } catch (std::exception const &) { + * value = def; + * } + * } + * }; + * * @author: Marcelo Juchem */ - template - auto split_step(value_type delimiter, TProcess &&process) - -> decltype(process(std::declval())) - { return process(split_step(delimiter)); } - - template - auto split_step(Range delimiter, TProcess &&process) - -> decltype(process(std::declval())) - { return process(split_step(delimiter)); } + template + auto split_step(value_type delimiter, TProcess &&process, Args &&...args) + -> decltype(process(std::declval(), std::forward(args)...)) + { return process(split_step(delimiter), std::forward(args)...); } + + template + auto split_step(Range delimiter, TProcess &&process, Args &&...args) + -> decltype(process(std::declval(), std::forward(args)...)) + { return process(split_step(delimiter), std::forward(args)...); } private: Iter b_, e_; diff --git a/folly/test/RangeTest.cpp b/folly/test/RangeTest.cpp index 681aa03d..8cbbfb09 100644 --- a/folly/test/RangeTest.cpp +++ b/folly/test/RangeTest.cpp @@ -439,6 +439,7 @@ TEST(StringPiece, split_step_char_delimiter) { 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()); @@ -496,6 +497,7 @@ TEST(StringPiece, split_step_range_delimiter) { 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()); @@ -560,6 +562,7 @@ TEST(StringPiece, split_step_with_process_char_delimiter) { 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()); @@ -642,6 +645,7 @@ TEST(StringPiece, split_step_with_process_range_delimiter) { 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()); @@ -721,6 +725,82 @@ TEST(StringPiece, split_step_with_process_range_delimiter) { 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 a({1, 2, 3, 260, 5}); vector b({2, 3, 4});