/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2012-2017 Danny Robson <danny@nerdcruft.net>
 */

#ifndef UTIL_TYPES_COMPARATOR_HPP
#define UTIL_TYPES_COMPARATOR_HPP

#include <memory>

#include "../iterator/zip.hpp"

namespace cruft::comparator {
    ///////////////////////////////////////////////////////////////////////////
    /// Compares standard types that can be reduced to pointers.
    template <typename T>
    struct pointer {
        constexpr
        bool
        operator() (const std::unique_ptr<T> &a, const std::unique_ptr<T> &b)
        {
            return a < b;
        }

        constexpr
        bool
        operator() (const T *a, const std::unique_ptr<T> &b)
        {
            return a < b.get ();
        }

        constexpr
        bool
        operator() (const std::unique_ptr<T> &a, const T *b)
        {
            return a.get () < b;
        }
    };


    ///////////////////////////////////////////////////////////////////////////
    /// Provides a comparison interface for types exposing an index operator.
    ///
    /// Will return true if the first parameter has the first index that
    /// compares less than the second parameter. Useful for providing a total
    /// order of coordinate types where this doesn't make sense by default.
    ///
    /// \tparam T The container data type to compare. Must provide an index
    /// operator.
    template <typename T>
    struct indexed {
        constexpr
        bool operator() (const T &a, const T &b) const
        {
            for (auto x: cruft::iterator::zip (a, b)) {
                const auto &[i,j] = x; // BUG: clang-4.0: workaround for segfault.
                if (i  < j) return true;
                if (i != j) return false;
            }

            return false;
        }
    };
}

#endif