blob: bdeab9314455fe3b9783c88f0c0ca888022f805d [file] [log] [blame]
// Ceres Solver - A fast non-linear least squares minimizer
// Copyright 2018 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of Google Inc. nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: jodebo_beck@gmx.de (Johannes Beck)
//
// Algorithms to be used together with integer_sequence, like computing the sum
// or the exclusive scan (sometimes called exclusive prefix sum) at compile
// time.
#ifndef CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_
#define CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_
#include "integer_sequence.h"
namespace ceres {
namespace internal {
// Implementation of calculating the sum of an integer sequence.
// Recursively instantiate SumImpl and calculate the sum of the N first
// numbers. This reduces the number of instantiations and speeds up
// compilation.
//
// Examples:
// 1) integer_sequence<int, 5>:
// Value = 5
//
// 2) integer_sequence<int, 4, 2>:
// Value = 4 + 2 + SumImpl<integer_sequence<int>>::Value
// Value = 4 + 2 + 0
//
// 3) integer_sequence<int, 2, 1, 4>:
// Value = 2 + 1 + SumImpl<integer_sequence<int, 4>>::Value
// Value = 2 + 1 + 4
template <typename Seq>
struct SumImpl;
// Strip of and sum the first number.
template <typename T, T N, T... Ns>
struct SumImpl<integer_sequence<T, N, Ns...>> {
static constexpr T Value = N + SumImpl<integer_sequence<T, Ns...>>::Value;
};
// Strip of and sum the first two numbers.
template <typename T, T N1, T N2, T... Ns>
struct SumImpl<integer_sequence<T, N1, N2, Ns...>> {
static constexpr T Value =
N1 + N2 + SumImpl<integer_sequence<T, Ns...>>::Value;
};
// Strip of and sum the first four numbers.
template <typename T, T N1, T N2, T N3, T N4, T... Ns>
struct SumImpl<integer_sequence<T, N1, N2, N3, N4, Ns...>> {
static constexpr T Value =
N1 + N2 + N3 + N4 + SumImpl<integer_sequence<T, Ns...>>::Value;
};
// Only one number is left. 'Value' is just that number ('recursion' ends).
template <typename T, T N>
struct SumImpl<integer_sequence<T, N>> {
static constexpr T Value = N;
};
// No number is left. 'Value' is the identity element (for sum this is zero).
template <typename T>
struct SumImpl<integer_sequence<T>> {
static constexpr T Value = T(0);
};
// Calculate the sum of an integer sequence. The resulting sum will be stored in
// 'Value'.
template <typename Seq>
class Sum {
using T = typename Seq::value_type;
public:
static constexpr T Value = SumImpl<Seq>::Value;
};
// Implementation of calculating an exclusive scan (exclusive prefix sum) of an
// integer sequence. Exclusive means that the i-th input element is not included
// in the i-th sum. Calculating the exclusive scan for an input array I results
// in the following output R:
//
// R[0] = 0
// R[1] = I[0];
// R[2] = I[0] + I[1];
// R[3] = I[0] + I[1] + I[2];
// ...
//
// In C++17 std::exclusive_scan does the same operation at runtime (but
// cannot be used to calculate the prefix sum at compile time). See
// https://en.cppreference.com/w/cpp/algorithm/exclusive_scan for a more
// detailed description.
//
// Example for integer_sequence<int, 1, 4, 3> (seq := integer_sequence):
// T , Sum, Ns... , Rs...
// ExclusiveScanImpl<int, 0, seq<int, 1, 4, 3>, seq<int >>
// ExclusiveScanImpl<int, 1, seq<int, 4, 3>, seq<int, 0 >>
// ExclusiveScanImpl<int, 5, seq<int, 3>, seq<int, 0, 1 >>
// ExclusiveScanImpl<int, 8, seq<int >, seq<int, 0, 1, 5>>
// ^^^^^^^^^^^^^^^^^
// resulting sequence
template <typename T, T Sum, typename SeqIn, typename SeqOut>
struct ExclusiveScanImpl;
template <typename T, T Sum, T N, T... Ns, T... Rs>
struct ExclusiveScanImpl<T, Sum, integer_sequence<T, N, Ns...>,
integer_sequence<T, Rs...>> {
using Type =
typename ExclusiveScanImpl<T, Sum + N, integer_sequence<T, Ns...>,
integer_sequence<T, Rs..., Sum>>::Type;
};
// End of 'recursion'. The resulting type is SeqOut.
template <typename T, T Sum, typename SeqOut>
struct ExclusiveScanImpl<T, Sum, integer_sequence<T>, SeqOut> {
using Type = SeqOut;
};
// Calculates the exclusive scan of the specified integer sequence. The last
// element (the total) is not included in the resulting sequence so they have
// same length. This means the exclusive scan of integer_sequence<int, 1, 2, 3>
// will be integer_sequence<int, 0, 1, 3>.
template <typename Seq>
class ExclusiveScanT {
using T = typename Seq::value_type;
public:
using Type =
typename ExclusiveScanImpl<T, T(0), Seq, integer_sequence<T>>::Type;
};
// Helper to use exclusive scan without typename.
template <typename Seq>
using ExclusiveScan = typename ExclusiveScanT<Seq>::Type;
} // namespace internal
} // namespace ceres
#endif // CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_