<commit_before>#ifndef KGR_KANGARU_INCLUDE_KANGARU_CONTAINER_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_CONTAINER_HPP

#include "detail/traits.hpp"
#include "detail/service_traits.hpp"
#include "detail/utils.hpp"
#include "detail/container_service.hpp"
#include "detail/invoke.hpp"
#include "detail/single.hpp"
#include "detail/injected.hpp"
#include "detail/error.hpp"
#include "predicate.hpp"

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>
#include <algorithm>
#include <vector>

namespace kgr {

struct Container final {
private:
	template<typename Condition, typename T = int> using enable_if = detail::enable_if_t<Condition::value, T>;
	template<typename Condition, typename T = int> using disable_if = detail::enable_if_t<!Condition::value, T>;
	template<typename T> using instance_ptr = std::unique_ptr<T, void(*)(void*)>;
	using instance_cont = std::vector<instance_ptr<void>>;
	using service_cont = std::unordered_map<type_id_t, void*>;
	template<typename T> using contained_service_t = typename std::conditional<
		detail::is_single<T>::value,
		instance_ptr<detail::SingleInjected<T>>,
		detail::Injected<T>>::type;
	
	template<typename T>
	static void deleter(void* i) {
		delete static_cast<T*>(i);
	}
	
	template<typename T, typename... Args>
	static instance_ptr<detail::SingleInjected<T>> make_instance_ptr(Args&&... args) {
		return instance_ptr<detail::SingleInjected<T>>{
			new detail::SingleInjected<T>{std::forward<Args>(args)...},
			&Container::deleter<detail::BaseInjected<T>>
		};
	}
	
	template<typename T, typename C, typename... Args>
	static instance_ptr<detail::BaseInjected<C>> make_override_ptr(Args&&... args) {
		return instance_ptr<detail::ServiceOverride<T, C>>{
			new detail::ServiceOverride<T, C>{std::forward<Args>(args)...},
			&Container::deleter<detail::BaseInjected<C>>
		};
	}
	
public:
	explicit Container() = default;
	Container(const Container &) = delete;
	Container& operator=(const Container &) = delete;
	Container(Container&&) = default;
	Container& operator=(Container&&) = default;
	~Container() = default;
	
	/*
	 * This function construct a service definition with the provided arguments.
	 * It also saves it in the container.
	 * It returns void.
	 * This function only works with single services.
	 * This version of the function will call functions in autocall.
	 */
	template<typename T, typename... Args,
		enable_if<detail::is_single<T>> = 0,
		enable_if<detail::is_service<T>> = 0,
		enable_if<detail::is_service_instantiable<T, Args...>> = 0>
	void instance(Args&&... args) {
		autocall(save_instance<T>(make_contained_service<T>(std::forward<Args>(args)...)).get());
	}
	
	/*
	 * This function construct a service definition with the provided arguments.
	 * It also saves it in the container.
	 * It returns void.
	 * This function only works with single services.
	 * This version of the function will not call functions in autocall.
	 */
	template<typename T, typename... Args,
		enable_if<detail::is_single<T>> = 0,
		enable_if<detail::is_service<T>> = 0,
		enable_if<detail::is_service_instantiable<T, Args...>> = 0>
	void instance(detail::no_autocall_t, Args&&... args) {
		save_instance<T>(make_contained_service<T>(std::forward<Args>(args)...));
	}
	
	/*
	 * This function returns the service given by serivce definition T.
	 * T must be a valid service and must be constructible with arguments passed as parameters
	 * In case of a non-single service, it takes additional arguments to be sent to the T::construct function.
	 * T must not be a polymorphic type.
	 */
	template<typename T, typename... Args, enable_if<detail::is_service_valid<T, Args...>> = 0>
	ServiceType<T> service(Args&&... args) {
		return definition<T>(std::forward<Args>(args)...).forward();
	}
	
	/*
	 * The following two overloads are called in a case where the service is invalid,
	 * or is called when provided arguments don't match the constructor.
	 * In GCC, a diagnostic is provided.
	 */
	template<typename T, enable_if<std::is_default_constructible<detail::ServiceError<T>>> = 0>
	detail::Sink service(detail::ServiceError<T> = {}) = delete;
	
	template<typename T, typename... Args>
	detail::Sink service(detail::ServiceError<T, detail::identity_t<Args>...>, Args&&...) = delete;
	
	/*
	 * This function returns the result of the callable object of type U.
	 * Args are additional arguments to be sent to the function after services arguments.
	 * This function will deduce arguments from the function signature.
	 */
	template<template<typename> class Map = AdlMap, typename U, typename... Args, enable_if<detail::is_invoke_valid<Map, detail::decay_t<U>, Args...>> = 0>
	detail::function_result_t<detail::decay_t<U>> invoke(U&& function, Args&&... args) {
		return invoke_helper<Map>(
			detail::tuple_seq_minus<detail::function_arguments_t<detail::decay_t<U>>, sizeof...(Args)>{},
			std::forward<U>(function),
			std::forward<Args>(args)...
		);
	}
	
	/*
	 * This function returns the result of the callable object of type U.
	 * This version of the function is called when `function` is not invokable to provide diagnostic.
	 */
	template<template<typename> class Map>
	detail::Sink invoke(detail::NotInvokableError = {}, ...) = delete;
	
	/*
	 * This function returns the result of the callable object of type U.
	 * It will call the function with the sevices listed in the `Services` parameter pack.
	 * It will call it in a equivalent expression of `std::declval<U>()(std::declval<ServiceType<Services>>()..., std::declval<Args>()...)`
	 */
	template<typename... Services, typename U, typename... Args, detail::int_t<enable_if<detail::is_service_valid<Services>>...> = 0>
	auto invoke(U&& function, Args&&... args) -> decltype(std::declval<U>()(std::declval<ServiceType<Services>>()..., std::declval<Args>()...)) {
		return std::forward<U>(function)(service<Services>()..., std::forward<Args>(args)...);
	}
	
	/*
	 * This oveload is called when one of the services to be injected is invalid.
	 * It will provide diagnostic on GCC.
	 */
	template<typename... Services>
	detail::Sink invoke(detail::NotInvokableError = {}, ...) = delete;
	
	/*
	 * This function clears this container.<commit_msg>Fix ambiguous call invoking empty function<commit_after>#ifndef KGR_KANGARU_INCLUDE_KANGARU_CONTAINER_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_CONTAINER_HPP

#include "detail/traits.hpp"
#include "detail/service_traits.hpp"
#include "detail/utils.hpp"
#include "detail/container_service.hpp"
#include "detail/invoke.hpp"
#include "detail/single.hpp"
#include "detail/injected.hpp"
#include "detail/error.hpp"
#include "predicate.hpp"

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>
#include <algorithm>
#include <vector>

namespace kgr {

struct Container final {
private:
	template<typename Condition, typename T = int> using enable_if = detail::enable_if_t<Condition::value, T>;
	template<typename Condition, typename T = int> using disable_if = detail::enable_if_t<!Condition::value, T>;
	template<typename T> using instance_ptr = std::unique_ptr<T, void(*)(void*)>;
	using instance_cont = std::vector<instance_ptr<void>>;
	using service_cont = std::unordered_map<type_id_t, void*>;
	template<typename T> using contained_service_t = typename std::conditional<
		detail::is_single<T>::value,
		instance_ptr<detail::SingleInjected<T>>,
		detail::Injected<T>>::type;
	
	template<typename T>
	static void deleter(void* i) {
		delete static_cast<T*>(i);
	}
	
	template<typename T, typename... Args>
	static instance_ptr<detail::SingleInjected<T>> make_instance_ptr(Args&&... args) {
		return instance_ptr<detail::SingleInjected<T>>{
			new detail::SingleInjected<T>{std::forward<Args>(args)...},
			&Container::deleter<detail::BaseInjected<T>>
		};
	}
	
	template<typename T, typename C, typename... Args>
	static instance_ptr<detail::BaseInjected<C>> make_override_ptr(Args&&... args) {
		return instance_ptr<detail::ServiceOverride<T, C>>{
			new detail::ServiceOverride<T, C>{std::forward<Args>(args)...},
			&Container::deleter<detail::BaseInjected<C>>
		};
	}
	
public:
	explicit Container() = default;
	Container(const Container &) = delete;
	Container& operator=(const Container &) = delete;
	Container(Container&&) = default;
	Container& operator=(Container&&) = default;
	~Container() = default;
	
	/*
	 * This function construct a service definition with the provided arguments.
	 * It also saves it in the container.
	 * It returns void.
	 * This function only works with single services.
	 * This version of the function will call functions in autocall.
	 */
	template<typename T, typename... Args,
		enable_if<detail::is_single<T>> = 0,
		enable_if<detail::is_service<T>> = 0,
		enable_if<detail::is_service_instantiable<T, Args...>> = 0>
	void instance(Args&&... args) {
		autocall(save_instance<T>(make_contained_service<T>(std::forward<Args>(args)...)).get());
	}
	
	/*
	 * This function construct a service definition with the provided arguments.
	 * It also saves it in the container.
	 * It returns void.
	 * This function only works with single services.
	 * This version of the function will not call functions in autocall.
	 */
	template<typename T, typename... Args,
		enable_if<detail::is_single<T>> = 0,
		enable_if<detail::is_service<T>> = 0,
		enable_if<detail::is_service_instantiable<T, Args...>> = 0>
	void instance(detail::no_autocall_t, Args&&... args) {
		save_instance<T>(make_contained_service<T>(std::forward<Args>(args)...));
	}
	
	/*
	 * This function returns the service given by serivce definition T.
	 * T must be a valid service and must be constructible with arguments passed as parameters
	 * In case of a non-single service, it takes additional arguments to be sent to the T::construct function.
	 * T must not be a polymorphic type.
	 */
	template<typename T, typename... Args, enable_if<detail::is_service_valid<T, Args...>> = 0>
	ServiceType<T> service(Args&&... args) {
		return definition<T>(std::forward<Args>(args)...).forward();
	}
	
	/*
	 * The following two overloads are called in a case where the service is invalid,
	 * or is called when provided arguments don't match the constructor.
	 * In GCC, a diagnostic is provided.
	 */
	template<typename T, enable_if<std::is_default_constructible<detail::ServiceError<T>>> = 0>
	detail::Sink service(detail::ServiceError<T> = {}) = delete;
	
	template<typename T, typename... Args>
	detail::Sink service(detail::ServiceError<T, detail::identity_t<Args>...>, Args&&...) = delete;
	
	/*
	 * This function returns the result of the callable object of type U.
	 * Args are additional arguments to be sent to the function after services arguments.
	 * This function will deduce arguments from the function signature.
	 */
	template<template<typename> class Map = AdlMap, typename U, typename... Args, enable_if<detail::is_invoke_valid<Map, detail::decay_t<U>, Args...>> = 0>
	detail::function_result_t<detail::decay_t<U>> invoke(U&& function, Args&&... args) {
		return invoke_helper<Map>(
			detail::tuple_seq_minus<detail::function_arguments_t<detail::decay_t<U>>, sizeof...(Args)>{},
			std::forward<U>(function),
			std::forward<Args>(args)...
		);
	}
	
	/*
	 * This function returns the result of the callable object of type U.
	 * This version of the function is called when `function` is not invokable to provide diagnostic.
	 */
	template<template<typename> class Map>
	detail::Sink invoke(detail::NotInvokableError = {}, ...) = delete;
	
	/*
	 * This function returns the result of the callable object of type U.
	 * It will call the function with the sevices listed in the `Services` parameter pack.
	 * It will call it in a equivalent expression of `std::declval<U>()(std::declval<ServiceType<Services>>()..., std::declval<Args>()...)`
	 */
	template<typename... Services, typename U, typename... Args, detail::int_t<enable_if<detail::is_service_valid<Services>>..., detail::enable_if_t<(sizeof...(Services) > 0)>> = 0>
	auto invoke(U&& function, Args&&... args) -> decltype(std::declval<U>()(std::declval<ServiceType<Services>>()..., std::declval<Args>()...)) {
		return std::forward<U>(function)(service<Services>()..., std::forward<Args>(args)...);
	}
	
	/*
	 * This oveload is called when one of the services to be injected is invalid.
	 * It will provide diagnostic on GCC.
	 */
	template<typename... Services>
	detail::Sink invoke(detail::NotInvokableError = {}, ...) = delete;
	
	/*
	 * This function clears this container.
{'fraction_non_alphanumeric': 0.14608904933814681, 'fraction_numerical': 0.0016847172081829122, 'mean_word_length': 5.033881897386253, 'pattern_counts': {'":': 0, '<': 216, '<?xml version=': 0, '>': 219, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '97421', 'n_tokens_mistral': 4067, 'n_tokens_neox': 3799, 'n_words': 1054}