Current File : /home/inlingua/miniconda3/pkgs/libmamba-2.0.5-haf1ee3a_1/include/mamba/solver/solution.hpp
// Copyright (c) 2023, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.

#ifndef MAMBA_CORE_SOLUTION_HPP
#define MAMBA_CORE_SOLUTION_HPP

#include <type_traits>
#include <variant>
#include <vector>

#include "mamba/specs/package_info.hpp"
#include "mamba/util/loop_control.hpp"
#include "mamba/util/type_traits.hpp"

namespace mamba::solver
{
    struct Solution
    {
        struct Omit
        {
            specs::PackageInfo what;
        };

        struct Upgrade
        {
            specs::PackageInfo remove;
            specs::PackageInfo install;
        };

        struct Downgrade
        {
            specs::PackageInfo remove;
            specs::PackageInfo install;
        };

        struct Change
        {
            specs::PackageInfo remove;
            specs::PackageInfo install;
        };

        struct Reinstall
        {
            specs::PackageInfo what;
        };

        struct Remove
        {
            specs::PackageInfo remove;
        };

        struct Install
        {
            specs::PackageInfo install;
        };

        template <typename T>
        inline static constexpr bool has_remove_v = util::is_any_of_v<T, Upgrade, Downgrade, Change, Remove>;

        template <typename T>
        inline static constexpr bool has_install_v = util::is_any_of_v<T, Upgrade, Downgrade, Change, Install>;

        using Action = std::variant<Omit, Upgrade, Downgrade, Change, Reinstall, Remove, Install>;
        using action_list = std::vector<Action>;

        action_list actions = {};
    };

    template <typename Iter, typename UnaryFunc>
    void for_each_to_remove(Iter first, Iter last, UnaryFunc&& func);
    template <typename Range, typename UnaryFunc>
    void for_each_to_remove(Range&& actions, UnaryFunc&& func);

    template <typename Iter, typename UnaryFunc>
    void for_each_to_install(Iter first, Iter last, UnaryFunc&& func);
    template <typename Range, typename UnaryFunc>
    void for_each_to_install(Range&& actions, UnaryFunc&& func);

    template <typename Iter, typename UnaryFunc>
    void for_each_to_omit(Iter first, Iter last, UnaryFunc&& func);
    template <typename Range, typename UnaryFunc>
    void for_each_to_omit(Range&& actions, UnaryFunc&& func);

    /********************************
     *  Implementation of Solution  *
     ********************************/

    namespace detail
    {
        template <typename Action>
        auto to_remove_ptr(Action& action)
        {
            using PackageInfoPtr = std::
                conditional_t<std::is_const_v<Action>, const specs::PackageInfo*, specs::PackageInfo*>;
            return std::visit(
                [](auto& a) -> PackageInfoPtr
                {
                    using A = std::decay_t<decltype(a)>;
                    if constexpr (Solution::has_remove_v<A>)
                    {
                        return &(a.remove);
                    }
                    else if constexpr (std::is_same_v<A, Solution::Reinstall>)
                    {
                        return &(a.what);
                    }
                    return nullptr;
                },
                action
            );
        }
    }

    // TODO(C++20): Poor man's replacement to range filter transform
    template <typename Iter, typename UnaryFunc>
    void for_each_to_remove(Iter first, Iter last, UnaryFunc&& func)
    {
        for (; first != last; ++first)
        {
            if (auto* const ptr = detail::to_remove_ptr(*first))
            {
                if constexpr (std::is_same_v<decltype(func(*ptr)), util::LoopControl>)
                {
                    if (func(*ptr) == util::LoopControl::Break)
                    {
                        break;
                    }
                }
                else
                {
                    func(*ptr);
                }
            }
        }
    }

    template <typename Range, typename UnaryFunc>
    void for_each_to_remove(Range&& actions, UnaryFunc&& func)
    {
        return for_each_to_remove(actions.begin(), actions.end(), std::forward<UnaryFunc>(func));
    }

    namespace detail
    {
        template <typename Action>
        auto to_install_ptr(Action& action)
        {
            using PackageInfoPtr = std::
                conditional_t<std::is_const_v<Action>, const specs::PackageInfo*, specs::PackageInfo*>;
            return std::visit(
                [](auto& a) -> PackageInfoPtr
                {
                    using A = std::decay_t<decltype(a)>;
                    if constexpr (Solution::has_install_v<A>)
                    {
                        return &(a.install);
                    }
                    else if constexpr (std::is_same_v<A, Solution::Reinstall>)
                    {
                        return &(a.what);
                    }
                    return nullptr;
                },
                action
            );
        }
    }

    template <typename Iter, typename UnaryFunc>
    void for_each_to_install(Iter first, Iter last, UnaryFunc&& func)
    {
        for (; first != last; ++first)
        {
            if (auto* const ptr = detail::to_install_ptr(*first))
            {
                if constexpr (std::is_same_v<decltype(func(*ptr)), util::LoopControl>)
                {
                    if (func(*ptr) == util::LoopControl::Break)
                    {
                        break;
                    }
                }
                else
                {
                    func(*ptr);
                }
            }
        }
    }

    // TODO(C++20): Poor man's replacement to range filter transform
    template <typename Range, typename UnaryFunc>
    void for_each_to_install(Range&& actions, UnaryFunc&& func)
    {
        return for_each_to_install(actions.begin(), actions.end(), std::forward<UnaryFunc>(func));
    }

    namespace detail
    {
        template <typename Action>
        auto to_omit_ptr(Action& action)
        {
            using PackageInfoPtr = std::
                conditional_t<std::is_const_v<Action>, const specs::PackageInfo*, specs::PackageInfo*>;
            return std::visit(
                [](auto& a) -> PackageInfoPtr
                {
                    using A = std::decay_t<decltype(a)>;
                    if constexpr (std::is_same_v<A, Solution::Omit>)
                    {
                        return &(a.what);
                    }
                    return nullptr;
                },
                action
            );
        }
    }

    // TODO(C++20): Poor man's replacement to range filter transform
    template <typename Iter, typename UnaryFunc>
    void for_each_to_omit(Iter first, Iter last, UnaryFunc&& func)
    {
        for (; first != last; ++first)
        {
            if (auto* const ptr = detail::to_omit_ptr(*first))
            {
                if constexpr (std::is_same_v<decltype(func(*ptr)), util::LoopControl>)
                {
                    if (func(*ptr) == util::LoopControl::Break)
                    {
                        break;
                    }
                }
                else
                {
                    func(*ptr);
                }
            }
        }
    }

    template <typename Range, typename UnaryFunc>
    void for_each_to_omit(Range&& actions, UnaryFunc&& func)
    {
        return for_each_to_omit(actions.begin(), actions.end(), std::forward<UnaryFunc>(func));
    }
}
#endif