/* * Copyright 2016 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. */ #pragma once /* * Iterim macros (until we have C++0x range-based for) that simplify * writing loops of the form * * for (Container::iterator i = c.begin(); i != c.end(); ++i) statement * * Just replace the above with: * * FOR_EACH (i, c) statement * * and everything is taken care of. * * The implementation is a bit convoluted to make sure the container is * evaluated only once (however, keep in mind that c.end() is evaluated * at every pass through the loop). To ensure the container is not * evaluated multiple times, the macro defines one do-nothing if * statement to inject the Boolean variable FOR_EACH_state1, and then a * for statement that is executed only once, which defines the variable * FOR_EACH_state2 holding an rvalue reference to the container being * iterated. The workhorse is the last loop, which uses the just-defined * rvalue reference FOR_EACH_state2. * * The state variables are nested so they don't interfere; you can use * FOR_EACH multiple times in the same scope, either at the same level or * nested. * * In optimized builds g++ eliminates the extra gymnastics entirely and * generates code 100% identical to the handwritten loop. */ #include #include /* * Form a local variable name from "FOR_EACH_" x __LINE__, so that * FOR_EACH can be nested without creating shadowed declarations. */ #define _FE_ANON(x) FB_CONCATENATE(FOR_EACH_, FB_CONCATENATE(x, __LINE__)) /* * Shorthand for: * for (auto i = c.begin(); i != c.end(); ++i) * except that c is evaluated only once. */ #define FOR_EACH(i, c) \ if (bool _FE_ANON(s1_) = false) {} else \ for (auto && _FE_ANON(s2_) = (c); \ !_FE_ANON(s1_); _FE_ANON(s1_) = true) \ for (auto i = _FE_ANON(s2_).begin(); \ i != _FE_ANON(s2_).end(); ++i) /* * Similar to FOR_EACH, but iterates the container backwards by * using rbegin() and rend(). */ #define FOR_EACH_R(i, c) \ if (bool FOR_EACH_R_state1 = false) {} else \ for (auto && FOR_EACH_R_state2 = (c); \ !FOR_EACH_R_state1; FOR_EACH_R_state1 = true) \ for (auto i = FOR_EACH_R_state2.rbegin(); \ i != FOR_EACH_R_state2.rend(); ++i) /* * Similar to FOR_EACH but also allows client to specify a 'count' variable * to track the current iteration in the loop (starting at zero). * Similar to python's enumerate() function. For example: * string commaSeparatedValues = "VALUES: "; * FOR_EACH_ENUMERATE(ii, value, columns) { // don't want comma at the end! * commaSeparatedValues += (ii == 0) ? *value : string(",") + *value; * } */ #define FOR_EACH_ENUMERATE(count, i, c) \ if (bool FOR_EACH_state1 = false) {} else \ for (auto && FOR_EACH_state2 = (c); \ !FOR_EACH_state1; FOR_EACH_state1 = true) \ if (size_t FOR_EACH_privateCount = 0) {} else \ if (const size_t& count = FOR_EACH_privateCount) {} else \ for (auto i = FOR_EACH_state2.begin(); \ i != FOR_EACH_state2.end(); ++FOR_EACH_privateCount, ++i) /** * Similar to FOR_EACH, but gives the user the key and value for each entry in * the container, instead of just the iterator to the entry. For example: * map testMap; * FOR_EACH_KV(key, value, testMap) { * cout << key << " " << value; * } */ #define FOR_EACH_KV(k, v, c) \ if (unsigned int FOR_EACH_state1 = 0) {} else \ for (auto && FOR_EACH_state2 = (c); \ !FOR_EACH_state1; FOR_EACH_state1 = 1) \ for (auto FOR_EACH_state3 = FOR_EACH_state2.begin(); \ FOR_EACH_state3 != FOR_EACH_state2.end(); \ FOR_EACH_state1 == 2 \ ? ((FOR_EACH_state1 = 0), ++FOR_EACH_state3) \ : (FOR_EACH_state3 = FOR_EACH_state2.end())) \ for (auto &k = FOR_EACH_state3->first; \ !FOR_EACH_state1; ++FOR_EACH_state1) \ for (auto &v = FOR_EACH_state3->second; \ !FOR_EACH_state1; ++FOR_EACH_state1) namespace folly { namespace detail { // Boost 1.48 lacks has_less, we emulate a subset of it here. template class HasLess { struct BiggerThanChar { char unused[2]; }; template static char test(decltype(C() < D())*); template static BiggerThanChar test(...); public: enum { value = sizeof(test(0)) == 1 }; }; /** * notThereYet helps the FOR_EACH_RANGE macro by opportunistically * using "<" instead of "!=" whenever available when checking for loop * termination. This makes e.g. examples such as FOR_EACH_RANGE (i, * 10, 5) execute zero iterations instead of looping virtually * forever. At the same time, some iterator types define "!=" but not * "<". The notThereYet function will dispatch differently for those. * * Below is the correct implementation of notThereYet. It is disabled * because of a bug in Boost 1.46: The filesystem::path::iterator * defines operator< (via boost::iterator_facade), but that in turn * uses distance_to which is undefined for that particular * iterator. So HasLess (defined above) identifies * boost::filesystem::path as properly comparable with <, but in fact * attempting to do so will yield a compile-time error. * * The else branch (active) contains a conservative * implementation. */ #if 0 template typename std::enable_if::value, bool>::type notThereYet(T& iter, const U& end) { return iter < end; } template typename std::enable_if::value, bool>::type notThereYet(T& iter, const U& end) { return iter != end; } #else template typename std::enable_if< (std::is_arithmetic::value && std::is_arithmetic::value) || (std::is_pointer::value && std::is_pointer::value), bool>::type notThereYet(T& iter, const U& end) { return iter < end; } template typename std::enable_if< !( (std::is_arithmetic::value && std::is_arithmetic::value) || (std::is_pointer::value && std::is_pointer::value) ), bool>::type notThereYet(T& iter, const U& end) { return iter != end; } #endif /** * downTo is similar to notThereYet, but in reverse - it helps the * FOR_EACH_RANGE_R macro. */ template typename std::enable_if::value, bool>::type downTo(T& iter, const U& begin) { return begin < iter--; } template typename std::enable_if::value, bool>::type downTo(T& iter, const U& begin) { if (iter == begin) return false; --iter; return true; } } } /* * Iteration with given limits. end is assumed to be reachable from * begin. end is evaluated every pass through the loop. * * NOTE: The type of the loop variable should be the common type of "begin" * and "end". e.g. If "begin" is "int" but "end" is "long", we want "i" * to be "long". This is done by getting the type of (true ? begin : end) */ #define FOR_EACH_RANGE(i, begin, end) \ for (auto i = (true ? (begin) : (end)); \ ::folly::detail::notThereYet(i, (end)); \ ++i) /* * Iteration with given limits. begin is assumed to be reachable from * end by successive decrements. begin is evaluated every pass through * the loop. * * NOTE: The type of the loop variable should be the common type of "begin" * and "end". e.g. If "begin" is "int" but "end" is "long", we want "i" * to be "long". This is done by getting the type of (false ? begin : end) */ #define FOR_EACH_RANGE_R(i, begin, end) \ for (auto i = (false ? (begin) : (end)); ::folly::detail::downTo(i, (begin));)