Commit faf7b5c6 authored by Tom Jackson's avatar Tom Jackson Committed by Sara Golemon

Promoting out of experimental

Summary:
At long last, promoting this out of experimental. Also, while I'm at
it, I've separated the tests and benchmarks into their corresponding parts.

Redirect headers provided.

Test Plan: Unit tests, contbuild.

Reviewed By: marcelo.juchem@fb.com

FB internal diff: D1151911
parent de873ac7
...@@ -13,35 +13,5 @@ ...@@ -13,35 +13,5 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma GCC message "folly::gen has moved to folly/gen/*.h"
#ifndef FOLLY_COMBINEGEN_H_ #include "folly/gen/Combine.h"
#define FOLLY_COMBINEGEN_H_
#include "folly/experimental/Gen.h"
namespace folly {
namespace gen {
namespace detail {
template<class Container>
class Interleave;
template<class Container>
class Zip;
} // namespace detail
template<class Source2,
class Source2Decayed = typename std::decay<Source2>::type,
class Interleave = detail::Interleave<Source2Decayed>>
Interleave interleave(Source2&& source2) {
return Interleave(std::forward<Source2>(source2));
}
} // namespace gen
} // namespace folly
#include "folly/experimental/CombineGen-inl.h"
#endif /* FOLLY_COMBINEGEN_H_ */
...@@ -13,61 +13,5 @@ ...@@ -13,61 +13,5 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma message "folly::gen has moved to folly/gen/*.h"
#ifndef FOLLY_FILEGEN_H_ #include "folly/gen/File.h"
#define FOLLY_FILEGEN_H_
#include "folly/File.h"
#include "folly/experimental/Gen.h"
#include "folly/io/IOBuf.h"
namespace folly {
namespace gen {
namespace detail {
class FileReader;
class FileWriter;
} // namespace detail
/**
* Generator that reads from a file with a buffer of the given size.
* Reads must be buffered (the generator interface expects the generator
* to hold each value).
*/
template <class S = detail::FileReader>
S fromFile(File file, size_t bufferSize=4096) {
return S(std::move(file), IOBuf::create(bufferSize));
}
/**
* Generator that reads from a file using a given buffer.
*/
template <class S = detail::FileReader>
S fromFile(File file, std::unique_ptr<IOBuf> buffer) {
return S(std::move(file), std::move(buffer));
}
/**
* Sink that writes to a file with a buffer of the given size.
* If bufferSize is 0, writes will be unbuffered.
*/
template <class S = detail::FileWriter>
S toFile(File file, size_t bufferSize=4096) {
return S(std::move(file), bufferSize ? nullptr : IOBuf::create(bufferSize));
}
/**
* Sink that writes to a file using a given buffer.
* If the buffer is nullptr, writes will be unbuffered.
*/
template <class S = detail::FileWriter>
S toFile(File file, std::unique_ptr<IOBuf> buffer) {
return S(std::move(file), std::move(buffer));
}
}} // !folly::gen
#include "folly/experimental/FileGen-inl.h"
#endif /* FOLLY_FILEGEN_H_ */
This diff is collapsed.
...@@ -13,144 +13,5 @@ ...@@ -13,144 +13,5 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma message "folly::gen has moved to folly/gen/*.h"
#ifndef FOLLY_STRINGGEN_H_ #include "folly/gen/String.h"
#define FOLLY_STRINGGEN_H_
#include "folly/Range.h"
#include "folly/experimental/Gen.h"
namespace folly {
namespace gen {
namespace detail {
class StringResplitter;
class SplitStringSource;
template<class Delimiter, class Output>
class Unsplit;
template<class Delimiter, class OutputBuffer>
class UnsplitBuffer;
template<class TargetContainer,
class Delimiter,
class... Targets>
class SplitTo;
} // namespace detail
/**
* Split the output from a generator into StringPiece "lines" delimited by
* the given delimiter. Delimters are NOT included in the output.
*
* resplit() behaves as if the input strings were concatenated into one long
* string and then split.
*/
// make this a template so we don't require StringResplitter to be complete
// until use
template <class S=detail::StringResplitter>
S resplit(char delimiter) {
return S(delimiter);
}
template <class S=detail::SplitStringSource>
S split(const StringPiece& source, char delimiter) {
return S(source, delimiter);
}
/*
* Joins a sequence of tokens into a string, with the chosen delimiter.
*
* E.G.
* fbstring result = split("a,b,c", ",") | unsplit(",");
* assert(result == "a,b,c");
*
* std::string result = split("a,b,c", ",") | unsplit<std::string>(" ");
* assert(result == "a b c");
*/
// NOTE: The template arguments are reversed to allow the user to cleanly
// specify the output type while still inferring the type of the delimiter.
template<class Output = folly::fbstring,
class Delimiter,
class Unsplit = detail::Unsplit<Delimiter, Output>>
Unsplit unsplit(const Delimiter& delimiter) {
return Unsplit(delimiter);
}
template<class Output = folly::fbstring,
class Unsplit = detail::Unsplit<fbstring, Output>>
Unsplit unsplit(const char* delimiter) {
return Unsplit(delimiter);
}
/*
* Joins a sequence of tokens into a string, appending them to the output
* buffer. If the output buffer is empty, an initial delimiter will not be
* inserted at the start.
*
* E.G.
* std::string buffer;
* split("a,b,c", ",") | unsplit(",", &buffer);
* assert(buffer == "a,b,c");
*
* std::string anotherBuffer("initial");
* split("a,b,c", ",") | unsplit(",", &anotherbuffer);
* assert(anotherBuffer == "initial,a,b,c");
*/
template<class Delimiter,
class OutputBuffer,
class UnsplitBuffer = detail::UnsplitBuffer<Delimiter, OutputBuffer>>
UnsplitBuffer unsplit(Delimiter delimiter, OutputBuffer* outputBuffer) {
return UnsplitBuffer(delimiter, outputBuffer);
}
template<class OutputBuffer,
class UnsplitBuffer = detail::UnsplitBuffer<fbstring, OutputBuffer>>
UnsplitBuffer unsplit(const char* delimiter, OutputBuffer* outputBuffer) {
return UnsplitBuffer(delimiter, outputBuffer);
}
template<class... Targets>
detail::Map<detail::SplitTo<std::tuple<Targets...>, char, Targets...>>
eachToTuple(char delim) {
return detail::Map<
detail::SplitTo<std::tuple<Targets...>, char, Targets...>>(
detail::SplitTo<std::tuple<Targets...>, char, Targets...>(delim));
}
template<class... Targets>
detail::Map<detail::SplitTo<std::tuple<Targets...>, fbstring, Targets...>>
eachToTuple(StringPiece delim) {
return detail::Map<
detail::SplitTo<std::tuple<Targets...>, fbstring, Targets...>>(
detail::SplitTo<std::tuple<Targets...>, fbstring, Targets...>(delim));
}
template<class First, class Second>
detail::Map<detail::SplitTo<std::pair<First, Second>, char, First, Second>>
eachToPair(char delim) {
return detail::Map<
detail::SplitTo<std::pair<First, Second>, char, First, Second>>(
detail::SplitTo<std::pair<First, Second>, char, First, Second>(delim));
}
template<class First, class Second>
detail::Map<detail::SplitTo<std::pair<First, Second>, fbstring, First, Second>>
eachToPair(StringPiece delim) {
return detail::Map<
detail::SplitTo<std::pair<First, Second>, fbstring, First, Second>>(
detail::SplitTo<std::pair<First, Second>, fbstring, First, Second>(
to<fbstring>(delim)));
}
} // namespace gen
} // namespace folly
#include "folly/experimental/StringGen-inl.h"
#endif /* FOLLY_STRINGGEN_H_ */
This diff is collapsed.
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
#ifndef FOLLY_COMBINEGEN_H_ #ifndef FOLLY_GEN_COMBINE_H
#error This file may only be included from folly/experimental/CombineGen.h #error This file may only be included from folly/gen/Combine.h
#endif #endif
#include <iterator> #include <iterator>
......
/*
* Copyright 2013 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOLLY_GEN_COMBINE_H
#define FOLLY_GEN_COMBINE_H
#include "folly/gen/Base.h"
namespace folly {
namespace gen {
namespace detail {
template<class Container>
class Interleave;
template<class Container>
class Zip;
} // namespace detail
template<class Source2,
class Source2Decayed = typename std::decay<Source2>::type,
class Interleave = detail::Interleave<Source2Decayed>>
Interleave interleave(Source2&& source2) {
return Interleave(std::forward<Source2>(source2));
}
} // namespace gen
} // namespace folly
#include "folly/gen/Combine-inl.h"
#endif // FOLLY_GEN_COMBINE_H
This diff is collapsed.
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOLLY_GEN_CORE_H
#define FOLLY_GEN_CORE_H
namespace folly { namespace gen {
template<class Value, class Self>
class GenImpl;
template<class Self>
class Operator;
namespace detail {
template<class Self>
struct FBounded;
template<class First, class Second>
class Composed;
template<class Value, class First, class Second>
class Chain;
} // detail
}} // folly::gen
#include "folly/gen/Core-inl.h"
#endif // FOLLY_GEN_CORE_H
...@@ -14,13 +14,13 @@ ...@@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
#ifndef FOLLY_FILEGEN_H_ #ifndef FOLLY_GEN_FILE_H
#error This file may only be included from folly/experimental/FileGen.h #error This file may only be included from folly/gen/File.h
#endif #endif
#include <system_error> #include <system_error>
#include "folly/experimental/StringGen.h" #include "folly/gen/String.h"
namespace folly { namespace folly {
namespace gen { namespace gen {
......
/*
* Copyright 2013 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOLLY_GEN_FILE_H
#define FOLLY_GEN_FILE_H
#include "folly/File.h"
#include "folly/gen/Base.h"
#include "folly/io/IOBuf.h"
namespace folly {
namespace gen {
namespace detail {
class FileReader;
class FileWriter;
} // namespace detail
/**
* Generator that reads from a file with a buffer of the given size.
* Reads must be buffered (the generator interface expects the generator
* to hold each value).
*/
template <class S = detail::FileReader>
S fromFile(File file, size_t bufferSize=4096) {
return S(std::move(file), IOBuf::create(bufferSize));
}
/**
* Generator that reads from a file using a given buffer.
*/
template <class S = detail::FileReader>
S fromFile(File file, std::unique_ptr<IOBuf> buffer) {
return S(std::move(file), std::move(buffer));
}
/**
* Sink that writes to a file with a buffer of the given size.
* If bufferSize is 0, writes will be unbuffered.
*/
template <class S = detail::FileWriter>
S toFile(File file, size_t bufferSize=4096) {
return S(std::move(file), bufferSize ? nullptr : IOBuf::create(bufferSize));
}
/**
* Sink that writes to a file using a given buffer.
* If the buffer is nullptr, writes will be unbuffered.
*/
template <class S = detail::FileWriter>
S toFile(File file, std::unique_ptr<IOBuf> buffer) {
return S(std::move(file), std::move(buffer));
}
}} // !folly::gen
#include "folly/gen/File-inl.h"
#endif // FOLLY_GEN_FILE_H
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
#ifndef FOLLY_STRINGGEN_H_ #ifndef FOLLY_GEN_STRING_H
#error This file may only be included from folly/experimental/StringGen.h #error This file may only be included from folly/gen/String.h
#endif #endif
#include "folly/Conv.h" #include "folly/Conv.h"
......
/*
* Copyright 2013 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOLLY_GEN_STRING_H
#define FOLLY_GEN_STRING_H
#include "folly/Range.h"
#include "folly/gen/Base.h"
namespace folly {
namespace gen {
namespace detail {
class StringResplitter;
class SplitStringSource;
template<class Delimiter, class Output>
class Unsplit;
template<class Delimiter, class OutputBuffer>
class UnsplitBuffer;
template<class TargetContainer,
class Delimiter,
class... Targets>
class SplitTo;
} // namespace detail
/**
* Split the output from a generator into StringPiece "lines" delimited by
* the given delimiter. Delimters are NOT included in the output.
*
* resplit() behaves as if the input strings were concatenated into one long
* string and then split.
*/
// make this a template so we don't require StringResplitter to be complete
// until use
template <class S=detail::StringResplitter>
S resplit(char delimiter) {
return S(delimiter);
}
template <class S=detail::SplitStringSource>
S split(const StringPiece& source, char delimiter) {
return S(source, delimiter);
}
/*
* Joins a sequence of tokens into a string, with the chosen delimiter.
*
* E.G.
* fbstring result = split("a,b,c", ",") | unsplit(",");
* assert(result == "a,b,c");
*
* std::string result = split("a,b,c", ",") | unsplit<std::string>(" ");
* assert(result == "a b c");
*/
// NOTE: The template arguments are reversed to allow the user to cleanly
// specify the output type while still inferring the type of the delimiter.
template<class Output = folly::fbstring,
class Delimiter,
class Unsplit = detail::Unsplit<Delimiter, Output>>
Unsplit unsplit(const Delimiter& delimiter) {
return Unsplit(delimiter);
}
template<class Output = folly::fbstring,
class Unsplit = detail::Unsplit<fbstring, Output>>
Unsplit unsplit(const char* delimiter) {
return Unsplit(delimiter);
}
/*
* Joins a sequence of tokens into a string, appending them to the output
* buffer. If the output buffer is empty, an initial delimiter will not be
* inserted at the start.
*
* E.G.
* std::string buffer;
* split("a,b,c", ",") | unsplit(",", &buffer);
* assert(buffer == "a,b,c");
*
* std::string anotherBuffer("initial");
* split("a,b,c", ",") | unsplit(",", &anotherbuffer);
* assert(anotherBuffer == "initial,a,b,c");
*/
template<class Delimiter,
class OutputBuffer,
class UnsplitBuffer = detail::UnsplitBuffer<Delimiter, OutputBuffer>>
UnsplitBuffer unsplit(Delimiter delimiter, OutputBuffer* outputBuffer) {
return UnsplitBuffer(delimiter, outputBuffer);
}
template<class OutputBuffer,
class UnsplitBuffer = detail::UnsplitBuffer<fbstring, OutputBuffer>>
UnsplitBuffer unsplit(const char* delimiter, OutputBuffer* outputBuffer) {
return UnsplitBuffer(delimiter, outputBuffer);
}
template<class... Targets>
detail::Map<detail::SplitTo<std::tuple<Targets...>, char, Targets...>>
eachToTuple(char delim) {
return detail::Map<
detail::SplitTo<std::tuple<Targets...>, char, Targets...>>(
detail::SplitTo<std::tuple<Targets...>, char, Targets...>(delim));
}
template<class... Targets>
detail::Map<detail::SplitTo<std::tuple<Targets...>, fbstring, Targets...>>
eachToTuple(StringPiece delim) {
return detail::Map<
detail::SplitTo<std::tuple<Targets...>, fbstring, Targets...>>(
detail::SplitTo<std::tuple<Targets...>, fbstring, Targets...>(delim));
}
template<class First, class Second>
detail::Map<detail::SplitTo<std::pair<First, Second>, char, First, Second>>
eachToPair(char delim) {
return detail::Map<
detail::SplitTo<std::pair<First, Second>, char, First, Second>>(
detail::SplitTo<std::pair<First, Second>, char, First, Second>(delim));
}
template<class First, class Second>
detail::Map<detail::SplitTo<std::pair<First, Second>, fbstring, First, Second>>
eachToPair(StringPiece delim) {
return detail::Map<
detail::SplitTo<std::pair<First, Second>, fbstring, First, Second>>(
detail::SplitTo<std::pair<First, Second>, fbstring, First, Second>(
to<fbstring>(delim)));
}
} // namespace gen
} // namespace folly
#include "folly/gen/String-inl.h"
#endif // FOLLY_GEN_STRING_H
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <atomic>
#include <glog/logging.h>
#include "folly/Benchmark.h"
#include "folly/gen/Base.h"
using namespace folly;
using namespace folly::gen;
using std::pair;
using std::set;
using std::vector;
using std::tuple;
static std::atomic<int> testSize(1000);
static vector<int> testVector =
seq(1, testSize.load())
| mapped([](int) { return rand(); })
| as<vector>();
static vector<vector<int>> testVectorVector =
seq(1, 100)
| map([](int i) {
return seq(1, i) | as<vector>();
})
| as<vector>();
static vector<fbstring> strings =
from(testVector)
| eachTo<fbstring>()
| as<vector>();
auto square = [](int x) { return x * x; };
auto add = [](int a, int b) { return a + b; };
auto multiply = [](int a, int b) { return a * b; };
BENCHMARK(Sum_Basic_NoGen, iters) {
int limit = testSize.load();
int s = 0;
while (iters--) {
for (int i = 0; i < limit; ++i) {
s += i;
}
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(Sum_Basic_Gen, iters) {
int limit = testSize.load();
int s = 0;
while (iters--) {
s += range(0, limit) | sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_DRAW_LINE()
BENCHMARK(Sum_Vector_NoGen, iters) {
int s = 0;
while (iters--) {
for (auto& i : testVector) {
s += i;
}
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(Sum_Vector_Gen, iters) {
int s = 0;
while (iters--) {
s += from(testVector) | sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_DRAW_LINE()
BENCHMARK(Member, iters) {
int s = 0;
while(iters--) {
s += from(strings)
| member(&fbstring::size)
| sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(MapMember, iters) {
int s = 0;
while(iters--) {
s += from(strings)
| map([](const fbstring& x) { return x.size(); })
| sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_DRAW_LINE()
BENCHMARK(Count_Vector_NoGen, iters) {
int s = 0;
while (iters--) {
for (auto& i : testVector) {
if (i * 2 < rand()) {
++s;
}
}
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(Count_Vector_Gen, iters) {
int s = 0;
while (iters--) {
s += from(testVector)
| filter([](int i) {
return i * 2 < rand();
})
| count;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_DRAW_LINE()
BENCHMARK(Fib_Sum_NoGen, iters) {
int s = 0;
while (iters--) {
auto fib = [](int limit) -> vector<int> {
vector<int> ret;
int a = 0;
int b = 1;
for (int i = 0; i * 2 < limit; ++i) {
ret.push_back(a += b);
ret.push_back(b += a);
}
return ret;
};
for (auto& v : fib(testSize.load())) {
s += v;
}
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(Fib_Sum_Gen, iters) {
int s = 0;
while (iters--) {
auto fib = GENERATOR(int) {
int a = 0;
int b = 1;
for (;;) {
yield(a += b);
yield(b += a);
}
};
s += fib | take(testSize.load()) | sum;
}
folly::doNotOptimizeAway(s);
}
struct FibYielder {
template<class Yield>
void operator()(Yield&& yield) const {
int a = 0;
int b = 1;
for (;;) {
yield(a += b);
yield(b += a);
}
}
};
BENCHMARK_RELATIVE(Fib_Sum_Gen_Static, iters) {
int s = 0;
while (iters--) {
auto fib = generator<int>(FibYielder());
s += fib | take(testSize.load()) | sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_DRAW_LINE()
BENCHMARK(VirtualGen_0Virtual, iters) {
int s = 0;
while (iters--) {
auto numbers = seq(1, 10000);
auto squares = numbers | map(square);
auto quads = squares | map(square);
s += quads | sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(VirtualGen_1Virtual, iters) {
int s = 0;
while (iters--) {
VirtualGen<int> numbers = seq(1, 10000);
auto squares = numbers | map(square);
auto quads = squares | map(square);
s += quads | sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(VirtualGen_2Virtual, iters) {
int s = 0;
while (iters--) {
VirtualGen<int> numbers = seq(1, 10000);
VirtualGen<int> squares = numbers | map(square);
auto quads = squares | map(square);
s += quads | sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(VirtualGen_3Virtual, iters) {
int s = 0;
while (iters--) {
VirtualGen<int> numbers = seq(1, 10000);
VirtualGen<int> squares = numbers | map(square);
VirtualGen<int> quads = squares | map(square);
s += quads | sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_DRAW_LINE()
BENCHMARK(Concat_NoGen, iters) {
int s = 0;
while (iters--) {
for (auto& v : testVectorVector) {
for (auto& i : v) {
s += i;
}
}
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(Concat_Gen, iters) {
int s = 0;
while (iters--) {
s += from(testVectorVector) | rconcat | sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_DRAW_LINE()
BENCHMARK(Composed_NoGen, iters) {
int s = 0;
while (iters--) {
for (auto& i : testVector) {
s += i * i;
}
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(Composed_Gen, iters) {
int s = 0;
auto sumSq = map(square) | sum;
while (iters--) {
s += from(testVector) | sumSq;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_RELATIVE(Composed_GenRegular, iters) {
int s = 0;
while (iters--) {
s += from(testVector) | map(square) | sum;
}
folly::doNotOptimizeAway(s);
}
BENCHMARK_DRAW_LINE()
BENCHMARK(Sample, iters) {
size_t s = 0;
while (iters--) {
auto sampler = seq(1, 10 * 1000 * 1000) | sample(1000);
s += (sampler | sum);
}
folly::doNotOptimizeAway(s);
}
// Results from an Intel(R) Xeon(R) CPU E5-2660 0 @ 2.20GHz
// ============================================================================
// folly/gen/test/BaseBenchmark.cpp relative time/iter iters/s
// ============================================================================
// Sum_Basic_NoGen 372.39ns 2.69M
// Sum_Basic_Gen 195.96% 190.03ns 5.26M
// ----------------------------------------------------------------------------
// Sum_Vector_NoGen 200.41ns 4.99M
// Sum_Vector_Gen 77.14% 259.81ns 3.85M
// ----------------------------------------------------------------------------
// Member 4.56us 219.42K
// MapMember 400.47% 1.14us 878.73K
// ----------------------------------------------------------------------------
// Count_Vector_NoGen 13.96us 71.64K
// Count_Vector_Gen 86.05% 16.22us 61.65K
// ----------------------------------------------------------------------------
// Fib_Sum_NoGen 2.21us 452.63K
// Fib_Sum_Gen 23.94% 9.23us 108.36K
// Fib_Sum_Gen_Static 48.77% 4.53us 220.73K
// ----------------------------------------------------------------------------
// VirtualGen_0Virtual 9.60us 104.13K
// VirtualGen_1Virtual 28.00% 34.30us 29.15K
// VirtualGen_2Virtual 22.62% 42.46us 23.55K
// VirtualGen_3Virtual 16.96% 56.64us 17.66K
// ----------------------------------------------------------------------------
// Concat_NoGen 2.20us 453.66K
// Concat_Gen 109.49% 2.01us 496.70K
// ----------------------------------------------------------------------------
// Composed_NoGen 545.32ns 1.83M
// Composed_Gen 87.94% 620.07ns 1.61M
// Composed_GenRegular 88.13% 618.74ns 1.62M
// ----------------------------------------------------------------------------
// Sample 176.48ms 5.67
// ============================================================================
int main(int argc, char *argv[]) {
google::ParseCommandLineFlags(&argc, &argv, true);
runBenchmarks();
return 0;
}
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <string>
#include <vector>
#include <tuple>
#include "folly/Range.h"
#include "folly/FBVector.h"
#include "folly/experimental/TestUtil.h"
#include "folly/gen/Base.h"
#include "folly/gen/Combine.h"
using namespace folly::gen;
using namespace folly;
using std::string;
using std::vector;
using std::tuple;
auto even = [](int i) -> bool { return i % 2 == 0; };
auto odd = [](int i) -> bool { return i % 2 == 1; };
TEST(CombineGen, Interleave) {
{ // large (infinite) base, small container
auto base = seq(1) | filter(odd);
auto toInterleave = seq(1, 6) | filter(even);
auto interleaved = base | interleave(toInterleave | as<vector>());
EXPECT_EQ(interleaved | as<vector>(), vector<int>({1, 2, 3, 4, 5, 6}));
}
{ // small base, large container
auto base = seq(1) | filter(odd) | take(3);
auto toInterleave = seq(1) | filter(even) | take(50);
auto interleaved = base | interleave(toInterleave | as<vector>());
EXPECT_EQ(interleaved | as<vector>(),
vector<int>({1, 2, 3, 4, 5, 6}));
}
}
TEST(CombineGen, Zip) {
auto base0 = seq(1);
// We rely on std::move(fbvector) emptying the source vector
auto zippee = fbvector<string>{"one", "two", "three"};
{
auto combined = base0
| zip(zippee)
| as<vector>();
ASSERT_EQ(combined.size(), 3);
EXPECT_EQ(std::get<0>(combined[0]), 1);
EXPECT_EQ(std::get<1>(combined[0]), "one");
EXPECT_EQ(std::get<0>(combined[1]), 2);
EXPECT_EQ(std::get<1>(combined[1]), "two");
EXPECT_EQ(std::get<0>(combined[2]), 3);
EXPECT_EQ(std::get<1>(combined[2]), "three");
ASSERT_FALSE(zippee.empty());
EXPECT_FALSE(zippee.front().empty()); // shouldn't have been move'd
}
{ // same as top, but using std::move.
auto combined = base0
| zip(std::move(zippee))
| as<vector>();
ASSERT_EQ(combined.size(), 3);
EXPECT_EQ(std::get<0>(combined[0]), 1);
EXPECT_TRUE(zippee.empty());
}
{ // same as top, but base is truncated
auto baseFinite = seq(1) | take(1);
auto combined = baseFinite
| zip(vector<string>{"one", "two", "three"})
| as<vector>();
ASSERT_EQ(combined.size(), 1);
EXPECT_EQ(std::get<0>(combined[0]), 1);
EXPECT_EQ(std::get<1>(combined[0]), "one");
}
}
TEST(CombineGen, TupleFlatten) {
vector<tuple<int,string>> intStringTupleVec{
tuple<int,string>{1, "1"},
tuple<int,string>{2, "2"},
tuple<int,string>{3, "3"},
};
vector<tuple<char>> charTupleVec{
tuple<char>{'A'},
tuple<char>{'B'},
tuple<char>{'C'},
tuple<char>{'D'},
};
vector<double> doubleVec{
1.0,
4.0,
9.0,
16.0,
25.0,
};
auto zipped1 = from(intStringTupleVec)
| zip(charTupleVec)
| assert_type<tuple<tuple<int, string>, tuple<char>>>()
| as<vector>();
EXPECT_EQ(std::get<0>(zipped1[0]), std::make_tuple(1, "1"));
EXPECT_EQ(std::get<1>(zipped1[0]), std::make_tuple('A'));
auto zipped2 = from(zipped1)
| tuple_flatten
| assert_type<tuple<int, string, char>&&>()
| as<vector>();
ASSERT_EQ(zipped2.size(), 3);
EXPECT_EQ(zipped2[0], std::make_tuple(1, "1", 'A'));
auto zipped3 = from(charTupleVec)
| zip(intStringTupleVec)
| tuple_flatten
| assert_type<tuple<char, int, string>&&>()
| as<vector>();
ASSERT_EQ(zipped3.size(), 3);
EXPECT_EQ(zipped3[0], std::make_tuple('A', 1, "1"));
auto zipped4 = from(intStringTupleVec)
| zip(doubleVec)
| tuple_flatten
| assert_type<tuple<int, string, double>&&>()
| as<vector>();
ASSERT_EQ(zipped4.size(), 3);
EXPECT_EQ(zipped4[0], std::make_tuple(1, "1", 1.0));
auto zipped5 = from(doubleVec)
| zip(doubleVec)
| assert_type<tuple<double, double>>()
| tuple_flatten // essentially a no-op
| assert_type<tuple<double, double>&&>()
| as<vector>();
ASSERT_EQ(zipped5.size(), 5);
EXPECT_EQ(zipped5[0], std::make_tuple(1.0, 1.0));
auto zipped6 = from(intStringTupleVec)
| zip(charTupleVec)
| tuple_flatten
| zip(doubleVec)
| tuple_flatten
| assert_type<tuple<int, string, char, double>&&>()
| as<vector>();
ASSERT_EQ(zipped6.size(), 3);
EXPECT_EQ(zipped6[0], std::make_tuple(1, "1", 'A', 1.0));
}
int main(int argc, char *argv[]) {
testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true);
return RUN_ALL_TESTS();
}
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <thread>
#include <glog/logging.h>
#include "folly/Benchmark.h"
#include "folly/File.h"
#include "folly/gen/Base.h"
#include "folly/gen/File.h"
using namespace folly::gen;
BENCHMARK(ByLine_Pipes, iters) {
std::thread thread;
int rfd;
int wfd;
BENCHMARK_SUSPEND {
int p[2];
CHECK_ERR(::pipe(p));
rfd = p[0];
wfd = p[1];
thread = std::thread([wfd, iters] {
char x = 'x';
PCHECK(::write(wfd, &x, 1) == 1); // signal startup
FILE* f = fdopen(wfd, "w");
PCHECK(f);
for (int i = 1; i <= iters; ++i) {
fprintf(f, "%d\n", i);
}
fclose(f);
});
char buf;
PCHECK(::read(rfd, &buf, 1) == 1); // wait for startup
}
auto s = byLine(folly::File(rfd)) | eachTo<int64_t>() | sum;
folly::doNotOptimizeAway(s);
BENCHMARK_SUSPEND {
::close(rfd);
CHECK_EQ(s, int64_t(iters) * (iters + 1) / 2);
thread.join();
}
}
// Results from an Intel(R) Xeon(R) CPU E5-2660 0 @ 2.20GHz
// ============================================================================
// folly/gen/test/FileBenchmark.cpp relative time/iter iters/s
// ============================================================================
// ByLine_Pipes 148.63ns 6.73M
// ============================================================================
int main(int argc, char *argv[]) {
google::ParseCommandLineFlags(&argc, &argv, true);
folly::runBenchmarks();
return 0;
}
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <string>
#include <vector>
#include "folly/File.h"
#include "folly/Range.h"
#include "folly/experimental/TestUtil.h"
#include "folly/gen/Base.h"
#include "folly/gen/File.h"
using namespace folly::gen;
using namespace folly;
using std::string;
using std::vector;
TEST(FileGen, ByLine) {
auto collect = eachTo<std::string>() | as<vector>();
test::TemporaryFile file("ByLine");
static const std::string lines(
"Hello world\n"
"This is the second line\n"
"\n"
"\n"
"a few empty lines above\n"
"incomplete last line");
EXPECT_EQ(lines.size(), write(file.fd(), lines.data(), lines.size()));
auto expected = from({lines}) | resplit('\n') | collect;
auto found = byLine(file.path().c_str()) | collect;
EXPECT_TRUE(expected == found);
}
class FileGenBufferedTest : public ::testing::TestWithParam<int> { };
TEST_P(FileGenBufferedTest, FileWriter) {
size_t bufferSize = GetParam();
test::TemporaryFile file("FileWriter");
static const std::string lines(
"Hello world\n"
"This is the second line\n"
"\n"
"\n"
"a few empty lines above\n");
auto src = from({lines, lines, lines, lines, lines, lines, lines, lines});
auto collect = eachTo<std::string>() | as<vector>();
auto expected = src | resplit('\n') | collect;
src | eachAs<StringPiece>() | toFile(File(file.fd()), bufferSize);
auto found = byLine(file.path().c_str()) | collect;
EXPECT_TRUE(expected == found);
}
INSTANTIATE_TEST_CASE_P(
DifferentBufferSizes,
FileGenBufferedTest,
::testing::Values(0, 1, 2, 4, 8, 64, 4096));
int main(int argc, char *argv[]) {
testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true);
return RUN_ALL_TESTS();
}
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <iosfwd>
#include <map>
#include <vector>
#include "folly/gen/String.h"
using namespace folly::gen;
using namespace folly;
using std::make_tuple;
using std::ostream;
using std::pair;
using std::string;
using std::tuple;
using std::unique_ptr;
using std::vector;
TEST(StringGen, EmptySplit) {
auto collect = eachTo<std::string>() | as<vector>();
{
auto pieces = split("", ',') | collect;
EXPECT_EQ(0, pieces.size());
}
// The last delimiter is eaten, just like std::getline
{
auto pieces = split(",", ',') | collect;
EXPECT_EQ(1, pieces.size());
EXPECT_EQ("", pieces[0]);
}
{
auto pieces = split(",,", ',') | collect;
EXPECT_EQ(2, pieces.size());
EXPECT_EQ("", pieces[0]);
EXPECT_EQ("", pieces[1]);
}
{
auto pieces = split(",,", ',') | take(1) | collect;
EXPECT_EQ(1, pieces.size());
EXPECT_EQ("", pieces[0]);
}
}
TEST(StringGen, Split) {
auto collect = eachTo<std::string>() | as<vector>();
{
auto pieces = split("hello,, world, goodbye, meow", ',') | collect;
EXPECT_EQ(5, pieces.size());
EXPECT_EQ("hello", pieces[0]);
EXPECT_EQ("", pieces[1]);
EXPECT_EQ(" world", pieces[2]);
EXPECT_EQ(" goodbye", pieces[3]);
EXPECT_EQ(" meow", pieces[4]);
}
{
auto pieces = split("hello,, world, goodbye, meow", ',')
| take(3) | collect;
EXPECT_EQ(3, pieces.size());
EXPECT_EQ("hello", pieces[0]);
EXPECT_EQ("", pieces[1]);
EXPECT_EQ(" world", pieces[2]);
}
{
auto pieces = split("hello,, world, goodbye, meow", ',')
| take(5) | collect;
EXPECT_EQ(5, pieces.size());
EXPECT_EQ("hello", pieces[0]);
EXPECT_EQ("", pieces[1]);
EXPECT_EQ(" world", pieces[2]);
}
}
TEST(StringGen, EmptyResplit) {
auto collect = eachTo<std::string>() | as<vector>();
{
auto pieces = from({""}) | resplit(',') | collect;
EXPECT_EQ(0, pieces.size());
}
// The last delimiter is eaten, just like std::getline
{
auto pieces = from({","}) | resplit(',') | collect;
EXPECT_EQ(1, pieces.size());
EXPECT_EQ("", pieces[0]);
}
{
auto pieces = from({",,"}) | resplit(',') | collect;
EXPECT_EQ(2, pieces.size());
EXPECT_EQ("", pieces[0]);
EXPECT_EQ("", pieces[1]);
}
}
TEST(StringGen, EachToTuple) {
{
auto lines = "2:1.414:yo 3:1.732:hi";
auto actual
= split(lines, ' ')
| eachToTuple<int, double, std::string>(':')
| as<vector>();
vector<tuple<int, double, std::string>> expected {
make_tuple(2, 1.414, "yo"),
make_tuple(3, 1.732, "hi"),
};
EXPECT_EQ(expected, actual);
}
{
auto lines = "2 3";
auto actual
= split(lines, ' ')
| eachToTuple<int>(',')
| as<vector>();
vector<tuple<int>> expected {
make_tuple(2),
make_tuple(3),
};
EXPECT_EQ(expected, actual);
}
{
// StringPiece target
auto lines = "1:cat 2:dog";
auto actual
= split(lines, ' ')
| eachToTuple<int, StringPiece>(':')
| as<vector>();
vector<tuple<int, StringPiece>> expected {
make_tuple(1, "cat"),
make_tuple(2, "dog"),
};
EXPECT_EQ(expected, actual);
}
{
// Empty field
auto lines = "2:tjackson:4 3::5";
auto actual
= split(lines, ' ')
| eachToTuple<int, fbstring, int>(':')
| as<vector>();
vector<tuple<int, fbstring, int>> expected {
make_tuple(2, "tjackson", 4),
make_tuple(3, "", 5),
};
EXPECT_EQ(expected, actual);
}
{
// Excess fields
auto lines = "1:2 3:4:5";
EXPECT_THROW((split(lines, ' ')
| eachToTuple<int, int>(':')
| as<vector>()),
std::runtime_error);
}
{
// Missing fields
auto lines = "1:2:3 4:5";
EXPECT_THROW((split(lines, ' ')
| eachToTuple<int, int, int>(':')
| as<vector>()),
std::runtime_error);
}
}
TEST(StringGen, EachToPair) {
{
// char delimiters
auto lines = "2:1.414 3:1.732";
auto actual
= split(lines, ' ')
| eachToPair<int, double>(':')
| as<std::map<int, double>>();
std::map<int, double> expected {
{ 3, 1.732 },
{ 2, 1.414 },
};
EXPECT_EQ(expected, actual);
}
{
// string delimiters
auto lines = "ab=>cd ef=>gh";
auto actual
= split(lines, ' ')
| eachToPair<string, string>("=>")
| as<std::map<string, string>>();
std::map<string, string> expected {
{ "ab", "cd" },
{ "ef", "gh" },
};
EXPECT_EQ(expected, actual);
}
}
TEST(StringGen, Resplit) {
auto collect = eachTo<std::string>() | as<vector>();
{
auto pieces = from({"hello,, world, goodbye, meow"}) |
resplit(',') | collect;
EXPECT_EQ(5, pieces.size());
EXPECT_EQ("hello", pieces[0]);
EXPECT_EQ("", pieces[1]);
EXPECT_EQ(" world", pieces[2]);
EXPECT_EQ(" goodbye", pieces[3]);
EXPECT_EQ(" meow", pieces[4]);
}
{
auto pieces = from({"hel", "lo,", ", world", ", goodbye, m", "eow"}) |
resplit(',') | collect;
EXPECT_EQ(5, pieces.size());
EXPECT_EQ("hello", pieces[0]);
EXPECT_EQ("", pieces[1]);
EXPECT_EQ(" world", pieces[2]);
EXPECT_EQ(" goodbye", pieces[3]);
EXPECT_EQ(" meow", pieces[4]);
}
}
template<typename F>
void runUnsplitSuite(F fn) {
fn("hello, world");
fn("hello,world,goodbye");
fn(" ");
fn("");
fn(", ");
fn(", a, b,c");
}
TEST(StringGen, Unsplit) {
auto basicFn = [](StringPiece s) {
EXPECT_EQ(split(s, ',') | unsplit(','), s);
};
auto existingBuffer = [](StringPiece s) {
folly::fbstring buffer("asdf");
split(s, ',') | unsplit(',', &buffer);
auto expected = folly::to<folly::fbstring>(
"asdf", s.empty() ? "" : ",", s);
EXPECT_EQ(expected, buffer);
};
auto emptyBuffer = [](StringPiece s) {
std::string buffer;
split(s, ',') | unsplit(',', &buffer);
EXPECT_EQ(s, buffer);
};
auto stringDelim = [](StringPiece s) {
EXPECT_EQ(s, split(s, ',') | unsplit(","));
std::string buffer;
split(s, ',') | unsplit(",", &buffer);
EXPECT_EQ(buffer, s);
};
runUnsplitSuite(basicFn);
runUnsplitSuite(existingBuffer);
runUnsplitSuite(emptyBuffer);
runUnsplitSuite(stringDelim);
EXPECT_EQ("1, 2, 3", seq(1, 3) | unsplit(", "));
}
int main(int argc, char *argv[]) {
testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true);
return RUN_ALL_TESTS();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment