/*
 * 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<data>::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
 * only evaluated 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 a 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 <type_traits>

/*
 * Shorthand for:
 *   for (auto i = c.begin(); i != c.end(); ++i)
 * except that c is only evaluated once.
 */
#define FOR_EACH(i, c)                              \
  if (bool FOR_EACH_state1 = false) {} else         \
    for (auto && FOR_EACH_state2 = (c);             \
         !FOR_EACH_state1; FOR_EACH_state1 = true)  \
      for (auto i = FOR_EACH_state2.begin();        \
           i != FOR_EACH_state2.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<string, string> 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 <typename T, typename U>
class HasLess {
  struct BiggerThanChar { char unused[2]; };
  template <typename C, typename D> static char test(decltype(C() < D())*);
  template <typename, typename> static BiggerThanChar test(...);
public:
  enum { value = sizeof(test<T, U>(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 <class T, class U>
typename std::enable_if<HasLess<T, U>::value, bool>::type
notThereYet(T& iter, const U& end) {
  return iter < end;
}

template <class T, class U>
typename std::enable_if<!HasLess<T, U>::value, bool>::type
notThereYet(T& iter, const U& end) {
  return iter != end;
}

#else

template <class T, class U>
typename std::enable_if<
  (std::is_arithmetic<T>::value && std::is_arithmetic<U>::value) ||
  (std::is_pointer<T>::value && std::is_pointer<U>::value),
  bool>::type
notThereYet(T& iter, const U& end) {
  return iter < end;
}

template <class T, class U>
typename std::enable_if<
  !(
    (std::is_arithmetic<T>::value && std::is_arithmetic<U>::value) ||
    (std::is_pointer<T>::value && std::is_pointer<U>::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 <class T, class U>
typename std::enable_if<HasLess<U, T>::value, bool>::type
downTo(T& iter, const U& begin) {
  return begin < iter--;
}

template <class T, class U>
typename std::enable_if<!HasLess<U, T>::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));)
