2 * Copyright 2014 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #ifndef FOLLY_GEN_COMBINE_H
18 #error This file may only be included from folly/gen/Combine.h
22 #include <system_error>
24 #include <type_traits>
33 * Alternate values from a sequence with values from a sequence container.
34 * Stops once we run out of values from either source.
36 template<class Container>
37 class Interleave : public Operator<Interleave<Container>> {
38 // see comment about copies in CopiedSource
39 const std::shared_ptr<const Container> container_;
41 explicit Interleave(Container container)
42 : container_(new Container(std::move(container))) {}
46 class Generator : public GenImpl<Value, Generator<Value, Source>> {
48 const std::shared_ptr<const Container> container_;
49 typedef const typename Container::value_type& ConstRefType;
51 static_assert(std::is_same<const Value&, ConstRefType>::value,
52 "Only matching types may be interleaved");
54 explicit Generator(Source source,
55 const std::shared_ptr<const Container> container)
56 : source_(std::move(source)),
57 container_(container) { }
59 template<class Handler>
60 bool apply(Handler&& handler) const {
61 auto iter = container_->begin();
62 return source_.apply([&](const Value& value) -> bool {
63 if (iter == container_->end()) {
66 if (!handler(value)) {
69 if (!handler(*iter)) {
78 template<class Value2,
80 class Gen = Generator<Value2,Source>>
81 Gen compose(GenImpl<Value2, Source>&& source) const {
82 return Gen(std::move(source.self()), container_);
85 template<class Value2,
87 class Gen = Generator<Value2,Source>>
88 Gen compose(const GenImpl<Value2, Source>& source) const {
89 return Gen(source.self(), container_);
96 * Combine inputs from Source with values from a sequence container by merging
100 template<class Container>
101 class Zip : public Operator<Zip<Container>> {
102 // see comment about copies in CopiedSource
103 const std::shared_ptr<const Container> container_;
105 explicit Zip(Container container)
106 : container_(new Container(std::move(container))) {}
108 template<class Value1,
110 class Value2 = decltype(*std::begin(*container_)),
111 class Result = std::tuple<typename std::decay<Value1>::type,
112 typename std::decay<Value2>::type>>
113 class Generator : public GenImpl<Result,
114 Generator<Value1,Source,Value2,Result>> {
116 const std::shared_ptr<const Container> container_;
118 explicit Generator(Source source,
119 const std::shared_ptr<const Container> container)
120 : source_(std::move(source)),
121 container_(container) { }
123 template<class Handler>
124 bool apply(Handler&& handler) const {
125 auto iter = container_->begin();
126 return (source_.apply([&](Value1 value) -> bool {
127 if (iter == container_->end()) {
130 if (!handler(std::make_tuple(std::forward<Value1>(value), *iter))) {
139 template<class Source,
141 class Gen = Generator<Value, Source>>
142 Gen compose(GenImpl<Value, Source>&& source) const {
143 return Gen(std::move(source.self()), container_);
146 template<class Source,
148 class Gen = Generator<Value, Source>>
149 Gen compose(const GenImpl<Value, Source>& source) const {
150 return Gen(source.self(), container_);
154 template<class... Types1,
156 auto add_to_tuple(std::tuple<Types1...> t1, std::tuple<Types2...> t2) ->
157 std::tuple<Types1..., Types2...> {
158 return std::tuple_cat(std::move(t1), std::move(t2));
161 template<class... Types1,
163 auto add_to_tuple(std::tuple<Types1...> t1, Type2&& t2) ->
164 decltype(std::tuple_cat(std::move(t1),
165 std::make_tuple(std::forward<Type2>(t2)))) {
166 return std::tuple_cat(std::move(t1),
167 std::make_tuple(std::forward<Type2>(t2)));
170 template<class Type1,
172 auto add_to_tuple(Type1&& t1, std::tuple<Types2...> t2) ->
173 decltype(std::tuple_cat(std::make_tuple(std::forward<Type1>(t1)),
175 return std::tuple_cat(std::make_tuple(std::forward<Type1>(t1)),
179 template<class Type1,
181 auto add_to_tuple(Type1&& t1, Type2&& t2) ->
182 decltype(std::make_tuple(std::forward<Type1>(t1),
183 std::forward<Type2>(t2))) {
184 return std::make_tuple(std::forward<Type1>(t1),
185 std::forward<Type2>(t2));
188 // Merges a 2-tuple into a single tuple (get<0> could already be a tuple)
191 template<class Tuple>
192 auto operator()(Tuple&& value) const ->
193 decltype(add_to_tuple(std::get<0>(std::forward<Tuple>(value)),
194 std::get<1>(std::forward<Tuple>(value)))) {
195 static_assert(std::tuple_size<
196 typename std::remove_reference<Tuple>::type
198 "Can only merge tuples of size 2");
199 return add_to_tuple(std::get<0>(std::forward<Tuple>(value)),
200 std::get<1>(std::forward<Tuple>(value)));
204 } // namespace detail
206 static const detail::Map<detail::MergeTuples> tuple_flatten;
208 // TODO(mcurtiss): support zip() for N>1 operands. Because of variadic problems,
209 // this might not be easily possible until gcc4.8 is available.
210 template<class Source,
211 class Zip = detail::Zip<typename std::decay<Source>::type>>
212 Zip zip(Source&& source) {
213 return Zip(std::forward<Source>(source));