text:
/*
 *
 * Copyright (C) 2019 Intel Corporation
 *
 * SPDX-License-Identifier: MIT
 *
 */

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <chrono>
#include <thread>

#include "gtest/gtest.h"

#include "utils/utils.hpp"
#include "test_harness/test_harness.hpp"
#include "logging/logging.hpp"

namespace lzt = level_zero_tests;

#include <level_zero/ze_api.h>

namespace {

class zeDriverAllocDeviceMemTests
    : public ::testing::Test,
      public ::testing::WithParamInterface<
          std::tuple<ze_device_mem_alloc_flag_t, size_t, size_t>> {
protected:
  void SetUp() override {
    const ze_device_mem_alloc_flag_t flags = std::get<0>(GetParam());
    size_ = std::get<1>(GetParam());
    const size_t alignment = std::get<2>(GetParam());
    memory_ = lzt::allocate_device_memory(size_, alignment, flags);
  }
  void TearDown() override { lzt::free_memory(memory_); }
  size_t size_;
  void *memory_ = nullptr;
};

class zeDriverAllocDeviceMemParamsTests : public zeDriverAllocDeviceMemTests {};

TEST_P(
    zeDriverAllocDeviceMemParamsTests,
    GivenAllocationFlagsAndSizeAndAlignmentWhenAllocatingDeviceMemoryThenNotNullPointerIsReturned) {
}

INSTANTIATE_TEST_CASE_P(
    zeDriverAllocDeviceMemTestVaryFlagsAndSizeAndAlignment,
    zeDriverAllocDeviceMemParamsTests,
    ::testing::Combine(
        ::testing::Values(0, ZE_DEVICE_MEM_ALLOC_FLAG_BIAS_CACHED,
                          ZE_DEVICE_MEM_ALLOC_FLAG_BIAS_UNCACHED),
        lzt::memory_allocation_sizes, lzt::memory_allocation_alignments));

class zeMemGetAllocPropertiesTests : public zeDriverAllocDeviceMemTests {};

TEST_P(
    zeMemGetAllocPropertiesTests,
    GivenValidDeviceMemoryPointerWhenGettingPropertiesThenVersionAndTypeReturned) {
  ze_memory_allocation_properties_t memory_properties;
  ze_context_handle_t context = lzt::get_default_context();
  ze_device_handle_t device = lzt::zeDevice::get_instance()->get_device();
  ze_device_handle_t device_test = device;

  memory_properties.pNext = nullptr;
  memory_properties.stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES;
  lzt::get_mem_alloc_properties(context, memory_, &memory_properties,
                                &device_test);
  EXPECT_EQ(ZE_MEMORY_TYPE_DEVICE, memory_properties.type);
  EXPECT_EQ(device, device_test);

  if (size_ > 0) {
    uint8_t *char_mem = static_cast<uint8_t *>(memory_);

    memory_properties.pNext = nullptr;
    memory_properties.stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES;
    device_test = device;
    lzt::get_mem_alloc_properties(context,
                                  static_cast<void *>(char_mem + size_ - 1),
                                  &memory_properties, &device_test);
    EXPECT_EQ(ZE_MEMORY_TYPE_DEVICE, memory_properties.type);
    EXPECT_EQ(device, device_test);
  }
}
TEST_P(
    zeMemGetAllocPropertiesTests,
    GivenPointerToDeviceHandleIsSetToNullWhenGettingMemoryPropertiesThenSuccessIsReturned) {

  auto context = lzt::get_default_context();
  ze_memory_allocation_properties_t memory_properties;

  memory_properties.pNext = nullptr;
  memory_properties.stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES;
  lzt::get_mem_alloc_properties(context, memory_, &memory_properties);
}

INSTANTIATE_TEST_CASE_P(zeMemGetAllocPropertiesTestVaryFlagsAndSizeAndAlignment,
                        zeMemGetAllocPropertiesTests,
                        ::testing::Combine(::testing::Values(0),
                                           lzt::memory_allocation_sizes,
                                           lzt::memory_allocation_alignments));

class zeDriverMemGetAddressRangeTests : public zeDriverAllocDeviceMemTests {};

TEST_P(
    zeDriverMemGetAddressRangeTests,
    GivenValidDeviceMemoryPointerWhenGettingAddressRangeThenBaseAddressAndSizeReturned) {

  void *pBase = nullptr;
  EXPECT_EQ(ZE_RESULT_SUCCESS, zeMemGetAddressRange(lzt::get_default_context(),
                                                    memory_, &pBase, NULL));
  EXPECT_EQ(pBase, memory_);
  size_t addr_range_size = 0;
  EXPECT_EQ(ZE_RESULT_SUCCESS,
            zeMemGetAddressRange(lzt::get_default_context(), memory_, NULL,
                                 &addr_range_size));

  // Get device mem size rounds size up to nearest page size
  EXPECT_GE(addr_range_size, size_);
  pBase = nullptr;
  addr_range_size = 0;
  if (size_ > 0) {
    uint8_t *char_mem = static_cast<uint8_t *>(memory_);
    EXPECT_EQ(ZE_RESULT_SUCCESS,
              zeMemGetAddressRange(lzt::get_default_context(),
                                   static_cast<void *>(char_mem + size_ - 1),
                                   &pBase, &addr_range_size));
  } else {
    EXPECT_EQ(ZE_RESULT_SUCCESS,
              zeMemGetAddressRange(lzt::get_default_context(), memory_, &pBase,
                                   &addr_range_size));
  }
  EXPECT_EQ(pBase, memory_);
  // Get device mem size rounds size up to nearest page size
  EXPECT_GE(addr_range_size, size_);
}

INSTANTIATE_TEST_CASE_P(
    zeDriverMemGetAddressRangeTestVaryFlagsAndSizeAndAlignment,
    zeDriverMemGetAddressRangeTests,
    ::testing::Combine(::testing::Values(0), lzt::memory_allocation_sizes,
                       lzt::memory_allocation_alignments));

class zeDriverMemFreeTests : public ::testing::Test {};

TEST_F(
    zeDriverMemFreeTests,
    GivenValidDeviceMemAllocationWhenFreeingDeviceMemoryThenSuccessIsReturned) {
  void *memory = lzt::allocate_device_memory(1);
  lzt::free_memory(memory);
}

class zeDriverAllocSharedMemTests
    : public ::testing::Test,
      public ::testing::WithParamInterface<
          std::tuple<ze_device_mem_alloc_flag_t, ze_host_mem_alloc_flag_t,
                     size_t, size_t>> {};
TEST_P(
    zeDriverAllocSharedMemTests,
    GivenAllocationFlagsSizeAndAlignmentWhenAllocatingSharedMemoryThenNotNullPointerIsReturned) {
  const ze_device_mem_alloc_flag_t dev_flags = std::get<0>(GetParam());
  const ze_host_mem_alloc_flag_t host_flags = std::get<1>(GetParam());
  const size_t size = std::get<2>(GetParam());
  const size_t alignment = std::get<3>(GetParam());

  void *memory = nullptr;
  auto driver = lzt::get_default_driver();
  auto device = lzt::get_default_device(driver);
  auto context = lzt::create_context();

  const int pattern = 0x55;
  // Access from host first
  memory = lzt::allocate_shared_memory(size, alignment, dev_flags, host_flags,
                                       device, context);
  EXPECT_NE(nullptr, memory);
  memset(memory, pattern, size);
  for (size_t i = 0; i++; i < size) {
    ASSERT_EQ(static_cast<uint8_t *>(memory)[i], pattern);
  }
  lzt::free_memory(context, memory);

  // Access from device first
  memory = lzt::allocate_shared_memory(size, alignment, dev_flags, host_flags,
                                       device, context);
  EXPECT_NE(nullptr, memory);
  const int pattern2 = 0x55;

  auto cmdlist = lzt::create_immediate_command_list(
      context, device, 0, ZE_COMMAND_QUEUE_MODE_SYNCHRONOUS,
      ZE_COMMAND_QUEUE_PRIORITY_NORMAL, 0);
  lzt::append_memory_fill(cmdlist, memory, &pattern2, 1, size, nullptr);

  for (size_t i = 0; i++; i < size) {
    ASSERT_EQ(static_cast<uint8_t *>(memory)[i], pattern2);
  }

  lzt::free_memory(context, memory);
  lzt::destroy_context(context);
}

INSTANTIATE_TEST_CASE_P(
    TestSharedMemFlagPermutations, zeDriverAllocSharedMemTests,
    ::testing::Combine(
        ::testing::Values(0, ZE_DEVICE_MEM_ALLOC_FLAG_BIAS_CACHED,
                          ZE_DEVICE_MEM_ALLOC_FLAG_BIAS_UNCACHED,
                          ZE_DEVICE_MEM_ALLOC_FLAG_BIAS_INITIAL_PLACEMENT),
        ::testing::Values(0, ZE_HOST_MEM_ALLOC_FLAG_BIAS_CACHED,
                          ZE_HOST_MEM_ALLOC_FLAG_BIAS_UNCACHED,
                          ZE_HOST_MEM_ALLOC_FLAG_BIAS_WRITE_COMBINED,
                          ZE_HOST_MEM_ALLOC_FLAG_BIAS_INITIAL_PLACEMENT),
        lzt::memory_allocation_sizes, lzt::memory_allocation_alignments));

class zeSharedMemGetPropertiesTests
    : public ::testing::Test,
      public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};

TEST_P(zeSharedMemGetPropertiesTests,
       GivenSharedAllocationWhenGettingMemPropertiesThenSuccessIsReturned) {
  const size_t size = std::get<0>(GetParam());
  const size_t alignment = std::get<1>(GetParam());
  ze_context_handle_t context = lzt::get_default_context();
  ze_device_handle_t device = lzt::zeDevice::get_instance()->get_device();
  ze_device_handle_t device_test = device;
  ze_memory_allocation_properties_t mem_properties;
  mem_properties.stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES;
  void *memory = lzt::allocate_shared_memory(size, alignment, 0, 0, device);
  lzt::get_mem_alloc_properties(context, memory, &mem_properties, &device_test);
  EXPECT_EQ(device_test, device);
  lzt::free_memory(memory);
}

INSTANTIATE_TEST_CASE_P(TestSharedMemGetPropertiesPermutations,
                        zeSharedMemGetPropertiesTests,
                        ::testing::Combine(lzt::memory_allocation_sizes,
                                           lzt::memory_allocation_alignments));

class zeSharedMemGetAddressRangeTests : public ::testing::Test {};

TEST_F(zeSharedMemGetAddressRangeTests,
       GivenSharedAllocationWhenGettingAddressRangeThenCorrectSizeIsReturned) {
  const size_t size = 1;
  const size_t alignment = 1;

  void *memory = lzt::allocate_shared_memory(size, alignment);
  size_t size_out;

  EXPECT_EQ(ZE_RESULT_SUCCESS, zeMemGetAddressRange(lzt::get_default_context(),
                                                    memory, NULL, &size_out));
  EXPECT_GE(size_out, size);
  lzt::free_memory(memory);
}

TEST_F(zeSharedMemGetAddressRangeTests,
       GivenSharedAllocationWhenGettingAddressRangeThenCorrectBaseIsReturned) {
  const size_t size = 1;
  const size_t alignment = 1;

  void *memory = lzt::allocate_shared_memory(size, alignment);
  void *base = nullptr;

  EXPECT_EQ(ZE_RESULT_SUCCESS, zeMemGetAddressRange(lzt::get_default_context(),
                                                    memory, &base, NULL));
  EXPECT_EQ(base, memory);
  lzt::free_memory(memory);
}

class zeSharedMemGetAddressRangeParameterizedTests
    : public ::testing::Test,
      public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};

TEST_P(
    zeSharedMemGetAddressRangeParameterizedTests,
    GivenSharedAllocationWhenGettingAddressRangeThenCorrectSizeAndBaseIsReturned) {
  const size_t size = std::get<0>(GetParam());
  const size_t alignment = std::get<1>(GetParam());

  void *memory = lzt::allocate_shared_memory(size, alignment);
  void *base = nullptr;
  size_t size_out;

  // Test getting address info from begining of memory range
  uint8_t *mem_target = static_cast<uint8_t *>(memory);
  EXPECT_EQ(ZE_RESULT_SUCCESS, zeMemGetAddressRange(lzt::get_default_context(),
                                                    memory, &base, &size_out));
  EXPECT_GE(size_out, size);
  EXPECT_EQ(base, memory);

  if (size > 1) {
    // Test getting address info from middle of memory range
    mem_target = static_cast<uint8_t *>(memory) + (size - 1) / 2;
    EXPECT_EQ(ZE_RESULT_SUCCESS,
              zeMemGetAddressRange(lzt::get_default_context(), mem_target,
                                   &base, &size_out));
    EXPECT_GE(size_out, size);
    EXPECT_EQ(memory, base);

    // Test getting address info from end of memory range
    mem_target = static_cast<uint8_t *>(memory) + (size - 1);
    EXPECT_EQ(ZE_RESULT_SUCCESS,
              zeMemGetAddressRange(lzt::get_default_context(), mem_target,
                                   &base, &size_out));
    EXPECT_GE(size_out, size);
    EXPECT_EQ(memory, base);
  }
  lzt::free_memory(memory);
}

INSTANTIATE_TEST_CASE_P(TestSharedMemGetAddressRangePermutations,
                        zeSharedMemGetAddressRangeParameterizedTests,
                        ::testing::Combine(lzt::memory_allocation_sizes,
                                           lzt::memory_allocation_alignments));
class zeDriverAllocHostMemTests
    : public ::testing::Test,
      public ::testing::WithParamInterface<
          std::tuple<ze_host_mem_alloc_flag_t, size_t, size_t>> {};
TEST_P(
    zeDriverAllocHostMemTests,
    GivenFlagsSizeAndAlignmentWhenAllocatingHostMemoryThenNotNullPointerIsReturned) {

  const ze_host_mem_alloc_flag_t flags = std::get<0>(GetParam());

  const size_t size = std::get<1>(GetParam());
  const size_t alignment = std::get<2>(GetParam());

  void *memory = nullptr;
  ze_host_mem_alloc_desc_t host_desc = {};
  host_desc.stype = ZE_STRUCTURE_TYPE_HOST_MEM_ALLOC_DESC;

  host_desc.pNext = nullptr;
  host_desc.flags = flags;
  EXPECT_EQ(ZE_RESULT_SUCCESS,
            zeMemAllocHost(lzt::get_default_context(), &host_desc, size,
                           alignment, &memory));

  EXPECT_NE(nullptr, memory);

  EXPECT_EQ(ZE_RESULT_SUCCESS, zeMemFree(lzt::get_default_context(), memory));
}

INSTANTIATE_TEST_CASE_P(
    TestHostMemParameterCombinations, zeDriverAllocHostMemTests,
    ::testing::Combine(
        ::testing::Values(0, ZE_HOST_MEM_ALLOC_FLAG_BIAS_CACHED,
                          ZE_HOST_MEM_ALLOC_FLAG_BIAS_UNCACHED,
                          ZE_HOST_MEM_ALLOC_FLAG_BIAS_WRITE_COMBINED),
        lzt::memory_allocation_sizes, lzt::memory_allocation_alignments));

class zeHostMemPropertiesTests
    : public ::testing::Test,
      public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};

TEST_P(
    zeHostMemPropertiesTests,
    GivenValidMemoryPointerWhenQueryingAttributesOnHostMemoryAllocationThenSuccessIsReturned) {

  const size_t size = std::get<0>(GetParam());
  const size_t alignment = std::get<1>(GetParam());
  void *memory = lzt::allocate_host_memory(size, alignment);
  ze_memory_allocation_properties_t mem_properties = {};
  auto context = lzt::get_default_context();

  mem_properties.stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES;
  mem_properties.pNext = nullptr;
  lzt::get_mem_alloc_properties(context, memory, &mem_properties, nullptr);
  EXPECT_EQ(ZE_MEMORY_TYPE_HOST, mem_properties.type);

  lzt::free_memory(memory);
}

INSTANTIATE_TEST_CASE_P(TestHostMemGetPropertiesParameterCombinations,
                        zeHostMemPropertiesTests,
                        ::testing::Combine(lzt::memory_allocation_sizes,
                                           lzt::memory_allocation_alignments));

class zeHostMemGetAddressRangeTests : public ::testing::Test {};

TEST_F(
    zeHostMemGetAddressRangeTests,
    GivenBasePointerWhenQueryingBaseAddressofHostMemoryAllocationThenSuccessIsReturned) {

  const size_t size = 1;
  const size_t alignment = 1;

  void *base = nullptr;

  void *memory = lzt::allocate_host_memory(size, alignment);

  EXPECT_EQ(ZE_RESULT_SUCCESS, zeMemGetAddressRange(lzt::get_default_context(),
                                                    memory, &base, nullptr));
  EXPECT_EQ(memory, base);

  lzt::free_memory(memory);
}

class zeHostMemGetAddressRangeSizeTests
    : public ::testing::Test,
      public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};

TEST_P(
    zeHostMemGetAddressRangeSizeTests,
    GivenSizePointerWhenQueryingSizeOfHostMemoryAllocationThenSuccessIsReturned) {

  const size_t size = std::get<0>(GetParam());
  const size_t alignment = std::get<1>(GetParam());

  size_t size_out;
  void *memory = lzt::allocate_host_memory(size, alignment);

  EXPECT_EQ(ZE_RESULT_SUCCESS,
            zeMemGetAddressRange(lzt::get_default_context(), memory, nullptr,
                                 &size_out));
  EXPECT_GE(size_out, size);

  lzt::free_memory(memory);
}

INSTANTIATE_TEST_CASE_P(TestHostMemGetAddressRangeSizeTests,
                        zeHostMemGetAddressRangeSizeTests,
                        ::testing::Combine(lzt::memory_allocation_sizes,
                                           lzt::memory_allocation_alignments));

class zeHostMemGetAddressRangeParameterTests
    : public ::testing::Test,
      public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};

TEST_P(
    zeHostMemGetAddressRangeParameterTests,
    GivenBasePointerAndSizeWhenQueryingBaseAddressOfHostMemoryAllocationThenSuccessIsReturned) {

  const size_t size = std::get<0>(GetParam());
  const size_t alignment = std::get<1>(GetParam());

  void *memory = lzt::allocate_host_memory(size, alignment);
  void *base = nullptr;
  size_t size_out;

  EXPECT_EQ(ZE_RESULT_SUCCESS, zeMemGetAddressRange(lzt::get_default_context(),
                                                    memory, &base, &size_out));
  EXPECT_EQ(memory, base);

  if (size > 1) {
    uint8_t *mem_target = static_cast<uint8_t *>(memory) + (size - 1) / 2;
    EXPECT_EQ(ZE_RESULT_SUCCESS,
              zeMemGetAddressRange(lzt::get_default_context(), mem_target,
                                   &base, &size_out));
    EXPECT_EQ(memory, base);
    EXPECT_GE(size_out, size);

    mem_target = static_cast<uint8_t *>(memory) + (size - 1);
    EXPECT_EQ(ZE_RESULT_SUCCESS,
              zeMemGetAddressRange(lzt::get_default_context(), mem_target,
                                   &base, &size_out));
    EXPECT_EQ(memory, base);
    EXPECT_GE(size_out, size);
  }

  lzt::free_memory(memory);
}

INSTANTIATE_TEST_CASE_P(zeHostMemGetAddressRangeParameterizedTests,
                        zeHostMemGetAddressRangeParameterTests,
                        ::testing::Combine(lzt::memory_allocation_sizes,
                                           lzt::memory_allocation_alignments));

class zeHostSystemMemoryHostTests : public ::testing::Test {
protected:
  zeHostSystemMemoryHostTests() { memory_ = new uint8_t[size_]; }
  ~zeHostSystemMemoryHostTests() { delete[] memory_; }
  const size_t size_ = 4 * 1024;
  uint8_t *memory_ = nullptr;
};

TEST_F(
    zeHostSystemMemoryHostTests,
    GivenHostSystemAllocationWhenWritingAndReadingOnHostThenCorrectDataIsRead) {
  lzt::write_data_pattern(memory_, size_, 1);
  lzt::validate_data_pattern(memory_, size_, 1);
}

class zeHostSystemMemoryDeviceTests : public ::testing::Test {
protected:
  zeHostSystemMemoryDeviceTests() { memory_ = new uint8_t[size_]; }
  ~zeHostSystemMemoryDeviceTests() { delete[] memory_; }
  const size_t size_ = 4 * 1024;
  uint8_t *memory_ = nullptr;
  lzt::zeCommandList cmdlist_;
  lzt::zeCommandQueue cmdqueue_;
};

TEST_F(
    zeHostSystemMemoryDeviceTests,
    GivenHostSystemAllocationWhenAccessingMemoryOnDeviceThenCorrectDataIsRead) {
  lzt::write_data_pattern(memory_, size_, 1);
  std::string module_name = "unified_mem_test.spv";
  ze_module_handle_t module = lzt::create_module(
      lzt::zeDevice::get_instance()->get_device(), module_name);
  std::string func_name = "unified_mem_test";

  lzt::FunctionArg arg;
  std::vector<lzt::FunctionArg> args;

  arg.arg_size = sizeof(uint8_t *);
  arg.arg_value = &memory_;
  args.push_back(arg);
  arg.arg_size = sizeof(int);
  int size = static_cast<int>(size_);
  arg.arg_value = &size;
  args.push_back(arg);
  lzt::create_and_execute_function(lzt::zeDevice::get_instance()->get_device(),
                                   module, func_name, 1, args);
  lzt::validate_data_pattern(memory_, size_, -1);
  lzt::destroy_module(module);
}

TEST_F(
    zeHostSystemMemoryDeviceTests,
    GivenHostSystemAllocationWhenCopyingMemoryOnDeviceThenMemoryCopiedCorrectly) {
  lzt::write_data_pattern(memory_, size_, 1);
  uint8_t *other_system_memory = new uint8_t[size_];

  lzt::append_memory_copy(cmdlist_.command_list_, other_system_memory, memory_,
                          size_, nullptr);
  lzt::append_barrier(cmdlist_.command_list_, nullptr, 0, nullptr);
  lzt::close_command_list(cmdlist_.command_list_);
  lzt::execute_command_lists(cmdqueue_.command_queue_, 1,
                             &cmdlist_.command_list_, nullptr);
  lzt::synchronize(cmdqueue_.command_queue_, UINT64_MAX);
  lzt::validate_data_pattern(other_system_memory, size_, 1);
  delete[] other_system_memory;
}

TEST_F(zeHostSystemMemoryDeviceTests,
       GivenHostSystemMemoryWhenSettingMemoryOnDeviceThenMemorySetCorrectly) {

  const uint8_t value = 0x55;
  lzt::write_data_pattern(memory_, size_, 1);
  lzt::append_memory_set(cmdlist_.command_list_, memory_, &value, size_);
  lzt::append_barrier(cmdlist_.command_list_, nullptr, 0, nullptr);
  lzt::close_command_list(cmdlist_.command_list_);
  lzt::execute_command_lists(cmdqueue_.command_queue_, 1,
                             &cmdlist_.command_list_, nullptr);
  lzt::synchronize(cmdqueue_.command_queue_, UINT64_MAX);
  for (unsigned int ui = 0; ui < size_; ui++)
    EXPECT_EQ(value, static_cast<uint8_t *>(memory_)[ui]);
}

} // namespace

max_stars_repo_name: TApplencourt/level-zero-tests

max_issues_repo_name: TApplencourt/level-zero-tests

max_forks_repo_name: TApplencourt/level-zero-tests


text:
#pragma once

#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>

#define ELLE_ENUM(Name, ...)                                            \
  enum class Name                                                       \
  {                                                                     \
    BOOST_PP_SEQ_FOR_EACH(                                              \
      ELLE_ENUM_VALUE, , BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))         \
  };                                                                    \
  ELLE_ENUM_IMPL_(                                                      \
    Name,                                                               \
    BOOST_PP_SEQ_FOR_EACH(                                              \
      ELLE_ENUM_SEQ_GET_NAME, , BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))  \
    );                                                                  \

#define ELLE_ENUM_SEQ_GET_NAME(R, _, Elem)      \
  (BOOST_PP_TUPLE_ELEM(2, 0, Elem))

#define ELLE_ENUM_GET_NAME(Elem)                \
  BOOST_PP_TUPLE_ELEM(2, 0, Elem)

#define ELLE_ENUM_GET_VALUE(Elem)               \
  BOOST_PP_TUPLE_ELEM(2, 1, Elem)

#define ELLE_ENUM_IMPL(Name, ...)                                       \
  ELLE_ENUM_IMPL_(Name, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__));         \

#define ELLE_ENUM_IMPL_(Name, Elems)                                    \
  inline                                                                \
  std::ostream&                                                         \
  operator <<(std::ostream& s, Name v)                                  \
  {                                                                     \
    switch (v)                                                          \
    {                                                                   \
      BOOST_PP_SEQ_FOR_EACH(                                            \
        ELLE_ENUM_PRINT, Name, Elems)                                   \
      default:                                                          \
        /* Don't make that any other valid name, hence the <> */        \
        s << "<unknown>";                                               \
        break;                                                          \
    }                                                                   \
    return s;                                                           \
  }                                                                     \

#define ELLE_ENUM_VALUE(R, Name, Elem)                                  \
  ELLE_ENUM_GET_NAME(Elem) = ELLE_ENUM_GET_VALUE(Elem),                 \

#define ELLE_ENUM_PRINT(R, Name, Elem)                                  \
  case Name::Elem:                                                      \
    s << BOOST_PP_STRINGIZE(Elem);                                      \
    break;

ext: hh

max_stars_repo_name: infinit/elle

max_issues_repo_name: mefyl/elle

max_forks_repo_name: mefyl/elle


text:
/**
 * @file transpsemilagr_test.cc
 * @brief NPDE homework TranspSemiLagr test file
 * @author Philippe Peter
 * @date November 2020
 * @copyright Developed at SAM, ETH Zurich
 */
#include "../transpsemilagr.h"

#include <gtest/gtest.h>
#include <lf/mesh/test_utils/test_meshes.h>
#include <lf/mesh/utils/utils.h>
#include <lf/uscalfe/uscalfe.h>

#include <Eigen/Core>
#include <cmath>
#include <memory>

namespace TranspSemiLagr::test {

// verifies that the vector u of nodal values satisfies zero boundary conditions
void verify_zero_bc(
    std::shared_ptr<const lf::uscalfe::UniformScalarFESpace<double>> fe_space,
    const Eigen::VectorXd& u) {
  auto mesh_p = fe_space->Mesh();
  const auto& dof_h = fe_space->LocGlobMap();
  auto boundary_nodes = lf::mesh::utils::flagEntitiesOnBoundary(mesh_p, 2);

  for (int i = 0; i < u.size(); ++i) {
    if (boundary_nodes(dof_h.Entity(i))) {
      EXPECT_NEAR(u[i], 0.0, 1.0E-6);
    }
  }
}

// The first set of test cases verifies, that all methods produce solutions that
// satisfy the zero dirichlet boundary conditions.

TEST(ReactionStep, boundary_conditions) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u_function));
  auto c_function = [](Eigen::VectorXd x) { return x(0) + x(1); };

  verify_zero_bc(fe_space, u0_vector);
  Eigen::VectorXd u_new = reaction_step(fe_space, u0_vector, c_function, 1.0);
  verify_zero_bc(fe_space, u_new);
}

TEST(SemiLagrStep, boundary_conditions) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u_function));

  auto v = [](Eigen::Vector2d x) {
    return (Eigen::Vector2d() << -x(1) + 3.0 * x(0) * x(0), x(0)).finished();
  };

  verify_zero_bc(fe_space, u0_vector);
  Eigen::VectorXd u_new = semiLagr_step(fe_space, u0_vector, v, 1.0);
  verify_zero_bc(fe_space, u_new);
}

TEST(solverot, boundary_conditions) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);
  auto u_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u_function));

  Eigen::VectorXd u_new = solverot(fe_space, u0_vector, 10, 1.0);
  verify_zero_bc(fe_space, u_new);
}

TEST(solvetrp, boundary_conditions) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);
  auto u_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };

  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u_function));
  Eigen::VectorXd u_new = solvetrp(fe_space, u0_vector, 10, 1.0);
  verify_zero_bc(fe_space, u_new);
}

// The following two test cases test the reaction_step function
// based on an exact solution u(x,t). Even though this exact solution
// is a polynomial of degree four in x, it is still the case that
// the approximate solution to the evolution problem is a good approximation
// of the nodal projection of the exact solution at time T. Since
// the reaction_step relies on a lumped mass matrix, the system of
// equations decouble and for each component ODE the RK-scheme is applied.

// u(x,t) = x0*(1-x0)*x1*(1-x1)*exp(2t)
TEST(ReactionStep, exact_solution_constant_c) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  // solution function at initial time t=0
  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };

  // solution function at final time t=1
  auto u1_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0)) * std::exp(2 * 1.0);
  };

  // c function in the ODE:
  auto c_function = [](Eigen::VectorXd /*x*/) { return 2.0; };

  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));
  Eigen::VectorXd u1_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u1_function));

  // apply 100 reaction steps with time step 0.01
  for (int i = 0; i < 100; ++i) {
    u0_vector = reaction_step(fe_space, u0_vector, c_function, 0.01);
  }
  EXPECT_NEAR((u0_vector - u1_vector).norm(), 0.0, 1.0E-3);
}

// based on exact solution u(x,t) = x0*(1-x0)*x1*(1-x1)*exp(2t*x0 + t*x1))
TEST(ReactionStep, exact_solution_linear_c) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  // solution function at initial time t=0
  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };

  // solution function at final time t=1
  auto u1_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0)) * std::exp(2 * x(0) + x(1));
  };

  // c function in the ODE:
  auto c_function = [](Eigen::VectorXd x) { return 2.0 * x(0) + x(1); };

  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));
  Eigen::VectorXd u1_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u1_function));

  // apply 100 reaction steps with time step 0.01
  for (int i = 0; i < 100; ++i) {
    u0_vector = reaction_step(fe_space, u0_vector, c_function, 0.01);
  }
  EXPECT_NEAR((u0_vector - u1_vector).norm(), 0.0, 1.0E-3);
}

// The following few testcases verify that solverot (and solvetrp) satisfy the
// following: If solverot simulates N timesteps of the PDE on [0,T] with initial
// condition u_0 the result should be the same as simulating N/2 timesteps on
// [0,T/2] and then another N/2 timestpes on [0,T/2] with the updated initial
// conditin, since all coefficients are indepentent of time.
TEST(solverot, consistency_1) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd sol_1 = solverot(fe_space, u0_vector, 2, 1.0);
  Eigen::VectorXd sol_2 =
      solverot(fe_space, solverot(fe_space, u0_vector, 1, 0.5), 1, 0.5);

  EXPECT_NEAR((sol_1 - sol_2).norm(), 0.0, 1.0E-4);
}

TEST(solverot, consistency_2) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd sol_1 = solverot(fe_space, u0_vector, 10, 1.0);
  Eigen::VectorXd sol_2 =
      solverot(fe_space, solverot(fe_space, u0_vector, 5, 0.5), 5, 0.5);

  EXPECT_NEAR((sol_1 - sol_2).norm(), 0.0, 1.0E-4);
}

TEST(solverot, consistency_3) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd sol_1 = solverot(fe_space, u0_vector, 10, 1.0);
  Eigen::VectorXd sol_2 =
      solverot(fe_space, solverot(fe_space, u0_vector, 1, 0.1), 9, 0.9);

  EXPECT_NEAR((sol_1 - sol_2).norm(), 0.0, 1.0E-4);
}

TEST(solvetrp, consistency_1) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd sol_1 = solvetrp(fe_space, u0_vector, 2, 1.0);
  Eigen::VectorXd sol_2 =
      solvetrp(fe_space, solvetrp(fe_space, u0_vector, 1, 0.5), 1, 0.5);

  EXPECT_NEAR((sol_1 - sol_2).norm(), 0.0, 1.0E-4);
}

TEST(solvetrp, consistency_2) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd sol_1 = solvetrp(fe_space, u0_vector, 10, 1.0);
  Eigen::VectorXd sol_2 =
      solvetrp(fe_space, solvetrp(fe_space, u0_vector, 5, 0.5), 5, 0.5);

  EXPECT_NEAR((sol_1 - sol_2).norm(), 0.0, 1.0E-4);
}

TEST(solvetrp, consistency_3) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd sol_1 = solvetrp(fe_space, u0_vector, 10, 1.0);
  Eigen::VectorXd sol_2 =
      solvetrp(fe_space, solvetrp(fe_space, u0_vector, 1, 0.1), 9, 0.9);

  EXPECT_NEAR((sol_1 - sol_2).norm(), 0.0, 1.0E-4);
}

// The final set of test cases checks the output of solverot and solvetrp
// against
// a numerical refernce solution.

TEST(solverot, reference_1) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd u_ref(u0_vector.size());
  u_ref << 0, 0, 0, 0, 0, 0.0159701, 0.0150475, 0, 0, 0.0171946, 0.0170436, 0,
      0, 0, 0, 0;
  Eigen::VectorXd u = solverot(fe_space, u0_vector, 1, 0.1);

  EXPECT_NEAR((u - u_ref).norm(), 0.0, 1.0E-5);
}

TEST(solverot, reference_2) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd u_ref(u0_vector.size());
  u_ref << 0, 0, 0, 0, 0, 0.00860437, 0.00827551, 0, 0, 0.00910899, 0.00901993,
      0, 0, 0, 0, 0;

  Eigen::VectorXd u = solverot(fe_space, u0_vector, 10, 0.1);

  EXPECT_NEAR((u - u_ref).norm(), 0.0, 1.0E-5);
}

TEST(solvetrp, reference_1) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd u_ref(u0_vector.size());
  u_ref << 0, 0, 0, 0, 0, 0.00993255, 0.00841276, 0, 0, 0.0105583, 0.00937419,
      0, 0, 0, 0, 0;
  Eigen::VectorXd u = solvetrp(fe_space, u0_vector, 1, 0.1);

  EXPECT_NEAR((u - u_ref).norm(), 0.0, 1.0E-5);
}

TEST(solvetrp, reference_2) {
  auto mesh_p = lf::mesh::test_utils::GenerateHybrid2DTestMesh(4, 1.0);
  auto fe_space =
      std::make_shared<const lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);

  auto u0_function = [](Eigen::VectorXd x) {
    return x(1) * x(0) * (1 - x(1)) * (1 - x(0));
  };
  Eigen::VectorXd u0_vector = lf::fe::NodalProjection(
      *fe_space, lf::mesh::utils::MeshFunctionGlobal(u0_function));

  Eigen::VectorXd u_ref(u0_vector.size());
  u_ref << 0, 0, 0, 0, 0, 0.00670092, 0.00583407, 0, 0, 0.00707033, 0.00636342,
      0, 0, 0, 0, 0;
  Eigen::VectorXd u = solvetrp(fe_space, u0_vector, 10, 0.1);
  EXPECT_NEAR((u - u_ref).norm(), 0.0, 1.0E-5);
}

}  // namespace TranspSemiLagr::test

ext: cc


text:
#ifndef ARGPARSE_HH
#define ARGPARSE_HH

#include <string>
#include <tuple>
#include <vector>
#include <MeshFEM/Types.hh>
#include <boost/optional.hpp>

// Filter invocation: (name, argument string)
using FilterInvocation = std::pair<std::string, std::string>;
// Parse command line arguments to get a .msh file path and a sequence of filters.
std::tuple<std::string, std::vector<FilterInvocation>, boost::optional<size_t>> parseCmdLine(int argc, char *argv[]);

// Parse a filter invocation's argument.
int parseIntArg(const std::string &arg);
double parseRealArg(const std::string &arg);

template<size_t N>
using VecHPCFix = Eigen::Matrix<Real, N, 1, 0>;

template<size_t N>
VecHPCFix<N> parseVectorArg(const std::string &arg);

template<size_t N>
std::vector<VecHPCFix<N>> parseVectorListArg(const std::string &arg);

#endif /* end of include guard: ARGPARSE_HH */

max_stars_repo_name: pbedenbaugh/MeshFEM

max_issues_repo_name: pbedenbaugh/MeshFEM

max_forks_repo_name: pbedenbaugh/MeshFEM


text:
// C++ standard libs
#include <algorithm>
#include <exception>
#include <queue>
#include <stack>
#include <tuple>
#include <unordered_set>

// Outside libs
#include <boost/functional/hash.hpp>
#include <personal.hpp>

// Local libs
#include "include/knight.hpp"

namespace kc{
//==================================================================================
// Tools
//==================================================================================
size_t knight_steps(size_t board_size, int8_t opt_level/*=0*/) {
    size_t solution;
    switch(opt_level) {
        case 0: solution = knight_steps_bfs(board_size); break;
        case 1: solution = knight_steps_astar(board_size); break;
        case 2: solution = knight_steps_parallel(board_size); break;
    }
    return solution;
}

void print_pos(const Pos& pos) {
    std::cout << "Pos: (" << pos.first << ", " << pos.second << ")\n";
}

void print_all(const Pos& pos, size_t steps) {
    std::cout << "Pos: (" << pos.first << ", " << pos.second
        << "); Steps: " << steps << std::endl;
}

//==================================================================================
// Breadth First
//==================================================================================
size_t knight_steps_bfs(size_t board_size) {
    // Initialize
    int n = board_size;
    std::queue<std::pair<Pos, size_t>> options;
    Pos goal = std::make_pair(n-1, n-1);
    Pos start = std::make_pair(0,0);
    options.push(std::make_pair(start,0));
    std::unordered_set<Pos, boost::hash<Pos>> visited;

    std::vector<Pos> movement = {std::make_pair(1,2), std::make_pair(2,1),
        std::make_pair(2,-1), std::make_pair(1,-2)};

    auto bounds_check = [&](int num) -> bool {
        return ((num >= 0) && (num < n));
    };

    while (!options.empty()) {
        // Remove from queue
        auto current = options.front();
        options.pop();
        Pos current_pos = current.first;
        size_t current_steps = current.second;
        //print_all(current_pos, current_steps);

        // Check if visited before
        if (visited.count(current_pos) > 0) {
            continue;
        } else {
            visited.insert(current_pos);
        }

        // Check if done
        if (current_pos == goal) {
            return current_steps;
        }

        // Otherwise add new options to queue
        for (auto& delta: movement) {
            auto forward_x = current_pos.first + delta.first;
            auto forward_y = current_pos.second + delta.second;
            auto back_x = current_pos.first - delta.first;
            auto back_y = current_pos.second - delta.second;
            if ((bounds_check(forward_x)) && (bounds_check(forward_y))) {
                Pos forward_move = std::make_pair(forward_x, forward_y);
                options.push(std::make_pair(forward_move, current_steps+1));
            }
            if ((bounds_check(back_x)) && (bounds_check(back_y))) {
                Pos back_move = std::make_pair(back_x, back_y);
                options.push(std::make_pair(back_move, current_steps+1));
            }
        }
    }
    return 0;
}

//==================================================================================
// A* Star
//==================================================================================
size_t knight_steps_astar(size_t board_size) {
    // Initialize
    // We want to prioritize a lower weight
    // (Pos, steps, weight)
    using Option = std::tuple<Pos, size_t, int>;
    int n = board_size;
    auto queue_sort = [] (const Option& a, const Option& b) {
        return std::get<2>(a) > std::get<2>(b);
    };

    std::priority_queue<
        Option, std::vector<Option>, decltype(queue_sort)>
        options(queue_sort);
    Pos goal = std::make_pair(n-1, n-1);
    Pos start = std::make_pair(0,0);
    auto calc_weight = [&](const Pos& current_pos, size_t steps) -> size_t {
        auto future = std::min(std::abs((current_pos.first - goal.first)),std::abs((current_pos.second - goal.second)));
        auto past = steps;
        return future + past;
    };
    options.push(std::make_tuple(start, 0, calc_weight(start,0)));
    std::unordered_set<Pos, boost::hash<Pos>> visited;

    std::vector<Pos> movement = {std::make_pair(1,2), std::make_pair(2,1),
        std::make_pair(2,-1), std::make_pair(1,-2)};

    auto bounds_check = [&](int num) -> bool {
        return ((num >= 0) && (num < n));
    };

    while (!options.empty()) {
        // Remove from queue
        auto current = options.top();
        options.pop();
        Pos current_pos = std::get<0>(current);
        int current_steps = std::get<1>(current);
        //print_all(current_pos, current_steps);

        // Check if visited before
        if (visited.count(current_pos) > 0) {
            continue;
        } else {
            visited.insert(current_pos);
        }

        // Check if done
        if (current_pos == goal) {
            return current_steps;
        }

        // Otherwise add new options to queue
        for (auto& delta: movement) {
            auto forward_x = current_pos.first + delta.first;
            auto forward_y = current_pos.second + delta.second;
            auto back_x = current_pos.first - delta.first;
            auto back_y = current_pos.second - delta.second;
            if ((bounds_check(forward_x)) && (bounds_check(forward_y))) {
                Pos forward_move = std::make_pair(forward_x, forward_y);
                options.push(std::make_tuple(
                    forward_move, current_steps+1,calc_weight(forward_move, current_steps+1)
                ));
            }
            if ((bounds_check(back_x)) && (bounds_check(back_y))) {
                Pos back_move = std::make_pair(back_x, back_y);
                options.push(std::make_tuple(
                    back_move, current_steps+1, calc_weight(back_move, current_steps+1)
                ));
            }
        }
    }
    return 0;
}

//==================================================================================
// Async
//==================================================================================
size_t knight_steps_async(size_t board_size) {
    // Initialize
    // We want to prioritize a lower weight
    // (Pos, steps, weight)
    using Option = std::tuple<Pos, size_t, int>;
    int n = board_size;
    auto queue_sort = [] (const Option& a, const Option& b) {
        return std::get<2>(a) > std::get<2>(b);
    };

    std::priority_queue<
        Option, std::vector<Option>, decltype(queue_sort)>
        options(queue_sort);
    Pos goal = std::make_pair(n-1, n-1);
    Pos start = std::make_pair(0,0);
    auto calc_weight = [&](const Pos& current_pos, size_t steps) -> size_t {
        auto future = std::min(std::abs((current_pos.first - goal.first)),std::abs((current_pos.second - goal.second)));
        auto past = steps;
        return future + past;
    };
    options.push(std::make_tuple(start, 0, calc_weight(start,0)));
    std::unordered_set<Pos, boost::hash<Pos>> visited;

    std::vector<Pos> movement = {std::make_pair(1,2), std::make_pair(2,1),
        std::make_pair(2,-1), std::make_pair(1,-2)};

    auto bounds_check = [&](int num) -> bool {
        return ((num >= 0) && (num < n));
    };

    while (!options.empty()) {
        // Remove from queue
        auto current = options.top();
        options.pop();
        Pos current_pos = std::get<0>(current);
        int current_steps = std::get<1>(current);
        //print_all(current_pos, current_steps);

        // Check if visited before
        if (visited.count(current_pos) > 0) {
            continue;
        } else {
            visited.insert(current_pos);
        }

        // Check if done
        if (current_pos == goal) {
            return current_steps;
        }

        // Otherwise add new options to queue
        for (auto& delta: movement) {
            auto forward_x = current_pos.first + delta.first;
            auto forward_y = current_pos.second + delta.second;
            auto back_x = current_pos.first - delta.first;
            auto back_y = current_pos.second - delta.second;
            if ((bounds_check(forward_x)) && (bounds_check(forward_y))) {
                Pos forward_move = std::make_pair(forward_x, forward_y);
                options.push(std::make_tuple(
                    forward_move, current_steps+1,calc_weight(forward_move, current_steps+1)
                ));
            }
            if ((bounds_check(back_x)) && (bounds_check(back_y))) {
                Pos back_move = std::make_pair(back_x, back_y);
                options.push(std::make_tuple(
                    back_move, current_steps+1, calc_weight(back_move, current_steps+1)
                ));
            }
        }
    }
    return 0;
}

//==================================================================================
// Parallel
//==================================================================================
size_t knight_steps_parallel(size_t board_size) {
    return 0;
}

}

ext: cpp


text:
/// Watch FS for changes.
///
/// @file

#pragma once
#ifndef WATCHER_HPP__DNJ8BT5L
#define WATCHER_HPP__DNJ8BT5L

#include <chrono>
#include <mutex>
#include <thread>

#include "rewofs/disablewarnings.hpp"
#include <boost/filesystem.hpp>
#include <boost/noncopyable.hpp>
#include <flatbuffers/flatbuffers.h>
#include "rewofs/enablewarnings.hpp"

#include "rewofs/server/transport.hpp"

//==========================================================================
namespace rewofs::server {
//==========================================================================

/// Map for ignoring remote actions.
class TemporalIgnores : private boost::noncopyable
{
private:
    using Path = boost::filesystem::path;

public:
    TemporalIgnores(const std::chrono::milliseconds ignore_duration);

    /// Add a temporal ignore.
    void add(const std::chrono::steady_clock::time_point now, Path path);
    /// @return true if the path should be ignored.
    bool check(const std::chrono::steady_clock::time_point now, const Path& path);

private:
    struct Item
    {
        std::chrono::steady_clock::time_point tp{};
        Path path{};
    };

    struct ItemsOrder
    {
        constexpr bool operator()(const Item& i1, const Item& i2) const
        {
            return i1.tp < i2.tp;
        }
    };

    const std::chrono::milliseconds m_ignore_duration{};
    std::deque<Item> m_items{};
    std::mutex m_mutex{};
};

//==========================================================================

class Watcher : private boost::noncopyable
{
public:
    Watcher(server::Transport& transport, TemporalIgnores& temporal_ignores);

    void start();
    void stop();
    void wait();

private:
    using Path = boost::filesystem::path;

    void run();

    template<typename _Msg>
    void send(flatbuffers::FlatBufferBuilder& fbb, flatbuffers::Offset<_Msg> msg);
    void notify_change();

    server::Transport& m_transport;
    TemporalIgnores& m_temporal_ignores;
    std::thread m_thread{};
    std::atomic<bool> m_quit{false};
};

//==========================================================================
} // namespace rewofs::server

#endif /* include guard */

ext: hpp

max_stars_repo_name: dsiroky/rewofs

max_issues_repo_name: dsiroky/rewofs

max_forks_repo_name: dsiroky/rewofs


text:
// ======================================================================

#include "Projection.h"
#include "Config.h"
#include "Hash.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <engines/gis/Engine.h>
#include <fmt/format.h>
#include <gis/Box.h>
#include <gis/CoordinateTransformation.h>
#include <grid-files/common/GeneralFunctions.h>
#include <macgyver/Exception.h>
#include <spine/HTTP.h>
#include <cmath>
#include <ogr_geometry.h>
#include <ogr_spatialref.h>
#include <stdexcept>

namespace SmartMet
{
namespace Plugin
{
namespace Dali
{
// ----------------------------------------------------------------------
/*!
 * \brief Initialize the projection from JSON
 */
// ----------------------------------------------------------------------

void Projection::init(const Json::Value& theJson,
                      const State& theState,
                      const Config& /* theConfig */)
{
  try
  {
    if (!theJson.isObject())
      throw Fmi::Exception(BCP, "Projection JSON is not a JSON object (name-value pairs)");

    // For later use
    gisengine = &theState.getGisEngine();

    // Extract all the members

    Json::Value nulljson;
    auto request = theState.getRequest();
    boost::optional<std::string> v;

    auto json = theJson.get("crs", nulljson);
    if (!json.isNull())
      crs = json.asString();

    json = theJson.get("bboxcrs", nulljson);
    if (!json.isNull())
      bboxcrs = json.asString();

    if (crs && *crs == "data")
    {
      json = theJson.get("size", nulljson);
      if (!json.isNull())
        size = json.asDouble();

      v = request.getParameter("size");
      if (v)
        size = toDouble(*v);
    }

    if (!size || *size <= 0)
    {
      json = theJson.get("xsize", nulljson);
      if (!json.isNull())
        xsize = json.asInt();

      json = theJson.get("ysize", nulljson);
      if (!json.isNull())
        ysize = json.asInt();

      v = request.getParameter("xsize");
      if (v)
        xsize = toInt32(*v);

      v = request.getParameter("ysize");
      if (v)
        ysize = toInt32(*v);
    }

    json = theJson.get("x1", nulljson);
    if (!json.isNull())
      x1 = json.asDouble();

    json = theJson.get("y1", nulljson);
    if (!json.isNull())
      y1 = json.asDouble();

    json = theJson.get("x2", nulljson);
    if (!json.isNull())
      x2 = json.asDouble();

    json = theJson.get("y2", nulljson);
    if (!json.isNull())
      y2 = json.asDouble();

    json = theJson.get("cx", nulljson);
    if (!json.isNull())
      cx = json.asDouble();

    json = theJson.get("cy", nulljson);
    if (!json.isNull())
      cy = json.asDouble();

    json = theJson.get("resolution", nulljson);
    if (!json.isNull())
      resolution = json.asDouble();

    // Note: intentionally after cx,cy parsing to enable name overrides

    json = theJson.get("geoid", nulljson);
    if (!json.isNull())
    {
      const auto& engine = theState.getGeoEngine();
      // TODO(mheiskan): Make the language configurable
      int id = json.asInt();
      auto loc = engine.idSearch(id, "fi");
      if (!loc)
        throw Fmi::Exception(BCP,
                             "Unable to find coordinates for geoid '" + Fmi::to_string(id) + "'");
      latlon_center = true;
      cx = loc->longitude;
      cy = loc->latitude;
    }

    json = theJson.get("place", nulljson);
    if (!json.isNull())
    {
      const auto& engine = theState.getGeoEngine();
      // TODO(mheiskan): Make the language configurable
      std::string name = json.asString();
      auto loc = engine.nameSearch(name, "fi");
      if (!loc)
        throw Fmi::Exception(BCP, "Unable to find coordinates for location '" + name + "'");

      latlon_center = true;
      cx = loc->longitude;
      cy = loc->latitude;
    }

    // Note: this must be handled after the CRS variables!

    json = theJson.get("bbox", nulljson);
    if (!json.isNull())
    {
      std::string bbox = json.asString();
      std::vector<std::string> parts;
      boost::algorithm::split(parts, bbox, boost::algorithm::is_any_of(","));
      if (parts.size() != 4)
        throw Fmi::Exception(BCP, "bbox should contain 4 comma separated doubles");

      // for example in EPSG:4326 order of coordinates is changed in WMS
      // for more info: https://trac.osgeo.org/gdal/wiki/rfc20_srs_axes

      OGRSpatialReference spatref;
      if (bboxcrs)
      {
        // SetFromUserInput wants 'EPSGA' - code in order to understand axis ordering
        if (boost::algorithm::starts_with(*bboxcrs, "EPSG:"))
          boost::algorithm::replace_first(*bboxcrs, "EPSG:", "EPSGA:");

        spatref.SetFromUserInput(bboxcrs->c_str());
        spatref.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      }
      else
      {
        // SetFromUserInput wants 'EPSGA' - code in order to understand axis ordering
        if (boost::algorithm::starts_with(*crs, "EPSG:"))
          boost::algorithm::replace_first(*crs, "EPSG:", "EPSGA:");

        spatref.SetFromUserInput(crs->c_str());
      }

      bool latLonOrder = spatref.EPSGTreatsAsLatLong() != 0;

      if (latLonOrder)
      {
        y1 = Fmi::stod(parts[0]);
        x1 = Fmi::stod(parts[1]);
        y2 = Fmi::stod(parts[2]);
        x2 = Fmi::stod(parts[3]);
      }
      else
      {
        x1 = Fmi::stod(parts[0]);
        y1 = Fmi::stod(parts[1]);
        x2 = Fmi::stod(parts[2]);
        y2 = Fmi::stod(parts[3]);
      }
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Hash value
 */
// ----------------------------------------------------------------------

std::size_t Projection::hash_value(const State& /* theState */) const
{
  try
  {
    auto hash = Fmi::hash_value(crs);
    Fmi::hash_combine(hash, Fmi::hash_value(size));
    Fmi::hash_combine(hash, Fmi::hash_value(xsize));
    Fmi::hash_combine(hash, Fmi::hash_value(ysize));
    Fmi::hash_combine(hash, Fmi::hash_value(x1));
    Fmi::hash_combine(hash, Fmi::hash_value(y1));
    Fmi::hash_combine(hash, Fmi::hash_value(x2));
    Fmi::hash_combine(hash, Fmi::hash_value(y2));
    Fmi::hash_combine(hash, Fmi::hash_value(cx));
    Fmi::hash_combine(hash, Fmi::hash_value(cy));
    Fmi::hash_combine(hash, Fmi::hash_value(resolution));
    Fmi::hash_combine(hash, Fmi::hash_value(bboxcrs));
    Fmi::hash_combine(hash, Fmi::hash_value(size));
    return hash;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Update area with querydata if necessary
 */
// ----------------------------------------------------------------------

void Projection::update(const Engine::Querydata::Q& theQ)
{
  if (!theQ)
    return;

  try
  {
    if (crs && *crs == "data")
    {
      crs = theQ->SpatialReference().projStr();
      bool no_bbox = (!x1 && !y1 && !x2 && !y2 && !cx && !cy && !resolution && !bboxcrs);

      if (no_bbox)
      {
        auto world1 = theQ->area().XYToWorldXY(theQ->area().BottomLeft());
        auto world2 = theQ->area().XYToWorldXY(theQ->area().TopRight());
        x1 = world1.X();
        y1 = world1.Y();
        x2 = world2.X();
        y2 = world2.Y();
      }

      if (size)
      {
        xsize = C_INT(C_DOUBLE(theQ->info()->GridXNumber()) * (*size));
        ysize = C_INT(C_DOUBLE(theQ->info()->GridYNumber()) * (*size));
      }

      ogr_crs.reset();
      box.reset();
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Return the spatial reference
 */
// ----------------------------------------------------------------------

const Fmi::SpatialReference& Projection::getCRS() const
{
  try
  {
    prepareCRS();
    return *ogr_crs;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Return the spatial area
 */
// ----------------------------------------------------------------------

const Fmi::Box& Projection::getBox() const
{
  try
  {
    prepareCRS();
    return *box;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Create OGR spatial reference from the settings
 */
// ----------------------------------------------------------------------

void Projection::prepareCRS() const
{
  try
  {
    // Done already?
    if (ogr_crs)
      return;

    if (!crs)
      throw Fmi::Exception(BCP, "CRS not set, unable to create projection");

    if (!xsize && !ysize)
    {
      if (size)
        return;

      throw Fmi::Exception(BCP, "CRS xsize and ysize are both missing");
    }

    // Are subdefinitions complete?
    bool full_rect_bbox = (x1 && y1 && x2 && y2);
    bool full_center_bbox = (cx && cy && resolution);

    // Are they partial?
    bool partial_rect_bbox = !full_rect_bbox && (x1 || y1 || x2 || y2);
    bool partial_center_bbox = !full_center_bbox && (cx || cy || resolution);

    // Disallow partial definitions
    if (partial_rect_bbox)
      throw Fmi::Exception(BCP, "Partial CRS bounding box given: x1,y1,x2,y2 are needed");
    if (partial_center_bbox)
      throw Fmi::Exception(BCP, "Partial CRS bounding box given: cx,cy,resolution are needed");

    // bbox definition missing completely?
    if (!full_rect_bbox && !full_center_bbox)
      throw Fmi::Exception(BCP,
                           "CRS bounding box missing: x1,y2,x2,y2 or cx,cy,resolution are needed");

// two conflicting definitions is OK, since we create the corners from centered bbox
#if 0
        if(full_rect_bbox && full_center_bbox)
      throw Fmi::Exception(BCP,"CRS bounding box overdefined: use only x1,y2,x2,y2 or cx,cy,resolution");
#endif

    // must give both width and height if centered bbox is given
    if (!full_rect_bbox && full_center_bbox && (!xsize || !ysize))
      throw Fmi::Exception(BCP,
                           "CRS xsize and ysize are required when a centered bounding box is used");

    // Create the CRS
    ogr_crs = std::make_shared<Fmi::SpatialReference>(*crs);

    if (xsize && *xsize <= 0)
      throw Fmi::Exception(BCP, "Projection xsize must be positive");

    if (ysize && *ysize <= 0)
      throw Fmi::Exception(BCP, "Projection ysize must be positive");

    // World XY bounding box will be calculated during the process

    double XMIN, YMIN, XMAX, YMAX;

    // Create the Contour::Area object

    if (full_rect_bbox)
    {
      // rect bounding box

      XMIN = *x1;
      YMIN = *y1;
      XMAX = *x2;
      YMAX = *y2;

      if (bboxcrs)
      {
        // Reproject corners coordinates from bboxcrs to crs
        Fmi::CoordinateTransformation transformation(*bboxcrs, *ogr_crs);
        transformation.transform(XMIN, YMIN);
        transformation.transform(XMAX, YMAX);
      }

      if (XMIN == XMAX || YMIN == YMAX)
        throw Fmi::Exception(BCP, "Bounding box size is zero!");

      if (!xsize)
      {
        // Preserve aspect by calculating xsize
        int w = boost::numeric_cast<int>((*ysize) * (XMAX - XMIN) / (YMAX - YMIN));
        box = std::make_shared<Fmi::Box>(XMIN, YMIN, XMAX, YMAX, w, *ysize);
      }
      else if (!ysize)
      {
        // Preserve aspect by calculating ysize
        int h = boost::numeric_cast<int>((*xsize) * (YMAX - YMIN) / (XMAX - XMIN));
        box = std::make_shared<Fmi::Box>(XMIN, YMIN, XMAX, YMAX, *xsize, h);
      }
      else
      {
        box = std::make_shared<Fmi::Box>(XMIN, YMIN, XMAX, YMAX, *xsize, *ysize);
      }

      if (ogr_crs->isGeographic() != 0)
      {
        // Substract equations 5 and 4, subsititute equation 3 and solve resolution
        double pi = boost::math::constants::pi<double>();
        double circumference = 2 * pi * 6371.220;
        resolution = (YMAX - YMIN) * circumference / (360 * (*ysize));
      }
      else
      {
        // Substract equations 1 and 2 to eliminate and solve resolution
        resolution = (XMAX - XMIN) / ((*xsize) * 1000);
      }
    }

    else
    {
      // centered bounding box
      if (!xsize || !ysize)
        throw Fmi::Exception(BCP,
                             "xsize and ysize are required when a centered bounding box is used");

      double CX = *cx, CY = *cy;

      if (latlon_center || (bboxcrs && *crs != *bboxcrs))
      {
        // Reproject center coordinates from latlon/bboxcrs to crs
        Fmi::CoordinateTransformation transformation(latlon_center ? "WGS84" : bboxcrs->c_str(),
                                                     *ogr_crs);
        transformation.transform(CX, CY);
      }

      if (ogr_crs->isGeographic() != 0)
      {
        double pi = boost::math::constants::pi<double>();
        double circumference = 2 * pi * 6371.220;

        // This will work well, since we move along an isocircle
        double dy = 360 * (*ysize) / 2.0 * (*resolution) / circumference;  // Equation 3.
        YMIN = CY - dy;                                                    // Equation 4.
        YMAX = CY + dy;                                                    // Equation 5

        // Distances will become distorted the further away we are from the equator
        double dx = 360 * (*xsize) / 2.0 * (*resolution) / circumference / cos(CX * pi / 180.0);
        XMIN = CX - dx;
        XMAX = CX + dx;

        box = std::make_shared<Fmi::Box>(XMIN, YMIN, XMAX, YMAX, *xsize, *ysize);
      }
      else
      {
        XMIN = CX - (*xsize) / 2.0 * (*resolution) * 1000;  // Equation 1.
        XMAX = CX + (*xsize) / 2.0 * (*resolution) * 1000;  // Equation 2.
        YMIN = CY - (*ysize) / 2.0 * (*resolution) * 1000;
        YMAX = CY + (*ysize) / 2.0 * (*resolution) * 1000;
        box = std::make_shared<Fmi::Box>(XMIN, YMIN, XMAX, YMAX, *xsize, *ysize);
      }
    }

    // newbase corners calculated from world xy coordinates

    Fmi::CoordinateTransformation transformation(*ogr_crs, "FMI");

    // Calculate bottom left and top right coordinates

    transformation.transform(XMIN, YMIN);
    itsBottomLeft = NFmiPoint(XMIN, YMIN);

    transformation.transform(XMAX, YMAX);
    itsTopRight = NFmiPoint(XMAX, YMAX);

#if 0
    std::cerr << std::setprecision(8) << "\nProjection:\n\n"
              << "\nxsize=" << (xsize ? *xsize : -1) << "\nysize=" << (ysize ? *ysize : -1)
              << "\nx1=" << (x1 ? *x1 : -1) << "\ny1=" << (y1 ? *y1 : -1)
              << "\nx2=" << (x2 ? *x2 : -1) << "\ny2=" << (y2 ? *y2 : -1)
              << "\ncx=" << (cx ? *cx : -1) << "\ncy=" << (cy ? *cy : -1)
              << "\nres=" << (resolution ? *resolution : -1) << "\nbl=" << itsBottomLeft.X() << ","
              << itsBottomLeft.Y() << "\ntr=" << itsTopRight.X() << "," << itsTopRight.Y() << "\n"
              << "\nxmin=" << box->xmin() << "\nxmax=" << box->xmax() << "\nymin=" << box->ymin()
              << "\nymax=" << box->ymax() << "\nwidth=" << box->width()
              << "\nheight=" << box->height() << "\n"
              << std::endl;
#endif
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

}  // namespace Dali
}  // namespace Plugin
}  // namespace SmartMet

max_stars_repo_name: fmidev/smartmet-plugin-wms

max_issues_repo_name: fmidev/smartmet-plugin-wms

max_forks_repo_name: fmidev/smartmet-plugin-wms


text:
//  ratio_fwd.hpp  ---------------------------------------------------------------//

//  Copyright 2008 Howard Hinnant
//  Copyright 2008 Beman Dawes
//  Copyright 2009 Vicente J. Botet Escriba

//  Distributed under the Boost Software License, Version 1.0.
//  See http://www.boost.org/LICENSE_1_0.txt

/*

This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype.
Many thanks to Howard for making his code available under the Boost license.
The original code was modified to conform to Boost conventions and to section
20.4 Compile-time rational arithmetic [ratio], of the C++ committee working
paper N2798.
See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf.

time2_demo contained this comment:

    Much thanks to Andrei Alexandrescu,
                   Walter Brown,
                   Peter Dimov,
                   Jeff Garland,
                   Terry Golubiewski,
                   Daniel Krugler,
                   Anthony Williams.
*/

// The way overflow is managed for ratio_less is taken from llvm/libcxx/include/ratio

#ifndef BOOST_RATIO_RATIO_FWD_HPP
#define BOOST_RATIO_RATIO_FWD_HPP

#include <boost/cstdint.hpp>
#ifdef INTMAX_C
#define BOOST_RATIO_INTMAX_C(a) INTMAX_C(a)
#else
#define BOOST_RATIO_INTMAX_C(a) a##LL
#endif

namespace boost
{

//----------------------------------------------------------------------------//
//                                                                            //
//              20.6 Compile-time rational arithmetic [ratio]                 //
//                                                                            //
//----------------------------------------------------------------------------//

// ratio
template <boost::intmax_t N, boost::intmax_t D = 1> class ratio;

// ratio arithmetic
template <class R1, class R2> struct ratio_add;
template <class R1, class R2> struct ratio_subtract;
template <class R1, class R2> struct ratio_multiply;
template <class R1, class R2> struct ratio_divide;

// ratio comparison
template <class R1, class R2> struct ratio_equal;
template <class R1, class R2> struct ratio_not_equal;
template <class R1, class R2> struct ratio_less;
template <class R1, class R2> struct ratio_less_equal;
template <class R1, class R2> struct ratio_greater;
template <class R1, class R2> struct ratio_greater_equal;

// convenience SI typedefs
typedef ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(1000000000000000000)> atto;
typedef ratio<BOOST_RATIO_INTMAX_C(1),    BOOST_RATIO_INTMAX_C(1000000000000000)> femto;
typedef ratio<BOOST_RATIO_INTMAX_C(1),       BOOST_RATIO_INTMAX_C(1000000000000)> pico;
typedef ratio<BOOST_RATIO_INTMAX_C(1),          BOOST_RATIO_INTMAX_C(1000000000)> nano;
typedef ratio<BOOST_RATIO_INTMAX_C(1),             BOOST_RATIO_INTMAX_C(1000000)> micro;
typedef ratio<BOOST_RATIO_INTMAX_C(1),                BOOST_RATIO_INTMAX_C(1000)> milli;
typedef ratio<BOOST_RATIO_INTMAX_C(1),                 BOOST_RATIO_INTMAX_C(100)> centi;
typedef ratio<BOOST_RATIO_INTMAX_C(1),                  BOOST_RATIO_INTMAX_C(10)> deci;
typedef ratio<                 BOOST_RATIO_INTMAX_C(10), BOOST_RATIO_INTMAX_C(1)> deca;
typedef ratio<                BOOST_RATIO_INTMAX_C(100), BOOST_RATIO_INTMAX_C(1)> hecto;
typedef ratio<               BOOST_RATIO_INTMAX_C(1000), BOOST_RATIO_INTMAX_C(1)> kilo;
typedef ratio<            BOOST_RATIO_INTMAX_C(1000000), BOOST_RATIO_INTMAX_C(1)> mega;
typedef ratio<         BOOST_RATIO_INTMAX_C(1000000000), BOOST_RATIO_INTMAX_C(1)> giga;
typedef ratio<      BOOST_RATIO_INTMAX_C(1000000000000), BOOST_RATIO_INTMAX_C(1)> tera;
typedef ratio<   BOOST_RATIO_INTMAX_C(1000000000000000), BOOST_RATIO_INTMAX_C(1)> peta;
typedef ratio<BOOST_RATIO_INTMAX_C(1000000000000000000), BOOST_RATIO_INTMAX_C(1)> exa;

}  // namespace boost

#endif  // BOOST_RATIO_HPP


text:
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/vinniefalco/json
//

#ifndef BOOST_JSON_SERIALIZER_HPP
#define BOOST_JSON_SERIALIZER_HPP

#include <boost/json/config.hpp>
#include <boost/json/value.hpp>
#include <boost/json/detail/format.hpp>
#include <boost/json/detail/stack.hpp>
#include <boost/json/detail/static_stack.hpp>
#include <boost/json/detail/stream.hpp>
#include <iosfwd>

namespace boost {
namespace json {

/** A serializer for JSON.

    This class traverses a @ref value and emits
    a serialized JSON object. It can work
    incrementally, by filling successive
    caller-provided buffers.
*/
class serializer
{
    enum class state : char;
    using stream = detail::stream;
    using const_stream = detail::const_stream;
    using local_stream = detail::local_stream;
    using local_const_stream =
        detail::local_const_stream;

    value const* jv_ = nullptr;
    detail::stack st_;
    const_stream cs0_;
    char buf_[detail::max_number_chars + 1];
    bool done_ = false;

    inline bool suspend(state st);
    inline bool suspend(state st,
        array::const_iterator it, value const* jv);
    inline bool suspend(state st,
        object::const_iterator it, value const* jv);
    template<bool StackEmpty> bool write_null(stream& ss);
    template<bool StackEmpty> bool write_true(stream& ss);
    template<bool StackEmpty> bool write_false(stream& ss);
    template<bool StackEmpty> bool write_string(stream& ss);
    template<bool StackEmpty> bool write_number(stream& ss);
    template<bool StackEmpty> bool write_array(stream& ss);
    template<bool StackEmpty> bool write_object(stream& ss);
    template<bool StackEmpty> bool write_value(stream& ss);
    inline std::size_t write_some(
        char* dest, std::size_t size);

public:
    /** Default constructor.

        This constructs a serializer without
        a current @ref value to serialize. Before
        any serialization can take place, @ref reset
        must be called.

        @par Exception Safety

        No-throw guarantee.
    */
    BOOST_JSON_DECL
    serializer() noexcept;

    /** Constructor.

        This constructs the serializer and
        calls @ref reset with `jv`.

        @par Exception Safety

        No-throw guarantee.

        @param jv The value to serialize.
    */
    explicit
    serializer(value const& jv) noexcept
    {
        reset(jv);
    }

    /** Returns `true` if the serialization is complete.

        This function returns `true` when all of the
        characters in the serialized representation of
        the value have been read.
    */
    bool
    is_done() const noexcept
    {
        return done_;
    }

    /** Reset the serializer for a new JSON value.

        This function prepares the serializer to emit
        a new serialized JSON based on the specified
        value. Any internally allocated memory is
        preserved and re-used for the new output.

        @param jv The value to serialize.
    */
    BOOST_JSON_DECL
    void
    reset(value const& jv) noexcept;

    /** Read the next buffer of serialized JSON.

        This function attempts to fill the caller
        provided buffer starting at `dest` with
        up to `size` characters of the serialized
        JSON that represents the value. If the
        buffer is not large enough, multiple calls
        may be required.

        @par Example

        This demonstrates how the serializer may
        be used to print a JSON value to an output
        stream.

        @code

        void print( std::ostream& os, value const& jv)
        {
            serializer sr( jv );
            while( ! sr.done() )
            {
                char buf[1024];
                auto const n = sr.read( buf, sizeof(buf) );
                os << string_view( buf, n );
            }
        }

        @endcode

        @par Exception Safety

        Strong guarantee.
        Calls to @ref storage::allocate may throw.

        @throw std::logic_error if no value is set.

        @return The number of characters written
        to `dest`.
    */
    BOOST_JSON_DECL
    std::size_t
    read(char* dest, std::size_t size);
};

//----------------------------------------------------------

/** Return a string representing a serialized @ref value.

    This function serializes the specified value
    and returns it as a @ref string.

    @par Exception Safety

    Strong guarantee.
    Calls to @ref storage::allocate may throw.

    @param jv The value to serialize.
*/
BOOST_JSON_DECL
string
to_string(
    value const& jv);

/** Serialize a @ref value to an output stream.

    This function serializes the specified value
    into the output stream.

    @par Exception Safety

    Strong guarantee.
    Calls to @ref storage::allocate may throw.

    @param os The output stream to serialize to.

    @param jv The value to serialize.

    @return `os`.
*/
BOOST_JSON_DECL
std::ostream&
operator<<(
    std::ostream& os,
    value const& jv);

} // json
} // boost

#ifdef BOOST_JSON_HEADER_ONLY
#include <boost/json/impl/serializer.ipp>
#endif

#endif

max_stars_repo_name: dendisuhubdy/json-cppalliance

max_issues_repo_name: dendisuhubdy/json-cppalliance

max_forks_repo_name: dendisuhubdy/json-cppalliance


text:
/*
==============================================================================
KratosConvectionDiffusionApplication
A library based on:
Kratos
A General Purpose Software for Multi-Physics Finite Element Analysis
Version 1.0 (Released on march 05, 2007).

Copyright 2007
Pooyan Dadvand, Riccardo Rossi
pooyan@cimne.upc.edu
rrossi@cimne.upc.edu
- CIMNE (International Center for Numerical Methods in Engineering),
Gran Capita' s/n, 08034 Barcelona, Spain

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 condition:

Distribution of this code for  any  commercial purpose  is permissible
ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNERS.

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.

==============================================================================
*/
//
//   Project Name:        Kratos
//   Last modified by:    $Author: antonia $
//   Date:                $Date: 2008-03-11 14:06:15 $
//   Revision:            $Revision: 1.4 $
//
//

// System includes

// External includes
#include <boost/python.hpp>

// Project includes
#include "includes/define.h"
#include "processes/process.h"
#include "custom_python/add_custom_utilities_to_python.h"
#include "custom_utilities/face_heat_utilities.h"
#include "custom_utilities/pure_convection_tools.h"
#include "custom_utilities/pure_convection_CrankN_tools.h"

#include "spaces/ublas_space.h"
#include "linear_solvers/linear_solver.h"

namespace Kratos
{

namespace Python
{

  void  AddCustomUtilitiesToPython()
  {
	using namespace boost::python;

	  class_<FaceHeatUtilities>("FaceHeatUtilities", init<>())
		.def("ApplyFaceHeat",&FaceHeatUtilities::ApplyFaceHeat)
		;

	  typedef UblasSpace<double, CompressedMatrix, Vector> SparseSpaceType;
	  typedef UblasSpace<double, Matrix, Vector> LocalSpaceType;
	  typedef LinearSolver<SparseSpaceType, LocalSpaceType > LinearSolverType;

	  class_< PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >,  boost::noncopyable >	("PureConvectionUtilities2D", init<	>() )
			  .def("ConstructSystem",&PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >::ConstructSystem)
			  .def("CalculateProjection",&PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >::CalculateProjection)
			  .def("ConvectScalarVar",&PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >::ConvectScalarVar)
			  .def("ClearSystem",&PureConvectionUtilities< 2, SparseSpaceType, LinearSolverType >::ClearSystem)
			  ;

	  class_< PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >,  boost::noncopyable >	("PureConvectionUtilities3D", init<	>() )
			  .def("ConstructSystem",&PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >::ConstructSystem)
			  .def("CalculateProjection",&PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >::CalculateProjection)
			  .def("ConvectScalarVar",&PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >::ConvectScalarVar)
			  .def("ClearSystem",&PureConvectionUtilities< 3, SparseSpaceType, LinearSolverType >::ClearSystem)
			  ;

	class_< PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >,  boost::noncopyable >	("PureConvectionCrankNUtilities2D", init<	>() )
			  .def("ConstructSystem",&PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >::ConstructSystem)
			  .def("CalculateProjection",&PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >::CalculateProjection)
			  .def("ConvectScalarVar",&PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >::ConvectScalarVar)
			  .def("ClearSystem",&PureConvectionCrankNUtilities< 2, SparseSpaceType, LinearSolverType >::ClearSystem)
			  ;

	  class_< PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >,  boost::noncopyable >	("PureConvectionCrankNUtilities3D", init<	>() )
			  .def("ConstructSystem",&PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >::ConstructSystem)
			  .def("CalculateProjection",&PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >::CalculateProjection)
			  .def("ConvectScalarVar",&PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >::ConvectScalarVar)
			  .def("ClearSystem",&PureConvectionCrankNUtilities< 3, SparseSpaceType, LinearSolverType >::ClearSystem)
			  ;

  }

}  // namespace Python.

} // Namespace Kratos


text:
#pragma once
#include <iostream>
#include <vector>
#include <numeric>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/irange.hpp>

template <typename T, uint rowSize>
class FlattenVector
{
public:
    FlattenVector<T, rowSize>(uint size) { vec.reserve(size); };
    T& operator[](uint index) { return vec[index]; }
    const T& operator[](uint index) const { return vec[index]; }
    void emplace_back(T&& element) { vec.emplace_back(std::move(element)); }
    auto size() const { return vec.size(); }

    template <typename Range>
    auto getFilledElements(Range&& range) const
    {
        auto indexToValue = [this](uint index){ return vec[index]; };
        auto hasValue = [](const T& element){ return element; };

        using namespace boost::adaptors;
        return boost::copy_range<decltype(vec)>(range | transformed(indexToValue)
                                                      | filtered(hasValue));
    }

    friend std::ostream& operator<<(std::ostream& os, const FlattenVector<T, rowSize>& flattenVec)
    {
        for(auto index : boost::irange(0lu, flattenVec.vec.size()))
        {
            os << flattenVec.vec[index] << " ";
            if((index + 1) % rowSize == 0)
                os << std::endl;
        }
        os << std::endl;
        return os;
    }

private:
    std::vector<T> vec;
};

max_stars_repo_name: rafauu/sudo-ku

max_issues_repo_name: rafauu/sudo-ku

max_forks_repo_name: rafauu/sudo-ku


text:
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////

#define BOOST_CONTAINER_SOURCE
#include <boost/container/detail/config_begin.hpp>
#include <boost/container/detail/workaround.hpp>
#include <boost/container/detail/thread_mutex.hpp>

#include <boost/container/pmr/synchronized_pool_resource.hpp>
#include <cstddef>

namespace {

using namespace boost::container::dtl;

class thread_mutex_lock
{
   thread_mutex &m_mut;

   public:
   explicit thread_mutex_lock(thread_mutex &m)
      : m_mut(m)
   {
      m_mut.lock();
   }

   ~thread_mutex_lock()
   {
      m_mut.unlock();
   }
};

}  //namespace {

namespace boost {
namespace container {
namespace pmr {

synchronized_pool_resource::synchronized_pool_resource(const pool_options& opts, memory_resource* upstream) BOOST_NOEXCEPT
   : m_mut(), m_pool_resource(opts, upstream)
{}

synchronized_pool_resource::synchronized_pool_resource() BOOST_NOEXCEPT
   : m_mut(), m_pool_resource()
{}

synchronized_pool_resource::synchronized_pool_resource(memory_resource* upstream) BOOST_NOEXCEPT
   : m_mut(), m_pool_resource(upstream)
{}

synchronized_pool_resource::synchronized_pool_resource(const pool_options& opts) BOOST_NOEXCEPT
   : m_mut(), m_pool_resource(opts)
{}

synchronized_pool_resource::~synchronized_pool_resource() //virtual
{}

void synchronized_pool_resource::release()
{
   thread_mutex_lock lck(m_mut); (void)lck;
   m_pool_resource.release();
}

memory_resource* synchronized_pool_resource::upstream_resource() const
{  return m_pool_resource.upstream_resource();  }

pool_options synchronized_pool_resource::options() const
{  return m_pool_resource.options();  }

void* synchronized_pool_resource::do_allocate(std::size_t bytes, std::size_t alignment) //virtual
{
   thread_mutex_lock lck(m_mut); (void)lck;
   return m_pool_resource.do_allocate(bytes, alignment);
}

void synchronized_pool_resource::do_deallocate(void* p, std::size_t bytes, std::size_t alignment) //virtual
{
   thread_mutex_lock lck(m_mut); (void)lck;
   return m_pool_resource.do_deallocate(p, bytes, alignment);
}

bool synchronized_pool_resource::do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT //virtual
{  return this == dynamic_cast<const synchronized_pool_resource*>(&other);  }

std::size_t synchronized_pool_resource::pool_count() const
{  return m_pool_resource.pool_count();  }

std::size_t synchronized_pool_resource::pool_index(std::size_t bytes) const
{  return m_pool_resource.pool_index(bytes);  }

std::size_t synchronized_pool_resource::pool_next_blocks_per_chunk(std::size_t pool_idx) const
{  return m_pool_resource.pool_next_blocks_per_chunk(pool_idx);  }

std::size_t synchronized_pool_resource::pool_block(std::size_t pool_idx) const
{  return m_pool_resource.pool_block(pool_idx);  }

std::size_t synchronized_pool_resource::pool_cached_blocks(std::size_t pool_idx) const
{  return m_pool_resource.pool_cached_blocks(pool_idx);  }

}  //namespace pmr {
}  //namespace container {
}  //namespace boost {

#include <boost/container/detail/config_end.hpp>


text:
// File: btBoostHello.hpp
#ifndef _btBoostHello_hpp
#define _btBoostHello_hpp

#include <btBulletDynamicsCommon.h>
#include <btBulletCollisionCommon.h>

#include <boost/python.hpp>

using namespace boost::python;

struct Data
{
    Data(): a(0), b(0) {}
    virtual ~Data() {}
    int a;
    float b;
};

inline bool operator==(const Data& lv, const Data& rv)
{
    return lv.a == rv.a && rv.b == rv.b;
}

class Hello
{
    Data m_data;

public:
    void setData(const Data& v)
    {
        m_data = v;
    }

    const Data& getData() const
    {
        return m_data;
    }

};

inline bool operator==(const Hello& lv, const Hello& rv)
{
    return lv.getData() == rv.getData();
}

using namespace std;

ostream& operator<<(ostream& os, const Data& v)
{
    os << "(a: " << v.a << ", b: " << v.b << ")";
    return os;
}

void defineHello()
{
    class_<Data>("Data")
        .def(self_ns::str(self_ns::self))
        .def(self_ns::repr(self_ns::self))
        .def(self == other<Data>())
        .def_readwrite("a", &Data::a)
        .def_readwrite("b", &Data::b)
    ;

    class_<Hello>("Hello")
        .def(self == other<Hello>())
        .add_property("data",
                      make_function(&Hello::getData,
                      return_value_policy<copy_const_reference>()),
                      &Hello::setData)
    ;
}

#endif // _btBoostHello_hpp

max_stars_repo_name: Klumhru/boost-python-bullet

max_issues_repo_name: Klumhru/boost-python-bullet

max_forks_repo_name: Klumhru/boost-python-bullet


text:
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <sstream>

#include "handler.hpp"

using namespace std;
using namespace otus;

string Handler::handleCommand(string_view command) {
  Tokens tokens;
  boost::split(tokens, command, [](char c) { return c == ' '; });

  transform(
      tokens[0].begin(),
      tokens[0].end(),
      tokens[0].begin(),
      ::toupper);

  if (tokens[0] == "INSERT") {
    return handleInsert(tokens);
  }
  else if (tokens[0] == "TRUNCATE") {
    return handleTruncate(tokens);
  }
  else if (tokens[0] == "INTERSECTION") {
    return handleIntersection(tokens);
  }
  else if (tokens[0] == "SYMMETRIC_DIFFERENCE") {
    return handleSymmetricDifference(tokens);
  }

  return "ERR unknown command \"" + tokens[0] + "\"\n";
}

string Handler::handleInsert(Tokens const &tokens) {
  if (tokens.size() != 4)
    return "ERR command \"INSERT\" takes exactly three args\n";

  int id;
  try {
    id = boost::lexical_cast<int>(tokens[2]);
  }
  catch (boost::bad_lexical_cast const &e) {
    return "ERR invalid id \"" + tokens[2] + "\"\n";
  }

  string const &tableName { tokens[1] };
  string const &name { tokens[3] };

  try {
    solver.insert(tableName, id, name);
  }
  catch (Solver::InvalidOperation const &e) {
    return "ERR " + string(e.what()) + '\n';
  }
  return "OK\n";
}

string Handler::handleTruncate(Tokens const &tokens) {
  if (tokens.size() != 2)
    return "ERR command \"TRUNCATE\" takes exactly one arg\n";
  else {
    string const &tableName { tokens[1] };
    try {
      solver.truncate(tableName);
    }
    catch (Solver::InvalidOperation const &e) {
      return "ERR " + string(e.what()) + '\n';
    }
  }
  return "OK\n";
}

string Handler::handleIntersection(Tokens const &tokens) {
  if (tokens.size() != 1)
    return "ERR command \"INTERSECTION\" takes no args\n";

  auto intersection { solver.intersection() };

  return formatJoinResult(intersection);
}

string Handler::handleSymmetricDifference(Tokens const &tokens) {
  if (tokens.size() != 1)
    return "ERR command \"SYMMETRIC_DIFFERENCE\" takes no args\n";

  auto symDiff { solver.symmetricDifference() };

  return formatJoinResult(symDiff);
}

string otus::formatJoinResult (Solver::JoinType &input) {
  sort(input.begin(), input.end(), [](auto const &a, auto const &b) {
      return get<0>(a) < get<0>(b);
      });

  stringstream result { };

  for (auto line: input) {
    auto id { to_string(get<0>(line)) };
    auto const &nameA { get<1>(line) };
    auto const &nameB { get<2>(line) };

    result << id << ',' << nameA << ',' << nameB << '\n';
  }

  result << "OK\n";

  return result.str();
}


text:
#ifndef CAMERA_HPP
#define CAMERA_HPP

#include <map>
#include <vector>

#include <boost/bind.hpp>
#include <boost/signals2.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>

#include <opencv2/opencv.hpp>

#include <spdlog/spdlog.h>

#include <Space.hpp>

namespace SPRITS
{
	enum class NewFrameEvent { COLOR, DEPTH };

	class Camera
	{
	private:
		std::thread thread_;
		cv::Mat debugFrame_;
		boost::tuple<bool, boost::tuple<int, int>, boost::tuple<int, int>, boost::tuple<int, int>> croppingData_;
		bool crop_, debug_;
		std::map<NewFrameEvent, boost::signals2::signal<void(const NewFrameEvent&, const cv::Mat&)>> signals_;
	protected:
		virtual void setCropping(boost::tuple<int, int> origin, boost::tuple<int, int> target) = 0;

		virtual void resetCropping() = 0;

		static void croppingEvent(int event, int x, int y, int flags, void* cam);
	public:
		Camera(bool crop = false, bool debug = false) : crop_(crop), debug_(debug), debugFrame_(cv::Mat(800, 800, CV_8UC3, cv::Scalar(255,0,255))), croppingData_(boost::make_tuple(false, boost::tuple<int,int>(), boost::tuple<int,int>(), boost::make_tuple(0, 0)))
		{
			if (crop)
			{
				cv::namedWindow("Crop");
				cv::setMouseCallback("Crop", &Camera::croppingEvent, this);
			} else if (debug)
				cv::namedWindow("Debug");
		}

		template <typename Observer>
		boost::signals2::connection subscribe(const NewFrameEvent& event, Observer&& observer, boost::signals2::connect_position position = boost::signals2::at_back)
		{
			return signals_[event].connect(std::forward<Observer>(observer), position);
		}

		void notify(const NewFrameEvent& event, const cv::Mat& frame)
		{
			if (event == NewFrameEvent::COLOR)
			{
				if (crop_ || debug_)
					frame.copyTo(debugFrame_);
			}
			if (!crop_)
				signals_[event](event, frame);
		}

		virtual ~Camera()
		{
			cv::destroyAllWindows();
			for (auto&& sig : signals_ | boost::adaptors::map_values) sig.disconnect_all_slots();
		}

		virtual void update() {
			if (crop_)
			{
				if (boost::get<0>(croppingData_) && (boost::get<1>(croppingData_) != boost::tuple<int,int>()) && (boost::get<2>(croppingData_) != boost::tuple<int,int>()))
					cv::rectangle(debugFrame_, cv::Point(boost::get<0>(boost::get<1>(croppingData_)), boost::get<1>(boost::get<1>(croppingData_))), cv::Point(boost::get<0>(boost::get<2>(croppingData_)), boost::get<1>(boost::get<2>(croppingData_))), cv::Scalar(0, 0, 255), 3, 8, 0);
				cv::putText(debugFrame_, "Press ENTER to submit.", cv::Point((debugFrame_.cols - cv::getTextSize("Press ENTER to submit.", cv::FONT_HERSHEY_SIMPLEX, 0.6, 3, NULL).width)/2, 25), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(255, 255, 255)); // Add dynamic resizing
				cv::imshow("Crop", debugFrame_);
				if ((cv::waitKey(1) & 0xFF) == 10)
				{
					crop_ = false;
					cv::destroyWindow("Crop");
					if (debug_)
						cv::namedWindow("Debug");
				}
			}
			if (!crop_ && debug_)
			{
				cv::imshow("Debug", debugFrame_);
				cv::waitKey(1);
			}
		}
	};

	template<typename T> class CameraObserverDecorator;

	template<typename T> class CameraObserver
	{
	protected:
		CameraObserver(Camera *cam, Space<T> *spc) : cam_(cam), spc_(spc) { }
		Camera *cam_;
		Space<T> *spc_;
		std::map<NewFrameEvent, boost::signals2::connection> con_;
		friend class CameraObserverDecorator<T>;
	public:
		CameraObserver(Camera *cam, Space<T> *spc, const NewFrameEvent& event) : cam_(cam), spc_(spc) {
			con_[event] = cam->subscribe(event, boost::bind(&CameraObserver<T>::fire, this, _1, _2));
		}

		template<typename E, typename... Events>
		CameraObserver(Camera *cam, Space<T> *spc, E event, Events... events) : cam_(cam), spc_(spc)
		{
			for (auto event : { event, [](const NewFrameEvent& event) { return event; }(std::forward<Events>(events)...) })
				con_[event] = cam->subscribe(event, boost::bind(&CameraObserver<T>::fire, this, _1, _2));
		}

		virtual ~CameraObserver()
		{
			for (auto&& con : con_ | boost::adaptors::map_values) con.disconnect();
		}

		virtual void fire(const NewFrameEvent& event, const cv::Mat& frame) = 0;
	};

	template<typename T> class CameraObserverDecorator : public CameraObserver<T>
	{
	private:
		CameraObserver<T> *component_;
	public:
		CameraObserverDecorator(CameraObserver<T> *component, const NewFrameEvent& event) : CameraObserver<T>(component->cam_, component->spc_), component_(component)
		{
			this->con_[event] = component->cam_->subscribe(event, boost::bind(&CameraObserverDecorator<T>::fire, this, _1, _2), boost::signals2::at_front);
		}

		virtual ~CameraObserverDecorator()
		{
			delete component_;
		}

		template<typename E, typename... Events>
		CameraObserverDecorator(CameraObserver<T> *component, E event, Events... events) : CameraObserver<T>(component->cam_, component->spc_), component_(component)
		{
			for (auto event : { event, [](const NewFrameEvent& event) { return event; }(std::forward<Events>(events)...) })
				this->con_[event] = component->cam_->subscribe(event, boost::bind(&CameraObserverDecorator<T>::fire, this, _1, _2), boost::signals2::at_front);
		}
	};

	void Camera::croppingEvent(int event, int x, int y, int flags, void* cam_){
		Camera* cam = (Camera*)cam_;
		if (boost::get<0>(cam->croppingData_)) {
			if (event == cv::EVENT_MOUSEMOVE) {
				boost::get<0>(boost::get<2>(cam->croppingData_)) = x;
				boost::get<1>(boost::get<2>(cam->croppingData_)) = y;
			} else if ((event == CV_EVENT_LBUTTONUP) && (boost::get<1>(cam->croppingData_) != boost::tuple<int,int>()) && (boost::get<2>(cam->croppingData_) != boost::tuple<int,int>()) && ((std::max(boost::get<0>(boost::get<1>(cam->croppingData_)), boost::get<0>(boost::get<2>(cam->croppingData_))) - std::min(boost::get<0>(boost::get<1>(cam->croppingData_)), boost::get<0>(boost::get<2>(cam->croppingData_)))) * (std::max(boost::get<1>(boost::get<1>(cam->croppingData_)), boost::get<1>(boost::get<2>(cam->croppingData_))) - std::min(boost::get<1>(boost::get<1>(cam->croppingData_)), boost::get<1>(boost::get<2>(cam->croppingData_)))) > 10))
			{
				boost::get<0>(cam->croppingData_) = false;
				cam->setCropping(boost::make_tuple(std::min(boost::get<0>(boost::get<1>(cam->croppingData_)), boost::get<0>(boost::get<2>(cam->croppingData_))) + boost::get<0>(boost::get<3>(cam->croppingData_)), std::min(boost::get<1>(boost::get<1>(cam->croppingData_)), boost::get<1>(boost::get<2>(cam->croppingData_))) + boost::get<1>(boost::get<3>(cam->croppingData_))), boost::make_tuple(std::max(boost::get<0>(boost::get<1>(cam->croppingData_)), boost::get<0>(boost::get<2>(cam->croppingData_))) + boost::get<0>(boost::get<3>(cam->croppingData_)), std::max(boost::get<1>(boost::get<1>(cam->croppingData_)), boost::get<1>(boost::get<2>(cam->croppingData_))) + boost::get<1>(boost::get<3>(cam->croppingData_))));
				boost::get<0>(boost::get<3>(cam->croppingData_)) += std::min(boost::get<0>(boost::get<1>(cam->croppingData_)), boost::get<0>(boost::get<2>(cam->croppingData_)));
				boost::get<1>(boost::get<3>(cam->croppingData_)) += std::min(boost::get<1>(boost::get<1>(cam->croppingData_)), boost::get<1>(boost::get<2>(cam->croppingData_)));
				boost::get<1>(cam->croppingData_) = boost::tuple<int,int>();
				boost::get<2>(cam->croppingData_) = boost::tuple<int,int>();
			}
		} else if (event == CV_EVENT_LBUTTONDOWN) {
			boost::get<0>(cam->croppingData_) = true;
			boost::get<0>(boost::get<1>(cam->croppingData_)) = x;
			boost::get<1>(boost::get<1>(cam->croppingData_)) = y;
		} else if (event == CV_EVENT_RBUTTONUP)
		{
			cam->croppingData_ = boost::make_tuple(false, boost::tuple<int,int>(), boost::tuple<int,int>(), boost::make_tuple(0, 0));
			cam->resetCropping();
		}
	}
}

#endif

max_stars_repo_name: tommasoturchi/SPRITS

max_issues_repo_name: tommasoturchi/SPRITS

max_forks_repo_name: tommasoturchi/SPRITS