<commit_before>// Copyright (c) 2013 <NAME>
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef ASYNCXX_H_
# error "Do not include this header directly, include <async++.h> instead."
#endif

namespace async {
namespace detail {

// Common code for task and shared_task
template<typename Result> class basic_task {
protected:
	// Reference counted internal task object
	detail::task_ptr internal_task;

	// Real result type, with void turned into fake_void
	typedef typename void_to_fake_void<Result>::type internal_result;

	// Type-specific task object
	typedef task_result<internal_result> internal_task_type;

	// Friend access
	template<typename T> friend class basic_task;
	template<typename T> friend typename T::internal_task_type* get_internal_task(const T& t);

	// Common code for get()
	void get_internal() const
	{
		// Catch use of uninitialized task objects
		if (!internal_task)
			throw std::invalid_argument("Use of empty task object");

		// If the task was canceled, throw the associated exception
		internal_task->wait_and_throw();
	}

	// Common code for then()
	template<typename Sched, typename Func, typename Parent> typename continuation_traits<Parent, Func>::task_type then_internal(Sched& sched, Func&& f, Parent&& parent) const
	{
		// Catch use of uninitialized task objects
		if (!internal_task)
			throw std::invalid_argument("Use of empty task object");

		// Save a copy of internal_task because it might get moved into exec_func
		task_base* my_internal = internal_task.get();

		// Create continuation
		typedef typename continuation_traits<Parent, Func>::task_type::internal_result cont_internal_result;
		typedef continuation_exec_func<typename std::decay<Parent>::type, cont_internal_result, typename std::decay<Func>::type, continuation_traits<Parent, Func>::is_value_cont::value, is_task<typename continuation_traits<Parent, Func>::result_type>::value> exec_func;
		typename continuation_traits<Parent, Func>::task_type cont;
		cont.internal_task = task_ptr(new task_func<exec_func, cont_internal_result>(exec_func(std::forward<Func>(f), std::forward<Parent>(parent))));

		// Set continuation parameters
		cont.internal_task->sched = std::addressof(sched);
		cont.internal_task->always_cont = !continuation_traits<Parent, Func>::is_value_cont::value;

		// Add the continuation to this task
		// Avoid an expensive ref-count modification since the task isn't shared yet
		cont.internal_task->add_ref_unlocked();
		my_internal->add_continuation(task_ptr(cont.internal_task.get()));

		return cont;
	}

public:
	// Task result type
	typedef Result result_type;

	explicit operator bool() const
	{
		return internal_task;
	}

	// Query whether the task has finished executing
	bool ready() const
	{
		if (internal_task->state.load(std::memory_order_relaxed) >= task_state::TASK_COMPLETED) {
			std::atomic_thread_fence(std::memory_order_acquire);
			return true;
		} else
			return false;
	}

	// Wait for the task to complete
	void wait() const
	{
		// Catch use of uninitialized task objects
		if (!internal_task)
			throw std::invalid_argument("Use of empty task object");

		internal_task->wait();
	}
};

// Common code for event_task specializations
template<typename Result> class basic_event {
protected:
	// Reference counted internal task object
	detail::task_ptr internal_task;

	// Real result type, with void turned into fake_void
	typedef typename detail::void_to_fake_void<Result>::type internal_result;

	// Type-specific task object
	typedef detail::task_result<internal_result> internal_task_type;

	// Common code for set()
	template<typename T> bool set_internal(T&& result) const
	{
		// Catch use of uninitialized task objects
		if (!internal_task)
			throw std::invalid_argument("Use of empty event_task object");

		// Only allow setting the value once
		detail::task_state expected = detail::task_state::TASK_PENDING;
		if (!internal_task->state.compare_exchange_strong(expected, detail::task_state::TASK_LOCKED, std::memory_order_relaxed, std::memory_order_relaxed))
			return false;

		try {
			// Store the result and finish
			static_cast<internal_task_type*>(internal_task.get())->set_result(std::forward<T>(result));
			internal_task->finish();
		} catch (...) {
			// If the copy/move constructor of the result threw, save the exception.
			// We could also return the exception to the caller, but this would
			// cause race conditions.
			internal_task->cancel(std::current_exception());
		}
		return true;
	}

public:
	// Movable but not copyable
	basic_event(const basic_event&) = delete;
	basic_event(basic_event&& other)
		: internal_task(std::move(other.internal_task))
	{
		other.internal_task = nullptr;
	}
	basic_event& operator=(const basic_event&) = delete;
	basic_event& operator=(basic_event&& other)
	{
		std::swap(internal_task, other.internal_task);
	}

	// Main constructor
	basic_event()
		: internal_task(new internal_task_type) {}

	// Cancel events if they are destroyed before they are set
	~basic_event()
	{<commit_msg>Fix small typo in basic_event<commit_after>// Copyright (c) 2013 <NAME>
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef ASYNCXX_H_
# error "Do not include this header directly, include <async++.h> instead."
#endif

namespace async {
namespace detail {

// Common code for task and shared_task
template<typename Result> class basic_task {
protected:
	// Reference counted internal task object
	detail::task_ptr internal_task;

	// Real result type, with void turned into fake_void
	typedef typename void_to_fake_void<Result>::type internal_result;

	// Type-specific task object
	typedef task_result<internal_result> internal_task_type;

	// Friend access
	template<typename T> friend class basic_task;
	template<typename T> friend typename T::internal_task_type* get_internal_task(const T& t);

	// Common code for get()
	void get_internal() const
	{
		// Catch use of uninitialized task objects
		if (!internal_task)
			throw std::invalid_argument("Use of empty task object");

		// If the task was canceled, throw the associated exception
		internal_task->wait_and_throw();
	}

	// Common code for then()
	template<typename Sched, typename Func, typename Parent> typename continuation_traits<Parent, Func>::task_type then_internal(Sched& sched, Func&& f, Parent&& parent) const
	{
		// Catch use of uninitialized task objects
		if (!internal_task)
			throw std::invalid_argument("Use of empty task object");

		// Save a copy of internal_task because it might get moved into exec_func
		task_base* my_internal = internal_task.get();

		// Create continuation
		typedef typename continuation_traits<Parent, Func>::task_type::internal_result cont_internal_result;
		typedef continuation_exec_func<typename std::decay<Parent>::type, cont_internal_result, typename std::decay<Func>::type, continuation_traits<Parent, Func>::is_value_cont::value, is_task<typename continuation_traits<Parent, Func>::result_type>::value> exec_func;
		typename continuation_traits<Parent, Func>::task_type cont;
		cont.internal_task = task_ptr(new task_func<exec_func, cont_internal_result>(exec_func(std::forward<Func>(f), std::forward<Parent>(parent))));

		// Set continuation parameters
		cont.internal_task->sched = std::addressof(sched);
		cont.internal_task->always_cont = !continuation_traits<Parent, Func>::is_value_cont::value;

		// Add the continuation to this task
		// Avoid an expensive ref-count modification since the task isn't shared yet
		cont.internal_task->add_ref_unlocked();
		my_internal->add_continuation(task_ptr(cont.internal_task.get()));

		return cont;
	}

public:
	// Task result type
	typedef Result result_type;

	explicit operator bool() const
	{
		return internal_task;
	}

	// Query whether the task has finished executing
	bool ready() const
	{
		if (internal_task->state.load(std::memory_order_relaxed) >= task_state::TASK_COMPLETED) {
			std::atomic_thread_fence(std::memory_order_acquire);
			return true;
		} else
			return false;
	}

	// Wait for the task to complete
	void wait() const
	{
		// Catch use of uninitialized task objects
		if (!internal_task)
			throw std::invalid_argument("Use of empty task object");

		internal_task->wait();
	}
};

// Common code for event_task specializations
template<typename Result> class basic_event {
protected:
	// Reference counted internal task object
	detail::task_ptr internal_task;

	// Real result type, with void turned into fake_void
	typedef typename detail::void_to_fake_void<Result>::type internal_result;

	// Type-specific task object
	typedef detail::task_result<internal_result> internal_task_type;

	// Common code for set()
	template<typename T> bool set_internal(T&& result) const
	{
		// Catch use of uninitialized task objects
		if (!internal_task)
			throw std::invalid_argument("Use of empty event_task object");

		// Only allow setting the value once
		detail::task_state expected = detail::task_state::TASK_PENDING;
		if (!internal_task->state.compare_exchange_strong(expected, detail::task_state::TASK_LOCKED, std::memory_order_relaxed, std::memory_order_relaxed))
			return false;

		try {
			// Store the result and finish
			static_cast<internal_task_type*>(internal_task.get())->set_result(std::forward<T>(result));
			internal_task->finish();
		} catch (...) {
			// If the copy/move constructor of the result threw, save the exception.
			// We could also return the exception to the caller, but this would
			// cause race conditions.
			internal_task->cancel_base(std::current_exception());
		}
		return true;
	}

public:
	// Movable but not copyable
	basic_event(const basic_event&) = delete;
	basic_event(basic_event&& other)
		: internal_task(std::move(other.internal_task))
	{
		other.internal_task = nullptr;
	}
	basic_event& operator=(const basic_event&) = delete;
	basic_event& operator=(basic_event&& other)
	{
		std::swap(internal_task, other.internal_task);
	}

	// Main constructor
	basic_event()
		: internal_task(new internal_task_type) {}

	// Cancel events if they are destroyed before they are set
	~basic_event()
	{
{'fraction_non_alphanumeric': 0.09773008666941807, 'fraction_numerical': 0.000660338423442014, 'mean_word_length': 4.901607403799318, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 81, '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': '2321375', 'n_tokens_mistral': 3722, 'n_tokens_neox': 3419, 'n_words': 1162}