<commit_before>/*
* Certificate Store
* (C) 1999-2019 Jack Lloyd
* (C) 2018-2019 Patrik Fiedler, Tim Oesterreich
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/certstor_windows.h>
#include <botan/pkix_types.h>
#include <functional>

#include <array>
#include <vector>

#define NOMINMAX 1
#define _WINSOCKAPI_ // stop windows.h including winsock.h
#include <windows.h>
#include <wincrypt.h>

#define WINCRYPT_UNUSED_PARAM 0 // for avoiding warnings when passing NULL to unused params in win32 api that accept integer types

namespace Botan {
namespace {

const std::array<const char*, 2> cert_store_names{"Root", "CA"};

/**
 * Abstract RAII wrapper for PCCERT_CONTEXT and HCERTSTORE
 * The Windows API partly takes care of those pointers destructions itself.
 * Especially, iteratively calling `CertFindCertificateInStore` with the previous PCCERT_CONTEXT
 * will free the context and return a new one. In this case, this guard takes care of freeing the context
 * in case of an exception and at the end of the iterative process.
 */
template<class T>
class Handle_Guard
   {
   public:
      Handle_Guard(T context)
         : m_context(context)
         {
         }

      Handle_Guard(const Handle_Guard<T>& rhs) = delete;
      Handle_Guard(Handle_Guard<T>&& rhs) :
         m_context(std::move(rhs.m_context))
         {
         rhs.m_context = nullptr;
         }

      ~Handle_Guard()
         {
         close<T>();
         }

      operator bool() const
         {
         return m_context != nullptr;
         }

      bool assign(T context)
         {
         m_context = context;
         return m_context != nullptr;
         }

      T& get()
         {
         return m_context;
         }

      const T& get() const
         {
         return m_context;
         }

      T operator->()
         {
         return m_context;
         }

   private:
      template<class T2 = T>
      typename std::enable_if<std::is_same<T2, PCCERT_CONTEXT>::value>::type close()
         {
         if(m_context)
            {
            CertFreeCertificateContext(m_context);
            }
         }

      template<class T2 = T>
      typename std::enable_if<std::is_same<T2, HCERTSTORE>::value>::type close()
         {
         if(m_context)
            {
            // second parameter is a flag that tells the store how to deallocate memory
            // using the default "0", this function works like decreasing the reference counter
            // in a shared_ptr
            CertCloseStore(m_context, 0);
            }
         }

      T m_context;
   };

HCERTSTORE open_cert_store(const char* cert_store_name)
   {
   auto store = CertOpenSystemStoreA(WINCRYPT_UNUSED_PARAM, cert_store_name);
   if(!store)
      {
      throw Botan::Internal_Error(
         "failed to open windows certificate store '" + std::string(cert_store_name) +
         "' (Error Code: " +
         std::to_string(::GetLastError()) + ")");
      }
   return store;
   }

std::vector<X509_Certificate> search_cert_stores(
   const _CRYPTOAPI_BLOB& blob, const DWORD& find_type,
   std::function<bool (const std::vector<X509_Certificate>& certs, const X509_Certificate& cert)> filter,
   bool return_on_first_found)
   {
   std::vector<X509_Certificate> certs;
   for(const auto store_name : cert_store_names)
      {
      Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
      Handle_Guard<PCCERT_CONTEXT> cert_context = nullptr;
      while(cert_context.assign(CertFindCertificateInStore(
                                   windows_cert_store.get(), PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
                                   WINCRYPT_UNUSED_PARAM, find_type,
                                   &blob, cert_context.get())))
         {
         X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
         if(filter(certs, cert))
            {
            if(return_on_first_found)
               {
               return {cert};
               }
            certs.push_back(cert);
            }
         }
      }

   return certs;
   }

bool already_contains_certificate(const std::vector<X509_Certificate>& certs, X509_Certificate cert)
   {
   return std::any_of(certs.begin(), certs.end(), [&](const X509_Certificate& c)
      {
      return c == cert;
      });
   }

std::vector<X509_Certificate> find_cert_by_dn_and_key_id(const Botan::X509_DN& subject_dn,
                                       const std::vector<uint8_t>& key_id,
                                       bool return_on_first_found)
   {
   _CRYPTOAPI_BLOB blob;
   DWORD find_type;
   std::vector<uint8_t> dn_data; // has to live until search completes

   // if key_id is available, prefer searching that, as it should be "more unique" than the subject DN
   if(key_id.empty())
      {
      find_type = CERT_FIND_SUBJECT_NAME;
      dn_data = subject_dn.DER_encode();
      blob.cbData = static_cast<DWORD>(dn_data.size());
      blob.pbData = reinterpret_cast<BYTE*>(dn_data.data());
      }
   else
      {
      find_type = CERT_FIND_KEY_IDENTIFIER;
      blob.cbData = static_cast<DWORD>(key_id.size());
      blob.pbData = const_cast<BYTE*>(key_id.data());
      }

   auto filter = [&](const std::vector<X509_Certificate>& certs, const X509_Certificate& cert)
      {
      return !already_contains_certificate(certs, cert) && (key_id.empty() || cert.subject_dn() == subject_dn);
      };

   return search_cert_stores(blob, find_type, filter, return_on_first_found);
   }
} // namespace

Certificate_Store_Windows::Certificate_Store_Windows() {}

std::vector<X509_DN> Certificate_Store_Windows::all_subjects() const
   {
   std::vector<X509_DN> subject_dns;
   for(const auto store_name : cert_store_names)
      {
      Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
      Handle_Guard<PCCERT_CONTEXT> cert_context = nullptr;

      // Handle_Guard::assign exchanges the underlying pointer. No RAII is needed here, because the Windows API takes care of
      // freeing the previous context.
      while(cert_context.assign(CertEnumCertificatesInStore(windows_cert_store.get(), cert_context.get())))
         {
         X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
         subject_dns.push_back(cert.subject_dn());
         }
      }

   return subject_dns;
   }

std::optional<X509_Certificate>
Certificate_Store_Windows::find_cert(const Botan::X509_DN& subject_dn,
                                     const std::vector<uint8_t>& key_id) const
   {
   const auto certs = find_cert_by_dn_and_key_id(subject_dn, key_id, true);
   if(certs.empty())
      return std::nullopt;
   else
      return certs.front();
   }

std::vector<X509_Certificate> Certificate_Store_Windows::find_all_certs(
   const X509_DN& subject_dn,
   const std::vector<uint8_t>& key_id) const
   {
   return find_cert_by_dn_and_key_id(subject_dn, key_id, false);
   }

std::optional<X509_Certificate>
Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
   {
   if(key_hash.size() != 20)
      {
      throw Invalid_Argument("Certificate_Store_Windows::find_cert_by_pubkey_sha1 invalid hash");
      }

   CRYPT_HASH_BLOB blob;
   blob.cbData = static_cast<DWORD>(key_hash.size());
   blob.pbData = const_cast<BYTE*>(key_hash.data());

   auto filter = [&](const std::vector<X509_Certificate>&, const X509_Certificate&) { return true; };

   const auto certs = search_cert_stores(blob, CERT_FIND_KEY_IDENTIFIER, filter, true);
   if(certs.empty())
      return std::nullopt;
   else
      return certs.front();
   }

std::optional<X509_Certificate>
Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256(
   const std::vector<uint8_t>& subject_hash) const
   {
   BOTAN_UNUSED(subject_hash);
   throw Not_Implemented("Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256");
   }

std::optional<X509_CRL> Certificate_Store_Windows::find_crl_for(const X509_Certificate& subject) const
   {
   // TODO: this could be implemented by using the CertFindCRLInStore function
   BOTAN_UNUSED(subject);
   return std::nullopt;
   }
}
<commit_msg>improve performance of Certificate_Store_Windows::all_subjects()<commit_after>/*
* Certificate Store
* (C) 1999-2021 Jack Lloyd
* (C) 2018-2019 Patrik Fiedler, Tim Oesterreich
* (C) 2021      René Meusel
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/ber_dec.h>
#include <botan/certstor_windows.h>
#include <botan/pkix_types.h>

#include <array>
#include <functional>
#include <vector>

#define NOMINMAX 1
#define _WINSOCKAPI_ // stop windows.h including winsock.h
#include <windows.h>
#include <wincrypt.h>

#define WINCRYPT_UNUSED_PARAM 0 // for avoiding warnings when passing NULL to unused params in win32 api that accept integer types

namespace Botan {
namespace {

const std::array<const char*, 2> cert_store_names{"Root", "CA"};

/**
 * Abstract RAII wrapper for PCCERT_CONTEXT and HCERTSTORE
 * The Windows API partly takes care of those pointers destructions itself.
 * Especially, iteratively calling `CertFindCertificateInStore` with the previous PCCERT_CONTEXT
 * will free the context and return a new one. In this case, this guard takes care of freeing the context
 * in case of an exception and at the end of the iterative process.
 */
template<class T>
class Handle_Guard
   {
   public:
      Handle_Guard(T context)
         : m_context(context)
         {
         }

      Handle_Guard(const Handle_Guard<T>& rhs) = delete;
      Handle_Guard(Handle_Guard<T>&& rhs) :
         m_context(std::move(rhs.m_context))
         {
         rhs.m_context = nullptr;
         }

      ~Handle_Guard()
         {
         close<T>();
         }

      operator bool() const
         {
         return m_context != nullptr;
         }

      bool assign(T context)
         {
         m_context = context;
         return m_context != nullptr;
         }

      T& get()
         {
         return m_context;
         }

      const T& get() const
         {
         return m_context;
         }

      T operator->()
         {
         return m_context;
         }

   private:
      template<class T2 = T>
      typename std::enable_if<std::is_same<T2, PCCERT_CONTEXT>::value>::type close()
         {
         if(m_context)
            {
            CertFreeCertificateContext(m_context);
            }
         }

      template<class T2 = T>
      typename std::enable_if<std::is_same<T2, HCERTSTORE>::value>::type close()
         {
         if(m_context)
            {
            // second parameter is a flag that tells the store how to deallocate memory
            // using the default "0", this function works like decreasing the reference counter
            // in a shared_ptr
            CertCloseStore(m_context, 0);
            }
         }

      T m_context;
   };

HCERTSTORE open_cert_store(const char* cert_store_name)
   {
   auto store = CertOpenSystemStoreA(WINCRYPT_UNUSED_PARAM, cert_store_name);
   if(!store)
      {
      throw Botan::Internal_Error(
         "failed to open windows certificate store '" + std::string(cert_store_name) +
         "' (Error Code: " +
         std::to_string(::GetLastError()) + ")");
      }
   return store;
   }

std::vector<X509_Certificate> search_cert_stores(
   const _CRYPTOAPI_BLOB& blob, const DWORD& find_type,
   std::function<bool (const std::vector<X509_Certificate>& certs, const X509_Certificate& cert)> filter,
   bool return_on_first_found)
   {
   std::vector<X509_Certificate> certs;
   for(const auto store_name : cert_store_names)
      {
      Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
      Handle_Guard<PCCERT_CONTEXT> cert_context = nullptr;
      while(cert_context.assign(CertFindCertificateInStore(
                                   windows_cert_store.get(), PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
                                   WINCRYPT_UNUSED_PARAM, find_type,
                                   &blob, cert_context.get())))
         {
         X509_Certificate cert(cert_context->pbCertEncoded, cert_context->cbCertEncoded);
         if(filter(certs, cert))
            {
            if(return_on_first_found)
               {
               return {cert};
               }
            certs.push_back(cert);
            }
         }
      }

   return certs;
   }

bool already_contains_certificate(const std::vector<X509_Certificate>& certs, X509_Certificate cert)
   {
   return std::any_of(certs.begin(), certs.end(), [&](const X509_Certificate& c)
      {
      return c == cert;
      });
   }

std::vector<X509_Certificate> find_cert_by_dn_and_key_id(const Botan::X509_DN& subject_dn,
                                       const std::vector<uint8_t>& key_id,
                                       bool return_on_first_found)
   {
   _CRYPTOAPI_BLOB blob;
   DWORD find_type;
   std::vector<uint8_t> dn_data; // has to live until search completes

   // if key_id is available, prefer searching that, as it should be "more unique" than the subject DN
   if(key_id.empty())
      {
      find_type = CERT_FIND_SUBJECT_NAME;
      dn_data = subject_dn.DER_encode();
      blob.cbData = static_cast<DWORD>(dn_data.size());
      blob.pbData = reinterpret_cast<BYTE*>(dn_data.data());
      }
   else
      {
      find_type = CERT_FIND_KEY_IDENTIFIER;
      blob.cbData = static_cast<DWORD>(key_id.size());
      blob.pbData = const_cast<BYTE*>(key_id.data());
      }

   auto filter = [&](const std::vector<X509_Certificate>& certs, const X509_Certificate& cert)
      {
      return !already_contains_certificate(certs, cert) && (key_id.empty() || cert.subject_dn() == subject_dn);
      };

   return search_cert_stores(blob, find_type, filter, return_on_first_found);
   }
} // namespace

Certificate_Store_Windows::Certificate_Store_Windows() {}

std::vector<X509_DN> Certificate_Store_Windows::all_subjects() const
   {
   std::vector<X509_DN> subject_dns;
   for(const auto store_name : cert_store_names)
      {
      Handle_Guard<HCERTSTORE> windows_cert_store = open_cert_store(store_name);
      Handle_Guard<PCCERT_CONTEXT> cert_context = nullptr;

      // Handle_Guard::assign exchanges the underlying pointer. No RAII is needed here, because the Windows API takes care of
      // freeing the previous context.
      while(cert_context.assign(CertEnumCertificatesInStore(windows_cert_store.get(), cert_context.get())))
         {
         BER_Decoder dec(cert_context->pCertInfo->Subject.pbData, cert_context->pCertInfo->Subject.cbData);

         X509_DN dn;
         dn.decode_from(dec);
         subject_dns.emplace_back(std::move(dn));
         }
      }

   return subject_dns;
   }

std::optional<X509_Certificate>
Certificate_Store_Windows::find_cert(const Botan::X509_DN& subject_dn,
                                     const std::vector<uint8_t>& key_id) const
   {
   const auto certs = find_cert_by_dn_and_key_id(subject_dn, key_id, true);
   if(certs.empty())
      return std::nullopt;
   else
      return certs.front();
   }

std::vector<X509_Certificate> Certificate_Store_Windows::find_all_certs(
   const X509_DN& subject_dn,
   const std::vector<uint8_t>& key_id) const
   {
   return find_cert_by_dn_and_key_id(subject_dn, key_id, false);
   }

std::optional<X509_Certificate>
Certificate_Store_Windows::find_cert_by_pubkey_sha1(const std::vector<uint8_t>& key_hash) const
   {
   if(key_hash.size() != 20)
      {
      throw Invalid_Argument("Certificate_Store_Windows::find_cert_by_pubkey_sha1 invalid hash");
      }

   CRYPT_HASH_BLOB blob;
   blob.cbData = static_cast<DWORD>(key_hash.size());
   blob.pbData = const_cast<BYTE*>(key_hash.data());

   auto filter = [&](const std::vector<X509_Certificate>&, const X509_Certificate&) { return true; };

   const auto certs = search_cert_stores(blob, CERT_FIND_KEY_IDENTIFIER, filter, true);
   if(certs.empty())
      return std::nullopt;
   else
      return certs.front();
   }

std::optional<X509_Certificate>
Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256(
   const std::vector<uint8_t>& subject_hash) const
   {
   BOTAN_UNUSED(subject_hash);
   throw Not_Implemented("Certificate_Store_Windows::find_cert_by_raw_subject_dn_sha256");
   }

std::optional<X509_CRL> Certificate_Store_Windows::find_crl_for(const X509_Certificate& subject) const
   {
   // TODO: this could be implemented by using the CertFindCRLInStore function
   BOTAN_UNUSED(subject);
   return std::nullopt;
   }
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include "array_merge.h"

void arrays_match(int size, int a[], int b[]) {
  int i;

  for (i=0; i<size; ++i) {
    ASSERT_EQ(b[i], a[i]);
  }
}

TEST(ArrayMerge, Handle_empty_list) {
  int* a[] = { };
  int sizes[] = { };
  int expected[] = { 0 };
  int* result;

  result = array_merge(0, sizes,  a);
  arrays_match(1, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_singleton_list) {
  int num_arrays = 1;
  int sizes[] = { 1 };
  int a0[] = { 5 };
  int* a[] = { a0 };
  int expected[] = { 1, 5 };
  int* result;

  result = array_merge(num_arrays, sizes, a);
  arrays_match(2, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_one_longer_list) {
  int num_arrays = 1;
  int sizes[] = { 10 };
  int a0[] = { 3, 2, 0, 5, 8, 9, 6, 3, 2, 0 };
  int* a[] = { a0 };
  int expected[] = { 7, 0, 2, 3, 5, 6, 8, 9 };
  int* result;

  result = array_merge(num_arrays, sizes, a);
  arrays_match(8, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_multiple_copies_of_longer_list) {
  int num_arrays = 10;
  int sizes[] = { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 };
  int a0[] = { 3, 2, 0, 5, 8, 9, 6, 3, 2, 0 };
  int* a[] = { a0, a0, a0, a0, a0, a0, a0, a0, a0, a0 };
  int expected[] = { 7, 0, 2, 3, 5, 6, 8, 9 };
  int* result;

  result = array_merge(num_arrays, sizes, a);
  arrays_match(8, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_multiple_copies_of_longer_list_different_orders) {
  int num_arrays = 9;
  int sizes[] = { 10, 10, 10, 10, 10, 10, 10, 10, 10 };
  int a0[] = { 3, 2, 0, 5, 8, 9, 6, 3, 2, 0 };
  int a1[] = { 5, 8, 9, 3, 2, 0, 6, 3, 2, 0 };
  int a2[] = { 8, 5, 0, 2, 3, 0, 2, 3, 6, 9 };
  int* a[] = { a0, a1, a2, a0, a1, a2, a0, a1, a2 };
  int expected[] = { 7, 0, 2, 3, 5, 6, 8, 9 };
  int* result;

  result = array_merge(num_arrays, sizes, a);
  arrays_match(8, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_different_sizes) {
  int num_arrays = 11;
  int sizes[num_arrays];
  int* a[num_arrays];
  int expected[] = { 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  int* result;
  int i, j;

  for (i=0; i<num_arrays; ++i) {
    sizes[i] = i;
    a[i] = (int*) calloc(i, sizeof(int));
    for (j=0; j<i; ++j) {
      a[i][j] = j;
    }
  }

  result = array_merge(num_arrays, sizes, a);
  arrays_match(11, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_different_sizes_reversed) {
  int num_arrays = 11;
  int sizes[num_arrays];
  int* a[num_arrays];
  int expected[] = { 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  int* result;
  int i, j;

  for (i=num_arrays-1; i>=0; --i) {
    sizes[i] = i;
    a[i] = (int*) calloc(i, sizeof(int));
    for (j=0; j<i; ++j) {
      a[i][j] = j;
    }
  }

  result = array_merge(num_arrays, sizes, a);
  arrays_match(11, result, expected);
  free(result);
}

int main(int argc, char* argv[]) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>add more free: free a[i] in last two test<commit_after>#include <gtest/gtest.h>

#include "array_merge.h"

void arrays_match(int size, int a[], int b[]) {
  int i;

  for (i=0; i<size; ++i) {
    ASSERT_EQ(b[i], a[i]);
  }
}

TEST(ArrayMerge, Handle_empty_list) {
  int* a[] = { };
  int sizes[] = { };
  int expected[] = { 0 };
  int* result;

  result = array_merge(0, sizes,  a);
  arrays_match(1, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_singleton_list) {
  int num_arrays = 1;
  int sizes[] = { 1 };
  int a0[] = { 5 };
  int* a[] = { a0 };
  int expected[] = { 1, 5 };
  int* result;

  result = array_merge(num_arrays, sizes, a);
  arrays_match(2, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_one_longer_list) {
  int num_arrays = 1;
  int sizes[] = { 10 };
  int a0[] = { 3, 2, 0, 5, 8, 9, 6, 3, 2, 0 };
  int* a[] = { a0 };
  int expected[] = { 7, 0, 2, 3, 5, 6, 8, 9 };
  int* result;

  result = array_merge(num_arrays, sizes, a);
  arrays_match(8, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_multiple_copies_of_longer_list) {
  int num_arrays = 10;
  int sizes[] = { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 };
  int a0[] = { 3, 2, 0, 5, 8, 9, 6, 3, 2, 0 };
  int* a[] = { a0, a0, a0, a0, a0, a0, a0, a0, a0, a0 };
  int expected[] = { 7, 0, 2, 3, 5, 6, 8, 9 };
  int* result;

  result = array_merge(num_arrays, sizes, a);
  arrays_match(8, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_multiple_copies_of_longer_list_different_orders) {
  int num_arrays = 9;
  int sizes[] = { 10, 10, 10, 10, 10, 10, 10, 10, 10 };
  int a0[] = { 3, 2, 0, 5, 8, 9, 6, 3, 2, 0 };
  int a1[] = { 5, 8, 9, 3, 2, 0, 6, 3, 2, 0 };
  int a2[] = { 8, 5, 0, 2, 3, 0, 2, 3, 6, 9 };
  int* a[] = { a0, a1, a2, a0, a1, a2, a0, a1, a2 };
  int expected[] = { 7, 0, 2, 3, 5, 6, 8, 9 };
  int* result;

  result = array_merge(num_arrays, sizes, a);
  arrays_match(8, result, expected);
  free(result);
}

TEST(ArrayMerge, Handle_different_sizes) {
  int num_arrays = 11;
  int sizes[num_arrays];
  int* a[num_arrays];
  int expected[] = { 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  int* result;
  int i, j;

  for (i=0; i<num_arrays; ++i) {
    sizes[i] = i;
    a[i] = (int*) calloc(i, sizeof(int));
    for (j=0; j<i; ++j) {
      a[i][j] = j;
    }
  }

  result = array_merge(num_arrays, sizes, a);
  arrays_match(11, result, expected);
  for (i=0; i<num_arrays;++i) {
  	free(a[i]);
  }
  free(result);
}

TEST(ArrayMerge, Handle_different_sizes_reversed) {
  int num_arrays = 11;
  int sizes[num_arrays];
  int* a[num_arrays];
  int expected[] = { 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  int* result;
  int i, j;

  for (i=num_arrays-1; i>=0; --i) {
    sizes[i] = i;
    a[i] = (int*) calloc(i, sizeof(int));
    for (j=0; j<i; ++j) {
      a[i][j] = j;
    }
  }

  result = array_merge(num_arrays, sizes, a);
  arrays_match(11, result, expected);
  for (i=0; i<num_arrays;++i) {
  	free(a[i]);
  }
  free(result);
}

int main(int argc, char* argv[]) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>#ifndef MOLP_HPP
#define MOLP_HPP

#include <list>
#include "BVect.hpp"
#include "BEdge.hpp"
#include "DominanceStatus.hpp"

class MOLP {
 private:
  std::list<BEdge> set;
 public:
  MOLP();
  MOLP(std::list<BEdge>);
  std::list<BEdge> edges() const;
  std::list<BEdge>::iterator begin();
  std::list<BEdge>::iterator end();
  bool empty() const;
  unsigned size() const;
  void push_back(const BEdge&);
  void extendWithPoint(const BVect&);
  BVect leftmostPoint() const;
  BVect rightmostPoint() const;
  bool isInA1AreaOf(const MOLP&) const;
  bool isInA2AreaOf(const MOLP&) const;
  DominanceStatus computeUpdate(const MOLP&, std::list<MOLP>&) const;
};

#endif
<commit_msg>MOLP: Add << ostream operator<commit_after>#ifndef MOLP_HPP
#define MOLP_HPP

#include <list>
#include "BVect.hpp"
#include "BEdge.hpp"
#include "DominanceStatus.hpp"

class MOLP {
 private:
  std::list<BEdge> set;
 public:
  MOLP();
  MOLP(std::list<BEdge>);
  std::list<BEdge> edges() const;
  std::list<BEdge>::iterator begin();
  std::list<BEdge>::iterator end();
  bool empty() const;
  unsigned size() const;
  void push_back(const BEdge&);
  void extendWithPoint(const BVect&);
  BVect leftmostPoint() const;
  BVect rightmostPoint() const;
  bool isInA1AreaOf(const MOLP&) const;
  bool isInA2AreaOf(const MOLP&) const;
  DominanceStatus computeUpdate(const MOLP&, std::list<MOLP>&) const;
  friend ostream& operator << (ostream& s, const MOLP& m) {
    s << "{ ";
    for (auto edge: m.edges())
      s << edge << " ";
    s << "}";
    return s;
  }
};

#endif
<|endoftext|>


<commit_before><commit_msg>Update cost.hpp<commit_after>#ifndef COST_HPP_
#defin COST_HPP_

#include <vector>
#include <iostream>
#include <cstdlib>

#include "math_fucntions.hpp"
#include "graph_functions.hpp"
#include "solver_functions.hpp"

#include "Model.hpp"
#include "MarkovChannel.pb.h"

double cost(Model& model, std::vector<MarkovChannel::ChannelProtocol>& protocols,
   MarkovChannel::SolverParameter& solver_param);

#endif
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2012 Francois Beaune, Jupiter Jazz Limited
//
// 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.
//

// Interface header.
#include "fastsubsurfacescatteringsurfaceshader.h"

// appleseed.renderer headers.
#include "renderer/global/globaltypes.h"
#include "renderer/kernel/intersection/intersector.h"
#include "renderer/kernel/lighting/lightsampler.h"
#include "renderer/kernel/shading/shadingcontext.h"
#include "renderer/kernel/shading/shadingpoint.h"
#include "renderer/kernel/shading/shadingray.h"
#include "renderer/kernel/shading/shadingresult.h"
#include "renderer/modeling/edf/edf.h"
#include "renderer/modeling/input/inputarray.h"
#include "renderer/modeling/input/inputevaluator.h"
#include "renderer/modeling/input/source.h"
#include "renderer/modeling/project/project.h"
#include "renderer/modeling/surfaceshader/surfaceshader.h"
#include "renderer/utility/paramarray.h"

// appleseed.foundation headers.
#include "foundation/image/colorspace.h"
#include "foundation/math/basis.h"
#include "foundation/math/sampling.h"
#include "foundation/math/vector.h"
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/containers/specializedarrays.h"
#include "foundation/utility/foreach.h"

// Standard headers.
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <limits>
#include <memory>

// Forward declarations.
namespace renderer  { class Assembly; }
namespace renderer  { class Scene; }

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Fast subsurface scattering surface shader.
    //
    // References:
    //
    //   http://publications.dice.se/attachments/Colin_BarreBrisebois_Programming_ApproximatingTranslucency.pdf
    //   http://publications.dice.se/attachments/Colin_BarreBrisebois_Programming_ApproximatingTranslucency.pptx
    //

    const char* Model = "fast_sss_surface_shader";

    class FastSubSurfaceScatteringSurfaceShader
      : public SurfaceShader
    {
      public:
        FastSubSurfaceScatteringSurfaceShader(
            const char*             name,
            const ParamArray&       params)
          : SurfaceShader(name, params)
          , m_light_samples(m_params.get_required<size_t>("light_samples", 1))
          , m_occlusion_samples(m_params.get_required<size_t>("occlusion_samples", 1))
        {
            m_inputs.declare("scale", InputFormatScalar);
            m_inputs.declare("ambient_sss", InputFormatScalar);
            m_inputs.declare("view_dep_sss", InputFormatScalar);
            m_inputs.declare("diffuse", InputFormatScalar);
            m_inputs.declare("power", InputFormatScalar);
            m_inputs.declare("distortion", InputFormatScalar);
            m_inputs.declare("albedo", InputFormatSpectrum);
        }

        virtual void release() override
        {
            delete this;
        }

        virtual const char* get_model() const override
        {
            return Model;
        }

        virtual bool on_frame_begin(
            const Project&          project,
            const Assembly&         assembly) override
        {
            if (!SurfaceShader::on_frame_begin(project, assembly))
                return false;

            const Scene& scene = *project.get_scene();

            m_light_sampler.reset(new LightSampler(scene));

            return true;
        }

        virtual void evaluate(
            SamplingContext&        sampling_context,
            const ShadingContext&   shading_context,
            const ShadingPoint&     shading_point,
            ShadingResult&          shading_result) const override
        {
            // Initialize the shading result to opaque black.
            shading_result.m_color_space = ColorSpaceSpectral;
            shading_result.m_color.set(0.0f);
            shading_result.m_alpha.set(1.0f);

            // Return black if there is no light in the scene.
            if (!m_light_sampler->has_lights_or_emitting_triangles())
                return;

            // Evaluate the shader inputs.
            InputValues values;
            m_inputs.evaluate(
                shading_context.get_texture_cache(),
                shading_point.get_uv(0),
                &values);

            // Retrieve the intersection point, the shading normal and the camera direction.
            const Vector3d& point = shading_point.get_point();
            const Vector3d& shading_normal = shading_point.get_shading_normal();
            const Vector3d inv_shading_normal = -shading_normal;
            const Vector3d camera_vec = normalize(-shading_point.get_ray().m_dir);                                          // toward camera

            // todo: there are possible correlation artifacts since the sampling_context
            // object is forked twice from there: once to compute the average occluder
            // distance sampler and once by the light sampler.

            // Compute the average occluder distance.
            const double avg_distance =
                compute_average_distance(
                    sampling_context,
                    shading_context.get_intersector(),
                    point,
                    -shading_point.get_geometric_normal(),
                    Basis3d(inv_shading_normal),
                    m_occlusion_samples,
                    &shading_point);
            assert(avg_distance >= 0.0);

            // Compute the total SSS contribution.
            const double K = 2.99573227;                                                                                // -ln(0.05)
            const double sss_contrib = exp(-(avg_distance / values.m_scale) * K);

            sampling_context.split_in_place(3, m_light_samples);

            for (size_t i = 0; i < m_light_samples; ++i)
            {
                // Sample the light sources.
                LightSample light_sample;
                m_light_sampler->sample(sampling_context.next_vector2<3>(), light_sample);

                // Compute the contribution of this light sample.
                const Vector3d light_vec = normalize(light_sample.m_point - point);                                         // toward light
                const Vector3d distorted_light_vec = normalize(light_vec + values.m_distortion * inv_shading_normal);       // normalize() not strictly necessary
                const double dot_nl = saturate(dot(shading_normal, light_vec));                                             // dot(N, L): diffuse lighting
                const double dot_vl = saturate(dot(camera_vec, -distorted_light_vec));                                      // dot(V, -L): view-dependent SSS
                const double view_dep = pow(dot_vl, values.m_power);
                const double sample_contrib =
                    (values.m_ambient_sss + view_dep * values.m_view_dep_sss) * sss_contrib +                               // subsurface scattering
                    dot_nl * values.m_diffuse;                                                                              // diffuse lighting

                // Evaluate the input values of the EDF.
                InputEvaluator edf_input_evaluator(shading_context.get_texture_cache());
                const void* edf_data =
                    edf_input_evaluator.evaluate(
                        light_sample.m_triangle->m_edf->get_inputs(),
                        light_sample.m_bary);

                // Evaluate the EDF.
                Spectrum edf_value;
                light_sample.m_triangle->m_edf->evaluate(
                    edf_data,
                    light_sample.m_geometric_normal,
                    Basis3d(light_sample.m_shading_normal),
                    -light_vec,
                    edf_value);

                // Compute and accumulate the contribution of this light sample.
                Spectrum result = values.m_albedo;
                result *= edf_value;
                result *= static_cast<float>(sample_contrib);
                shading_result.m_color += result;
            }

            // Normalize the result.
            if (m_light_samples > 1)
                shading_result.m_color /= static_cast<float>(m_light_samples);
        }

      private:
        const size_t            m_light_samples;
        const size_t            m_occlusion_samples;
        auto_ptr<LightSampler>  m_light_sampler;

        struct InputValues
        {
            double      m_scale;            // distance at which light absorption reaches 95%
            double      m_ambient_sss;
            double      m_view_dep_sss;
            double      m_diffuse;
            double      m_power;
            double      m_distortion;
            Spectrum    m_albedo;
            Alpha       m_alpha;
        };

        static double compute_average_distance(
            const SamplingContext&  sampling_context,
            const Intersector&      intersector,
            const Vector3d&         point,
            const Vector3d&         geometric_normal,
            const Basis3d&          shading_basis,
            const size_t            sample_count,
            const ShadingPoint*     parent_shading_point)
        {
            // Create a sampling context.
            SamplingContext child_sampling_context = sampling_context.split(2, sample_count);

            // Construct an ambient occlusion ray.
            ShadingRay ao_ray;
            ao_ray.m_org = point;
            ao_ray.m_tmin = 0.0;
            ao_ray.m_tmax = numeric_limits<double>::max();
            ao_ray.m_time = 0.0;
            ao_ray.m_flags = ~0;

            size_t computed_samples = 0;
            double average_distance = 0.0;

            for (size_t i = 0; i < sample_count; ++i)
            {
                // Generate a cosine-weighted direction over the unit hemisphere.
                const Vector2d s = child_sampling_context.next_vector2<2>();
                ao_ray.m_dir = sample_hemisphere_cosine(s);

                // Transform the direction to world space.
                ao_ray.m_dir = shading_basis.transform_to_parent(ao_ray.m_dir);

                // Don't cast rays on or below the geometric surface.
                if (dot(ao_ray.m_dir, geometric_normal) <= 0.0)
                    continue;

                // Count the number of computed samples.
                ++computed_samples;

                // Trace the ambient occlusion ray and update the accumulated hit distance.
                ShadingPoint shading_point;
                if (intersector.trace(ao_ray, shading_point, parent_shading_point))
                    average_distance += shading_point.get_distance();
            }

            // Compute occlusion as a scalar between 0.0 and 1.0.
            if (computed_samples > 1)
                average_distance /= computed_samples;

            return average_distance;
        }
    };
}

//
// FastSubSurfaceScatteringSurfaceShaderFactory class implementation.
//

const char* FastSubSurfaceScatteringSurfaceShaderFactory::get_model() const
{
    return Model;
}

const char* FastSubSurfaceScatteringSurfaceShaderFactory::get_human_readable_model() const
{
    return "Fast Subsurface Scattering (experimental)";
}

DictionaryArray FastSubSurfaceScatteringSurfaceShaderFactory::get_widget_definitions() const
{
    DictionaryArray definitions;

    {
        Dictionary widget;
        widget.insert("name", "scale");
        widget.insert("label", "Geometric Scale");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "1.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "ambient_sss");
        widget.insert("label", "Ambient SSS");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "0.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "view_dep_sss");
        widget.insert("label", "View-Dependent SSS");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "0.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "diffuse");
        widget.insert("label", "Diffuse Lighting");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "0.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "power");
        widget.insert("label", "Power");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "1.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "distortion");
        widget.insert("label", "Normal Distortion");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "0.0");
        definitions.push_back(widget);
    }

    {
        Dictionary entity_types;
        entity_types.insert("color", "Colors");
        entity_types.insert("texture_instance", "Textures");

        Dictionary widget;
        widget.insert("name", "albedo");
        widget.insert("label", "Albedo");
        widget.insert("widget", "entity_picker");
        widget.insert("entity_types", entity_types);
        widget.insert("use", "required");
        widget.insert("default", "");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "light_samples");
        widget.insert("label", "Light Samples");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "1");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "occlusion_samples");
        widget.insert("label", "Occlusion Samples");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "1");
        definitions.push_back(widget);
    }

    return definitions;
}

auto_release_ptr<SurfaceShader> FastSubSurfaceScatteringSurfaceShaderFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return
        auto_release_ptr<SurfaceShader>(
            new FastSubSurfaceScatteringSurfaceShader(name, params));
}

}   // namespace renderer
<commit_msg>the fast SSS surface shader was not handling non-physical lights such as point lights and spot lights correctly.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2012 Francois Beaune, Jupiter Jazz Limited
//
// 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.
//

// Interface header.
#include "fastsubsurfacescatteringsurfaceshader.h"

// appleseed.renderer headers.
#include "renderer/global/globaltypes.h"
#include "renderer/kernel/intersection/intersector.h"
#include "renderer/kernel/lighting/lightsampler.h"
#include "renderer/kernel/shading/shadingcontext.h"
#include "renderer/kernel/shading/shadingpoint.h"
#include "renderer/kernel/shading/shadingray.h"
#include "renderer/kernel/shading/shadingresult.h"
#include "renderer/modeling/edf/edf.h"
#include "renderer/modeling/input/inputarray.h"
#include "renderer/modeling/input/inputevaluator.h"
#include "renderer/modeling/input/source.h"
#include "renderer/modeling/light/light.h"
#include "renderer/modeling/project/project.h"
#include "renderer/modeling/surfaceshader/surfaceshader.h"
#include "renderer/utility/paramarray.h"

// appleseed.foundation headers.
#include "foundation/image/colorspace.h"
#include "foundation/math/basis.h"
#include "foundation/math/sampling.h"
#include "foundation/math/vector.h"
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/containers/specializedarrays.h"
#include "foundation/utility/foreach.h"

// Standard headers.
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <limits>
#include <memory>

// Forward declarations.
namespace renderer  { class Assembly; }
namespace renderer  { class Scene; }

using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    //
    // Fast subsurface scattering surface shader.
    //
    // References:
    //
    //   http://publications.dice.se/attachments/Colin_BarreBrisebois_Programming_ApproximatingTranslucency.pdf
    //   http://publications.dice.se/attachments/Colin_BarreBrisebois_Programming_ApproximatingTranslucency.pptx
    //

    const char* Model = "fast_sss_surface_shader";

    class FastSubSurfaceScatteringSurfaceShader
      : public SurfaceShader
    {
      public:
        FastSubSurfaceScatteringSurfaceShader(
            const char*             name,
            const ParamArray&       params)
          : SurfaceShader(name, params)
          , m_light_samples(m_params.get_required<size_t>("light_samples", 1))
          , m_occlusion_samples(m_params.get_required<size_t>("occlusion_samples", 1))
        {
            m_inputs.declare("scale", InputFormatScalar);
            m_inputs.declare("ambient_sss", InputFormatScalar);
            m_inputs.declare("view_dep_sss", InputFormatScalar);
            m_inputs.declare("diffuse", InputFormatScalar);
            m_inputs.declare("power", InputFormatScalar);
            m_inputs.declare("distortion", InputFormatScalar);
            m_inputs.declare("albedo", InputFormatSpectrum);
        }

        virtual void release() override
        {
            delete this;
        }

        virtual const char* get_model() const override
        {
            return Model;
        }

        virtual bool on_frame_begin(
            const Project&          project,
            const Assembly&         assembly) override
        {
            if (!SurfaceShader::on_frame_begin(project, assembly))
                return false;

            const Scene& scene = *project.get_scene();

            m_light_sampler.reset(new LightSampler(scene));

            return true;
        }

        virtual void evaluate(
            SamplingContext&        sampling_context,
            const ShadingContext&   shading_context,
            const ShadingPoint&     shading_point,
            ShadingResult&          shading_result) const override
        {
            // Initialize the shading result to opaque black.
            shading_result.m_color_space = ColorSpaceSpectral;
            shading_result.m_color.set(0.0f);
            shading_result.m_alpha.set(1.0f);

            // Return black if there is no light in the scene.
            if (!m_light_sampler->has_lights_or_emitting_triangles())
                return;

            // Evaluate the shader inputs.
            InputValues values;
            m_inputs.evaluate(
                shading_context.get_texture_cache(),
                shading_point.get_uv(0),
                &values);

            // Retrieve the intersection point, the shading normal and the camera direction.
            const Vector3d& point = shading_point.get_point();
            const Vector3d& shading_normal = shading_point.get_shading_normal();
            const Vector3d inv_shading_normal = -shading_normal;
            const Vector3d camera_vec = normalize(-shading_point.get_ray().m_dir);                                          // toward camera

            // todo: there are possible correlation artifacts since the sampling_context
            // object is forked twice from there: once to compute the average occluder
            // distance sampler and once by the light sampler.

            // Compute the average occluder distance.
            const double avg_distance =
                compute_average_distance(
                    sampling_context,
                    shading_context.get_intersector(),
                    point,
                    -shading_point.get_geometric_normal(),
                    Basis3d(inv_shading_normal),
                    m_occlusion_samples,
                    &shading_point);
            assert(avg_distance >= 0.0);

            // Compute the total SSS contribution.
            const double K = 2.99573227;                                                                                // -ln(0.05)
            const double sss_contrib = exp(-(avg_distance / values.m_scale) * K);

            sampling_context.split_in_place(3, m_light_samples);

            for (size_t i = 0; i < m_light_samples; ++i)
            {
                // Sample the light sources.
                LightSample light_sample;
                m_light_sampler->sample(sampling_context.next_vector2<3>(), light_sample);

                // Compute the contribution of this light sample.
                const Vector3d light_vec = normalize(light_sample.m_point - point);                                         // toward light
                const Vector3d distorted_light_vec = normalize(light_vec + values.m_distortion * inv_shading_normal);       // normalize() not strictly necessary
                const double dot_nl = saturate(dot(shading_normal, light_vec));                                             // dot(N, L): diffuse lighting
                const double dot_vl = saturate(dot(camera_vec, -distorted_light_vec));                                      // dot(V, -L): view-dependent SSS
                const double view_dep = pow(dot_vl, values.m_power);
                const double sample_contrib =
                    (values.m_ambient_sss + view_dep * values.m_view_dep_sss) * sss_contrib +                               // subsurface scattering
                    dot_nl * values.m_diffuse;                                                                              // diffuse lighting

                Spectrum exitance;
                if (light_sample.m_triangle)
                {
                    // Evaluate the EDF's inputs.
                    InputEvaluator input_evaluator(shading_context.get_texture_cache());
                    const void* edf_data =
                        input_evaluator.evaluate(
                            light_sample.m_triangle->m_edf->get_inputs(),
                            light_sample.m_bary);

                    // Evaluate the EDF.
                    light_sample.m_triangle->m_edf->evaluate(
                        edf_data,
                        light_sample.m_geometric_normal,
                        Basis3d(light_sample.m_shading_normal),
                        -light_vec,
                        exitance);
                }
                else
                {
                    // Evaluate the light's inputs.
                    InputEvaluator input_evaluator(shading_context.get_texture_cache());
                    const void* light_data =
                        input_evaluator.evaluate(
                            light_sample.m_light->get_inputs(),
                            light_sample.m_bary);

                    // Evaluate the light.
                    light_sample.m_light->evaluate(
                        light_data,
                        -light_vec,
                        exitance);
                }

                // Compute and accumulate the contribution of this light sample.
                Spectrum result = values.m_albedo;
                result *= exitance;
                result *= static_cast<float>(sample_contrib);
                shading_result.m_color += result;
            }

            // Normalize the result.
            if (m_light_samples > 1)
                shading_result.m_color /= static_cast<float>(m_light_samples);
        }

      private:
        const size_t            m_light_samples;
        const size_t            m_occlusion_samples;
        auto_ptr<LightSampler>  m_light_sampler;

        struct InputValues
        {
            double      m_scale;            // distance at which light absorption reaches 95%
            double      m_ambient_sss;
            double      m_view_dep_sss;
            double      m_diffuse;
            double      m_power;
            double      m_distortion;
            Spectrum    m_albedo;
            Alpha       m_alpha;
        };

        static double compute_average_distance(
            const SamplingContext&  sampling_context,
            const Intersector&      intersector,
            const Vector3d&         point,
            const Vector3d&         geometric_normal,
            const Basis3d&          shading_basis,
            const size_t            sample_count,
            const ShadingPoint*     parent_shading_point)
        {
            // Create a sampling context.
            SamplingContext child_sampling_context = sampling_context.split(2, sample_count);

            // Construct an ambient occlusion ray.
            ShadingRay ao_ray;
            ao_ray.m_org = point;
            ao_ray.m_tmin = 0.0;
            ao_ray.m_tmax = numeric_limits<double>::max();
            ao_ray.m_time = 0.0;
            ao_ray.m_flags = ~0;

            size_t computed_samples = 0;
            double average_distance = 0.0;

            for (size_t i = 0; i < sample_count; ++i)
            {
                // Generate a cosine-weighted direction over the unit hemisphere.
                const Vector2d s = child_sampling_context.next_vector2<2>();
                ao_ray.m_dir = sample_hemisphere_cosine(s);

                // Transform the direction to world space.
                ao_ray.m_dir = shading_basis.transform_to_parent(ao_ray.m_dir);

                // Don't cast rays on or below the geometric surface.
                if (dot(ao_ray.m_dir, geometric_normal) <= 0.0)
                    continue;

                // Count the number of computed samples.
                ++computed_samples;

                // Trace the ambient occlusion ray and update the accumulated hit distance.
                ShadingPoint shading_point;
                if (intersector.trace(ao_ray, shading_point, parent_shading_point))
                    average_distance += shading_point.get_distance();
            }

            // Compute occlusion as a scalar between 0.0 and 1.0.
            if (computed_samples > 1)
                average_distance /= computed_samples;

            return average_distance;
        }
    };
}

//
// FastSubSurfaceScatteringSurfaceShaderFactory class implementation.
//

const char* FastSubSurfaceScatteringSurfaceShaderFactory::get_model() const
{
    return Model;
}

const char* FastSubSurfaceScatteringSurfaceShaderFactory::get_human_readable_model() const
{
    return "Fast Subsurface Scattering (experimental)";
}

DictionaryArray FastSubSurfaceScatteringSurfaceShaderFactory::get_widget_definitions() const
{
    DictionaryArray definitions;

    {
        Dictionary widget;
        widget.insert("name", "scale");
        widget.insert("label", "Geometric Scale");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "1.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "ambient_sss");
        widget.insert("label", "Ambient SSS");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "0.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "view_dep_sss");
        widget.insert("label", "View-Dependent SSS");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "0.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "diffuse");
        widget.insert("label", "Diffuse Lighting");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "0.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "power");
        widget.insert("label", "Power");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "1.0");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "distortion");
        widget.insert("label", "Normal Distortion");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "0.0");
        definitions.push_back(widget);
    }

    {
        Dictionary entity_types;
        entity_types.insert("color", "Colors");
        entity_types.insert("texture_instance", "Textures");

        Dictionary widget;
        widget.insert("name", "albedo");
        widget.insert("label", "Albedo");
        widget.insert("widget", "entity_picker");
        widget.insert("entity_types", entity_types);
        widget.insert("use", "required");
        widget.insert("default", "");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "light_samples");
        widget.insert("label", "Light Samples");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "1");
        definitions.push_back(widget);
    }

    {
        Dictionary widget;
        widget.insert("name", "occlusion_samples");
        widget.insert("label", "Occlusion Samples");
        widget.insert("widget", "text_box");
        widget.insert("use", "required");
        widget.insert("default", "1");
        definitions.push_back(widget);
    }

    return definitions;
}

auto_release_ptr<SurfaceShader> FastSubSurfaceScatteringSurfaceShaderFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return
        auto_release_ptr<SurfaceShader>(
            new FastSubSurfaceScatteringSurfaceShader(name, params));
}

}   // namespace renderer
<|endoftext|>


<commit_before>#pragma once

#include <agency/detail/config.hpp>
#include <agency/execution_policy.hpp>
#include <agency/flattened_executor.hpp>
#include <agency/cuda/execution_agent.hpp>
#include <agency/cuda/grid_executor.hpp>
#include <agency/cuda/parallel_executor.hpp>
#include <agency/cuda/concurrent_executor.hpp>
#include <agency/cuda/nested_executor.hpp>
#include <agency/cuda/bulk_invoke.hpp>
#include <agency/detail/tuple.hpp>
#include <type_traits>

namespace agency
{
namespace cuda
{
namespace detail
{

// add basic_execution_policy to allow us to catch its derivations as overloads of bulk_invoke, etc.
template<class ExecutionAgent,
         class BulkExecutor,
         class ExecutionCategory = typename execution_agent_traits<ExecutionAgent>::execution_category,
         class DerivedExecutionPolicy = void>
class basic_execution_policy :
  public agency::detail::basic_execution_policy<
    ExecutionAgent,
    BulkExecutor,
    ExecutionCategory,
    typename std::conditional<
      std::is_void<DerivedExecutionPolicy>::value,
      basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
      DerivedExecutionPolicy
    >::type
>
{
  public:
    // inherit the base class's constructors
    using agency::detail::basic_execution_policy<
      ExecutionAgent,
      BulkExecutor,
      ExecutionCategory,
      typename std::conditional<
        std::is_void<DerivedExecutionPolicy>::value,
        basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
        DerivedExecutionPolicy
      >::type
    >::basic_execution_policy;
}; // end basic_execution_policy

} // end detail

class parallel_execution_policy : public detail::basic_execution_policy<cuda::parallel_agent, cuda::parallel_executor, parallel_execution_tag, parallel_execution_policy>
{
  private:
    using super_t = detail::basic_execution_policy<cuda::parallel_agent, cuda::parallel_executor, parallel_execution_tag, parallel_execution_policy>;

    using par2d_t = detail::basic_execution_policy<cuda::parallel_agent_2d, cuda::parallel_executor, parallel_execution_tag>;

  public:
    using super_t::basic_execution_policy;

    using super_t::operator();

    // XXX consider whether we really want this functionality a member of parallel_execution_policy
    inline par2d_t operator()(agency::size2 shape) const
    {
      par2d_t par2d;

      return par2d(shape);
    }

    // XXX consider whether we really want this functionality a member of parallel_execution_policy
    template<class ExecutionPolicy>
    agency::detail::nested_execution_policy<
      par2d_t,
      agency::detail::decay_t<ExecutionPolicy>
    >
      operator()(agency::size2 domain, ExecutionPolicy&& exec) const
    {
      par2d_t par2d;

      return par2d(domain, std::forward<ExecutionPolicy>(exec));
    }
};

const parallel_execution_policy par{};

class concurrent_execution_policy : public detail::basic_execution_policy<cuda::concurrent_agent, cuda::concurrent_executor, concurrent_execution_tag, concurrent_execution_policy>
{
  private:
    using super_t = detail::basic_execution_policy<cuda::concurrent_agent, cuda::concurrent_executor, concurrent_execution_tag, concurrent_execution_policy>;

    using con2d_t = detail::basic_execution_policy<cuda::concurrent_agent_2d, cuda::concurrent_executor, concurrent_execution_tag>;

  public:
    using super_t::basic_execution_policy;

    using super_t::operator();

    // XXX consider whether we really want this functionality a member of concurrent_execution_policy
    inline con2d_t operator()(agency::size2 shape) const
    {
      con2d_t con2d;

      return con2d(shape);
    }

    // XXX consider whether we really want this functionality a member of concurrent_execution_policy
    template<class ExecutionPolicy>
    agency::detail::nested_execution_policy<
      con2d_t,
      agency::detail::decay_t<ExecutionPolicy>
    >
      operator()(agency::size2 domain, ExecutionPolicy&& exec) const
    {
      con2d_t con2d;

      return con2d(domain, std::forward<ExecutionPolicy>(exec));
    }
};

const concurrent_execution_policy con{};

namespace detail
{

// specialize rebind_executor for cuda's executor types
template<class ExecutionPolicy, class Enable = void>
struct rebind_executor_impl;

template<class ExecutionPolicy>
struct rebind_executor_impl<
  ExecutionPolicy,
  typename std::enable_if<
    std::is_same<
      typename ExecutionPolicy::execution_category,
      parallel_execution_tag
    >::value
  >::type
>
{
  using type = cuda::parallel_execution_policy;
};

// specialize rebind_executor for cuda::concurrent_executor
template<class ExecutionPolicy>
struct rebind_executor_impl<
  ExecutionPolicy,
  typename std::enable_if<
    std::is_same<
      typename ExecutionPolicy::execution_category,
      concurrent_execution_tag
    >::value
  >::type
>
{
  using type = cuda::concurrent_execution_policy;
};

} // end detail
} // end cuda

// specialize is_execution_policy
template<class ExecutionAgent,
         class BulkExecutor,
         class ExecutionCategory,
         class DerivedExecutionPolicy>
struct is_execution_policy<cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>> : std::true_type {};

template<>
struct is_execution_policy<cuda::parallel_execution_policy> : std::true_type {};

template<>
struct is_execution_policy<cuda::concurrent_execution_policy> : std::true_type {};

template<class ExecutionPolicy>
struct rebind_executor<ExecutionPolicy, cuda::grid_executor>
{
  using type = typename cuda::detail::rebind_executor_impl<ExecutionPolicy>::type;
};

template<class ExecutionPolicy>
struct rebind_executor<ExecutionPolicy, cuda::concurrent_executor>
{
  using type = typename cuda::detail::rebind_executor_impl<ExecutionPolicy>::type;
};

// the following functions are overloads of agency::bulk_invoke & agency::bulk_async
// for cuda execution policies. they forward along the to cuda::bulk_invoke & cuda::bulk_async
// we introduce these overloads to work around the use of lambdas in agency::bulk_invoke & agency::bulk_async

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
void bulk_invoke(cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>&& exec,
                 Function&& f,
                 Args&&... args)
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
void bulk_invoke(cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>& exec,
                 Function&& f,
                 Args&&... args)
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
void bulk_invoke(const cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>& exec,
                 Function&& f,
                 Args&&... args)
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
void bulk_invoke(cuda::parallel_execution_policy&& exec,
                 Function&& f,
                 Args&&... args)
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
void bulk_invoke(cuda::parallel_execution_policy& exec,
                 Function&& f,
                 Args&&... args)
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
void bulk_invoke(const cuda::parallel_execution_policy& exec,
                 Function&& f,
                 Args&&... args)
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
void bulk_invoke(cuda::concurrent_execution_policy&& exec,
                 Function&& f,
                 Args&&... args)
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
void bulk_invoke(cuda::concurrent_execution_policy& exec,
                 Function&& f,
                 Args&&... args)
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
void bulk_invoke(const cuda::concurrent_execution_policy& exec,
                 Function&& f,
                 Args&&... args)
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
agency::detail::policy_future<
  cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
  void
>
  bulk_async(cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>&& exec, Function&& f, Args&&... args)
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
agency::detail::policy_future<
  cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
  void
>
  bulk_async(cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>& exec, Function&& f, Args&&... args)
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
agency::detail::policy_future<
  cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
  void
>
  bulk_async(const cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>& exec, Function&& f, Args&&... args)
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
agency::detail::policy_future<
  cuda::parallel_execution_policy,
  void
>
  bulk_async(cuda::parallel_execution_policy&& exec,
             Function&& f,
             Args&&... args)
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
agency::detail::policy_future<
  cuda::parallel_execution_policy,
  void
>
  bulk_async(cuda::parallel_execution_policy& exec,
             Function&& f,
             Args&&... args)
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
agency::detail::policy_future<
  cuda::parallel_execution_policy,
  void
>
  bulk_async(const cuda::parallel_execution_policy& exec,
             Function&& f,
             Args&&... args)
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
agency::detail::policy_future<
  cuda::concurrent_execution_policy,
  void
>
  bulk_async(cuda::concurrent_execution_policy&& exec,
             Function&& f,
             Args&&... args)
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
agency::detail::policy_future<
  cuda::concurrent_execution_policy,
  void
>
  bulk_async(cuda::concurrent_execution_policy& exec,
             Function&& f,
             Args&&... args)
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
agency::detail::policy_future<
  cuda::concurrent_execution_policy,
  void
>
  bulk_async(const cuda::concurrent_execution_policy& exec,
             Function&& f,
             Args&&... args)
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

} // end agency

<commit_msg>Use return type deduction on the bulk_invoke & bulk_async overloads for CUDA execution policies in namespace agency<commit_after>#pragma once

#include <agency/detail/config.hpp>
#include <agency/execution_policy.hpp>
#include <agency/flattened_executor.hpp>
#include <agency/cuda/execution_agent.hpp>
#include <agency/cuda/grid_executor.hpp>
#include <agency/cuda/parallel_executor.hpp>
#include <agency/cuda/concurrent_executor.hpp>
#include <agency/cuda/nested_executor.hpp>
#include <agency/cuda/bulk_invoke.hpp>
#include <agency/detail/tuple.hpp>
#include <type_traits>

namespace agency
{
namespace cuda
{
namespace detail
{

// add basic_execution_policy to allow us to catch its derivations as overloads of bulk_invoke, etc.
template<class ExecutionAgent,
         class BulkExecutor,
         class ExecutionCategory = typename execution_agent_traits<ExecutionAgent>::execution_category,
         class DerivedExecutionPolicy = void>
class basic_execution_policy :
  public agency::detail::basic_execution_policy<
    ExecutionAgent,
    BulkExecutor,
    ExecutionCategory,
    typename std::conditional<
      std::is_void<DerivedExecutionPolicy>::value,
      basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
      DerivedExecutionPolicy
    >::type
>
{
  public:
    // inherit the base class's constructors
    using agency::detail::basic_execution_policy<
      ExecutionAgent,
      BulkExecutor,
      ExecutionCategory,
      typename std::conditional<
        std::is_void<DerivedExecutionPolicy>::value,
        basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
        DerivedExecutionPolicy
      >::type
    >::basic_execution_policy;
}; // end basic_execution_policy

} // end detail

class parallel_execution_policy : public detail::basic_execution_policy<cuda::parallel_agent, cuda::parallel_executor, parallel_execution_tag, parallel_execution_policy>
{
  private:
    using super_t = detail::basic_execution_policy<cuda::parallel_agent, cuda::parallel_executor, parallel_execution_tag, parallel_execution_policy>;

    using par2d_t = detail::basic_execution_policy<cuda::parallel_agent_2d, cuda::parallel_executor, parallel_execution_tag>;

  public:
    using super_t::basic_execution_policy;

    using super_t::operator();

    // XXX consider whether we really want this functionality a member of parallel_execution_policy
    inline par2d_t operator()(agency::size2 shape) const
    {
      par2d_t par2d;

      return par2d(shape);
    }

    // XXX consider whether we really want this functionality a member of parallel_execution_policy
    template<class ExecutionPolicy>
    agency::detail::nested_execution_policy<
      par2d_t,
      agency::detail::decay_t<ExecutionPolicy>
    >
      operator()(agency::size2 domain, ExecutionPolicy&& exec) const
    {
      par2d_t par2d;

      return par2d(domain, std::forward<ExecutionPolicy>(exec));
    }
};

const parallel_execution_policy par{};

class concurrent_execution_policy : public detail::basic_execution_policy<cuda::concurrent_agent, cuda::concurrent_executor, concurrent_execution_tag, concurrent_execution_policy>
{
  private:
    using super_t = detail::basic_execution_policy<cuda::concurrent_agent, cuda::concurrent_executor, concurrent_execution_tag, concurrent_execution_policy>;

    using con2d_t = detail::basic_execution_policy<cuda::concurrent_agent_2d, cuda::concurrent_executor, concurrent_execution_tag>;

  public:
    using super_t::basic_execution_policy;

    using super_t::operator();

    // XXX consider whether we really want this functionality a member of concurrent_execution_policy
    inline con2d_t operator()(agency::size2 shape) const
    {
      con2d_t con2d;

      return con2d(shape);
    }

    // XXX consider whether we really want this functionality a member of concurrent_execution_policy
    template<class ExecutionPolicy>
    agency::detail::nested_execution_policy<
      con2d_t,
      agency::detail::decay_t<ExecutionPolicy>
    >
      operator()(agency::size2 domain, ExecutionPolicy&& exec) const
    {
      con2d_t con2d;

      return con2d(domain, std::forward<ExecutionPolicy>(exec));
    }
};

const concurrent_execution_policy con{};

namespace detail
{

// specialize rebind_executor for cuda's executor types
template<class ExecutionPolicy, class Enable = void>
struct rebind_executor_impl;

template<class ExecutionPolicy>
struct rebind_executor_impl<
  ExecutionPolicy,
  typename std::enable_if<
    std::is_same<
      typename ExecutionPolicy::execution_category,
      parallel_execution_tag
    >::value
  >::type
>
{
  using type = cuda::parallel_execution_policy;
};

// specialize rebind_executor for cuda::concurrent_executor
template<class ExecutionPolicy>
struct rebind_executor_impl<
  ExecutionPolicy,
  typename std::enable_if<
    std::is_same<
      typename ExecutionPolicy::execution_category,
      concurrent_execution_tag
    >::value
  >::type
>
{
  using type = cuda::concurrent_execution_policy;
};

} // end detail
} // end cuda

// specialize is_execution_policy
template<class ExecutionAgent,
         class BulkExecutor,
         class ExecutionCategory,
         class DerivedExecutionPolicy>
struct is_execution_policy<cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>> : std::true_type {};

template<>
struct is_execution_policy<cuda::parallel_execution_policy> : std::true_type {};

template<>
struct is_execution_policy<cuda::concurrent_execution_policy> : std::true_type {};

template<class ExecutionPolicy>
struct rebind_executor<ExecutionPolicy, cuda::grid_executor>
{
  using type = typename cuda::detail::rebind_executor_impl<ExecutionPolicy>::type;
};

template<class ExecutionPolicy>
struct rebind_executor<ExecutionPolicy, cuda::concurrent_executor>
{
  using type = typename cuda::detail::rebind_executor_impl<ExecutionPolicy>::type;
};

// the following functions are overloads of agency::bulk_invoke & agency::bulk_async
// for cuda execution policies. they forward along the to cuda::bulk_invoke & cuda::bulk_async
// we introduce these overloads to work around the use of lambdas in agency::bulk_invoke & agency::bulk_async
// which are obstacles to __global__ function template instantiation for nvcc

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
auto bulk_invoke(cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>&& exec,
                 Function&& f,
                 Args&&... args)
  -> decltype(
       cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
auto bulk_invoke(cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>& exec,
                 Function&& f,
                 Args&&... args)
  -> decltype(
       cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
auto bulk_invoke(const cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>& exec,
                 Function&& f,
                 Args&&... args)
  -> decltype(
       cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_invoke(cuda::parallel_execution_policy&& exec,
                 Function&& f,
                 Args&&... args)
  -> decltype(
       cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_invoke(cuda::parallel_execution_policy& exec,
                 Function&& f,
                 Args&&... args)
  -> decltype(
       cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_invoke(const cuda::parallel_execution_policy& exec,
                 Function&& f,
                 Args&&... args)
  -> decltype(
       cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_invoke(cuda::concurrent_execution_policy&& exec,
                 Function&& f,
                 Args&&... args)
  -> decltype(
       cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_invoke(cuda::concurrent_execution_policy& exec,
                 Function&& f,
                 Args&&... args)
  -> decltype(
       cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_invoke(const cuda::concurrent_execution_policy& exec,
                 Function&& f,
                 Args&&... args)
  -> decltype(
       cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_invoke(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
auto bulk_async(cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>&& exec, Function&& f, Args&&... args)
  -> decltype(
       cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
auto bulk_async(cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>& exec, Function&& f, Args&&... args)
  -> decltype(
       cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class ExecutionAgent, class BulkExecutor, class ExecutionCategory, class DerivedExecutionPolicy, class Function, class... Args>
auto bulk_async(const cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>& exec, Function&& f, Args&&... args)
  -> decltype(
       cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_async(cuda::parallel_execution_policy&& exec, Function&& f, Args&&... args)
  -> decltype(
       cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_async(cuda::parallel_execution_policy& exec, Function&& f, Args&&... args)
  -> decltype(
       cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_async(const cuda::parallel_execution_policy& exec, Function&& f, Args&&... args)
  -> decltype(
       cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_async(cuda::concurrent_execution_policy&& exec, Function&& f, Args&&... args)
  -> decltype(
       cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_async(cuda::concurrent_execution_policy& exec, Function&& f, Args&&... args)
  -> decltype(
       cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

template<class Function, class... Args>
auto bulk_async(const cuda::concurrent_execution_policy& exec, Function&& f, Args&&... args)
  -> decltype(
       cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...)
     )
{
  return cuda::bulk_async(exec, std::forward<Function>(f), std::forward<Args>(args)...);
}

} // end agency

<|endoftext|>