// bslmf_makeintegersequence.h                                        -*-C++-*-
#ifndef INCLUDED_BSLMF_MAKEINTEGERSEQUENCE
#define INCLUDED_BSLMF_MAKEINTEGERSEQUENCE

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a template parameter pack of integers.
//
//@CLASSES:
//  bslmf::MakeIntegerSequence: compile-time integer sequence factory function
//
//@DESCRIPTION: This component defines a factory function
// 'bslmf::MakeIntegerSequence' that generate a compile-time sequence of
// increasing integer values starting with 0.
//
// 'bslmf::MakeIntegerSequence' meets the requirements of the
// 'make_integer_sequence' template introduced in the C++14 standard
// [intseq.intseq] and can be used in a client's code if the compiler supports
// the C++11 standard.
//
// Note, that this component has no (emulated) support for pre-standard C++11
// compilers, as its only purpose is to be used in deduction with template
// parameter packs.  There is no language support to emulate in earlier
// compilers.
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Pass C-array as a parameter to a function with variadic template
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want to initialize a C-Array of known size 't_N' with data read
// from a data source using a library class that provides a variadic template
// interface that loads a data of variable length into the supplied parameter
// pack.
//
// First, define a class template 'DataReader',
//..
// template <std::size_t t_N>
// class DataReader {
//   public:
//..
// Then, implement a method that loads the specified parameter pack 'args' with
// data read from a data source.
//..
//     template <class ...t_T>
//     void read(t_T*... args) const
//     {
//         static_assert(sizeof...(args) == t_N, "");
//         read_impl(args...);
//     }
//..
// Next, for the test purpose provide simple implementation of the recursive
// variadic 'read_impl' function that streams the index of the C-Array's
// element to 'stdout'.
//..
// private:
//     template <class U, class ...t_T>
//     void read_impl(U*, t_T*... args) const
//     {
//         printf("read element #%i\n",
//                static_cast<int>(t_N - 1 - sizeof...(args)));
//         read_impl(args...);
//     }
//..
// Then, implement the recursion break condition.
//..
//     void read_impl() const
//     {
//     }
// };
//..
// Next, define a helper function template 'readData' that expands the
// parameter pack of indices 'I' and invokes the variadic template 'read'
// method of the specified 'reader' object.
//..
// namespace {
// template<class R, class t_T, std::size_t... I>
// void readData(const R&  reader,
//               t_T      *data,
//               bslmf::IntegerSequence<std::size_t, I...>)
// {
//     reader.read(&data[I]...);
//         // In pseudocode, this is equivalent to:
//         // reader.read(&data[0],
//         //             &data[1],
//         //             &data[2],
//         //             ...
//         //             &data[t_N-1]);
// }
// }
//..
// Now, define function template 'readData' that invokes the helper function
// Note, that the 'bslmf::MakeIntegerSequence<std::size_t, t_N>' function
// generates an object of an integer sequence class instantiated with a
// template parameter pack of integers that will be expanded and used as an
// array's indices in the helper function when calling the
// 'Reader::read(t_T*...)' variadic template function.
//..
// template<class t_T, std::size_t t_N>
// void readData(const DataReader<t_N>& reader, t_T *data)
// {
//     readData(reader, data, bslmf::MakeIntegerSequence<std::size_t, t_N>());
// }
//..
// Finally, define a 'data' C-Array and 'reader' variables and pass them to the
// 'readData' function as parameters.
//..
// constexpr int      k_SIZE = 5;
// DataReader<k_SIZE> reader;
// int                data[k_SIZE] = {0};
//
// readData(reader, data);
//..
// The streaming operator produces output in the following format on 'stdout':
//..
// read element #0
// read element #1
// read element #2
// read element #3
// read element #4
//..

#include <bslscm_version.h>

#include <bslmf_integersequence.h>
#include <bslmf_integralconstant.h>

#include <bsls_libraryfeatures.h>

#include <cstddef>  // 'std::size_t'

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP14_INTEGER_SEQUENCE

namespace BloombergLP {
namespace bslmf {
                     // =============================================
                     // private struct MakeIntegerSequence_ConcatUtil
                     // =============================================

template <class t_S1, class t_S2>
struct MakeIntegerSequence_ConcatUtil;
    // This component-private class template provides a specialization that
    // concatenates two integer sequences.  This template is not defined unless
    // the (template parameter) types 't_S1' and 't_S2' are specializations of
    // the class template 'bslmf::IntegerSequence'.

template <class t_T, t_T... t_I1, t_T... t_I2>
struct MakeIntegerSequence_ConcatUtil<bslmf::IntegerSequence<t_T, t_I1...>,
                                      bslmf::IntegerSequence<t_T, t_I2...> >
    // This partial specialization of 'bslmf::MakeIntegerSequence_ConcatUtil'
    // appends all indices from the specified 't_I2' sequence at the end of the
    // indices of the specified 't_I1' sequence.
{
    using type =
             bslmf::IntegerSequence<t_T, t_I1..., (sizeof...(t_I1) + t_I2)...>;
        // 'type' is an alias to an integer sequence type that represents the
        // result of concatenation of two integer sequences 't_I1' and 't_I2'.
        //
        // Consider 't_I1 = {0, 1, 2}' and 't_I2 = {0, 1, 2}', then the result
        // of concatenation is 'type = {0, 1, 2, 3 + 0, 3 + 1, 3 + 2}'. That is
        // 'type = {0, 1, 2, 3, 4, 5}'.
};

template <class t_S1, class t_S2>
using MakeIntegerSequence_ConcatUtil_t =
                     typename MakeIntegerSequence_ConcatUtil<t_S1, t_S2>::type;
    // 'bslmf::MakeIntegerSequence_ConcatUtil_t' is an alias to the result type
    // of the 'bslmf::MakeIntegerSequence_ConcatUtil' meta-function.

                  // =======================================
                  // private struct MakeIntegerSequence_Impl
                  // =======================================

template <class t_T, class t_N>
struct MakeIntegerSequence_Impl
    // This is recursive meta-function that generates a sequence of increasing
    // integer values in a range of [0..t_N::value) having the specified length
    // 't_N::value'.
{
    using FirstPart = bsl::integral_constant<std::size_t, t_N::value / 2>;
    using SecondPart =
              bsl::integral_constant<std::size_t, t_N::value - t_N::value / 2>;

    using type = MakeIntegerSequence_ConcatUtil_t<
        typename MakeIntegerSequence_Impl<t_T, FirstPart>::type,
        typename MakeIntegerSequence_Impl<t_T, SecondPart>::type>;
        // 'type' is an alias to the result of the
        // 'bslmf::MakeIntegerSequence_ConcatUtil_t' meta-function instantiated
        // with two integer sequences of two lengths 't_N/2' and 't_N - t_N/2',
        // that implies logarithmic depth of the
        // 'bslmf::MakeIntegerSequence_Impl' meta-function instantiation.
};

template <class t_T>
struct MakeIntegerSequence_Impl<t_T, bsl::integral_constant<std::size_t, 0> >
    // This partial specialization of the 'bslmf::MakeIntegerSequence_Impl'
    // meta-function is a recursion break condition for an empty integer
    // sequence.
{
    using type = bslmf::IntegerSequence<t_T>;
};

template <class t_T>
struct MakeIntegerSequence_Impl<t_T, bsl::integral_constant<std::size_t, 1> >
    // This partial specialization of the 'bslmf::MakeIntegerSequence_Impl'
    // meta-function is a recursion break condition for an integer sequence
    // having the length 1.
{
    using type = bslmf::IntegerSequence<t_T, 0>;
};

template <class t_T>
struct MakeIntegerSequence_Impl<t_T, bsl::integral_constant<std::size_t, 2> >
    // This partial specialization of the 'bslmf::MakeIntegerSequence_Impl'
    // meta-function is a recursion break condition for an integer sequence
    // having the length 2.
{
    using type = bslmf::IntegerSequence<t_T, 0, 1>;
};

template <class t_T>
struct MakeIntegerSequence_Impl<t_T, bsl::integral_constant<std::size_t, 3> >
    // This partial specialization of the 'bslmf::MakeIntegerSequence_Impl'
    // meta-function is a recursion break condition for an integer sequence
    // having the length 3.
{
    using type = bslmf::IntegerSequence<t_T, 0, 1, 2>;
};

template <class t_T>
struct MakeIntegerSequence_Impl<t_T, bsl::integral_constant<std::size_t, 4> >
    // This partial specialization of the 'bslmf::MakeIntegerSequence_Impl'
    // meta-function is a recursion break condition for an integer sequence
    // having the length 4.
{
    using type = bslmf::IntegerSequence<t_T, 0, 1, 2, 3>;
};

template <class t_T>
struct MakeIntegerSequence_Impl<t_T, bsl::integral_constant<std::size_t, 5> >
    // This partial specialization of the 'bslmf::MakeIntegerSequence_Impl'
    // meta-function is a recursion break condition for an integer sequence
    // having the length 5.
{
    using type = bslmf::IntegerSequence<t_T, 0, 1, 2, 3, 4>;
};

template <class t_T>
struct MakeIntegerSequence_Impl<t_T, bsl::integral_constant<std::size_t, 6> >
    // This partial specialization of the 'bslmf::MakeIntegerSequence_Impl'
    // meta-function is a recursion break condition for an integer sequence
    // having the length 6.
{
    using type = bslmf::IntegerSequence<t_T, 0, 1, 2, 3, 4, 5>;
};

template <class t_T>
struct MakeIntegerSequence_Impl<t_T, bsl::integral_constant<std::size_t, 7> >
    // This partial specialization of the 'bslmf::MakeIntegerSequence_Impl'
    // meta-function is a recursion break condition for an integer sequence
    // having the length 7.
{
    using type = bslmf::IntegerSequence<t_T, 0, 1, 2, 3, 4, 5, 6>;
};

template <class t_T>
struct MakeIntegerSequence_Impl<t_T, bsl::integral_constant<std::size_t, 8> >
    // This partial specialization of the 'bslmf::MakeIntegerSequence_Impl'
    // meta-function is a recursion break condition for an integer sequence
    // having the length 8.
{
    using type = bslmf::IntegerSequence<t_T, 0, 1, 2, 3, 4, 5, 6, 7>;
};

// ALIASES
template <class t_T, class t_N>
using MakeIntegerSequence_Impl_t =
                             typename MakeIntegerSequence_Impl<t_T, t_N>::type;
    // 'bslmf::MakeIntegerSequence_Impl_t' is an alias to the result type of
    // the 'bslmf::MakeIntegerSequence_Impl' meta-function.

template <class t_T, t_T t_N>
using MakeIntegerSequence = BloombergLP::bslmf::
    MakeIntegerSequence_Impl_t<t_T, bsl::integral_constant<std::size_t, t_N> >;
    // 'MakeIntegerSequence' is defined to simplify creation of
    // 'bslmf::IntegerSequence' type that represents a collection of increasing
    // integer values of the specified type 't_T' in a range of [0..t_N) having
    // the specified t_N-value length.

}  // close package namespace
}  // close enterprise namespace

#endif  // BSLS_LIBRARYFEATURES_HAS_CPP14_INTEGER_SEQUENCE
#endif  // INCLUDED_BSLMF_INTEGERSEQUENCE

// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// 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.
// ----------------------------- END-OF-FILE ----------------------------------