<commit_before>#pragma once

#include "Communicator.hpp"
#include "PoolAllocator.hpp"
#include "FullEmpty.hpp"
#include "LegacyDelegate.hpp"
#include "GlobalCompletionEvent.hpp"
#include "ParallelLoop.hpp"
#include <type_traits>

namespace Grappa {
  
  namespace delegate {
    
    /// Do asynchronous generic delegate with `void` return type. Uses message pool to allocate
    /// the message. Enrolls with GCE so you can guarantee all have completed after a global
    /// GlobalCompletionEvent::wait() call.
    template<GlobalCompletionEvent * GCE = &Grappa::impl::local_gce, typename F = decltype(nullptr)>
    inline void call_async(MessagePoolBase& pool, Core dest, F remote_work) {
      static_assert(std::is_same< decltype(remote_work()), void >::value, "return type of callable must be void when not associated with Promise.");
      delegate_stats.count_op();
      Core origin = Grappa::mycore();
      
      if (dest == origin) {
        // short-circuit if local
        remote_work();
      } else {
        delegate_stats.count_op_am();
        if (GCE) GCE->enroll();
        
        pool.send_message(dest, [origin, remote_work] {
          remote_work();
          if (GCE) complete(make_global(GCE,origin));
        });
      }
    }
    
    /// A 'Promise' is a wrapper around a FullEmpty for async delegates with return values.
    /// The idea is to allocate storage for the result, issue the delegate request, and then
    /// block on waiting for the value when it's needed.
    ///<commit_msg>Add `delegate::increment_async()` because it comes up fairly frequently.<commit_after>#pragma once

#include "Communicator.hpp"
#include "PoolAllocator.hpp"
#include "FullEmpty.hpp"
#include "LegacyDelegate.hpp"
#include "GlobalCompletionEvent.hpp"
#include "ParallelLoop.hpp"
#include <type_traits>

namespace Grappa {
  
  namespace delegate {
    
    /// Do asynchronous generic delegate with `void` return type. Uses message pool to allocate
    /// the message. Enrolls with GCE so you can guarantee all have completed after a global
    /// GlobalCompletionEvent::wait() call.
    template<GlobalCompletionEvent * GCE = &Grappa::impl::local_gce, typename F = decltype(nullptr)>
    inline void call_async(MessagePoolBase& pool, Core dest, F remote_work) {
      static_assert(std::is_same< decltype(remote_work()), void >::value, "return type of callable must be void when not associated with Promise.");
      delegate_stats.count_op();
      Core origin = Grappa::mycore();
      
      if (dest == origin) {
        // short-circuit if local
        remote_work();
      } else {
        delegate_stats.count_op_am();
        if (GCE) GCE->enroll();
        
        pool.send_message(dest, [origin, remote_work] {
          remote_work();
          if (GCE) complete(make_global(GCE,origin));
        });
      }
    }
    
    template<typename T, typename U, GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    inline void increment_async(MessagePoolBase& pool, GlobalAddress<T> target, U increment) {
      delegate::call_async(target.core(), [increment]{
        (target.pointer()) += increment;
      });
    }
    
    /// A 'Promise' is a wrapper around a FullEmpty for async delegates with return values.
    /// The idea is to allocate storage for the result, issue the delegate request, and then
    /// block on waiting for the value when it's needed.
    ///
{'fraction_non_alphanumeric': 0.11010248901903368, 'fraction_numerical': 0.0, 'mean_word_length': 3.095923261390887, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, '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': '2850438', 'n_tokens_mistral': 972, 'n_tokens_neox': 955, 'n_words': 308}