<commit_before>/* rotating_file_logger_test.cc
   Jeremy Barnes, 31 January 2011
   Copyright (c) 2011 Datacratic.  All rights reserved.

   Tests for the endpoints.
*/

#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK

#include <boost/test/unit_test.hpp>
#include "soa/logger/file_output.h"
#include <sys/socket.h>
#include "jml/utils/guard.h"
#include "jml/arch/exception_handler.h"
#include "jml/utils/testing/watchdog.h"
#include "jml/utils/testing/fd_exhauster.h"
#include "jml/arch/timers.h"

using namespace std;
using namespace ML;
using namespace Datacratic;

BOOST_AUTO_TEST_CASE( test_rotating_file_logger )
{
    vector<string> filesOpened;

    ML::Call_Guard guard([&] () { for (auto file: filesOpened) unlink(file.c_str());});

    RotatingFileOutput logger;

    int numLinesWritten = 0;

    logger.onPreFileOpen = [&] (string filename)
        {
            cerr << "opening file " << filename << endl;
            filesOpened.push_back(filename);
        };

    logger.onPostFileOpen = [&] (string filename)
        {
            cerr << "closing file " << filename << endl;
        };

    logger.open("tmp/file-logger-%F-%T.log.gz", "2s");

    for (unsigned i = 0;  i < 60;  ++i) {
        logger.logMessage("HELLO", "This is a message " + numLinesWritten);
        ++numLinesWritten;
        ML::sleep(0.1);
    }

    logger.close();

    BOOST_CHECK_GT(filesOpened.size(), 3);
    BOOST_CHECK_LT(filesOpened.size(), 5);

    int totalLines = 0;

    for (auto file: filesOpened) {
        filter_istream stream(file);
        while (stream) {
            string line;
            getline(stream, line);

            if (line != "")
                ++totalLines;
        }
    }

    BOOST_CHECK_EQUAL(totalLines, numLinesWritten);
}

<commit_msg>made rotating_file_logger_test less sensitive to machine being under load and timing issues<commit_after>/* rotating_file_logger_test.cc
   Jeremy Barnes, 31 January 2011
   Copyright (c) 2011 Datacratic.  All rights reserved.

   Tests for the endpoints.
*/

#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK

#include <boost/test/unit_test.hpp>
#include "soa/logger/file_output.h"
#include <sys/socket.h>
#include "jml/utils/guard.h"
#include "jml/arch/exception_handler.h"
#include "jml/utils/testing/watchdog.h"
#include "jml/utils/testing/fd_exhauster.h"
#include "jml/arch/timers.h"

using namespace std;
using namespace ML;
using namespace Datacratic;

BOOST_AUTO_TEST_CASE( test_rotating_file_logger )
{
    vector<string> filesOpened;

    ML::Call_Guard guard([&] () { for (auto file: filesOpened) unlink(file.c_str());});

    RotatingFileOutput logger;

    int numLinesWritten = 0;

    logger.onPreFileOpen = [&] (string filename)
        {
            cerr << "opening file " << filename << endl;
            filesOpened.push_back(filename);
        };

    logger.onPostFileOpen = [&] (string filename)
        {
            cerr << "closing file " << filename << endl;
        };

    logger.open("tmp/file-logger-%F-%T.log.gz", "2s");

    for (unsigned i = 0;  i < 60;  ++i) {
        logger.logMessage("HELLO", "This is a message " + numLinesWritten);
        ++numLinesWritten;
        ML::sleep(0.1);
    }

    logger.close();

    BOOST_CHECK_GT(filesOpened.size(), 3);
    BOOST_CHECK_LE(filesOpened.size(), 6);

    int totalLines = 0;

    for (auto file: filesOpened) {
        filter_istream stream(file);
        while (stream) {
            string line;
            getline(stream, line);

            if (line != "")
                ++totalLines;
        }
    }

    BOOST_CHECK_EQUAL(totalLines, numLinesWritten);
}

<|endoftext|>


<commit_before>#include "length_framed_unbuffered_connection.hpp"

#include <array>

#include <boost/asio/write.hpp>
#include <boost/asio/read.hpp>

#include "byte_order.hpp"
#include "check.hpp"

namespace riak {

namespace ph = std::placeholders;
namespace asio = boost::asio;
namespace ip = boost::asio::ip;

length_framed_unbuffered_connection::length_framed_unbuffered_connection(
    boost::asio::io_service& io_service,
    const std::vector<boost::asio::ip::tcp::endpoint>& endpoints)
    : io_service_{io_service},
      socket_{io_service},
      endpoints_{endpoints} {}

void length_framed_unbuffered_connection::send_and_consume_request(
    request& new_request) {
  current_request_ = new_request;
  if (!socket_.is_open()) {
    reconnect(std::bind(&self_type::send_current_request, this));
  } else {
    send_current_request();
  }
}

void length_framed_unbuffered_connection::send_current_request() {
  request_length_ = current_request_.message.size();
  request_length_ = riak::byte_order::host_to_network_long(request_length_);
  std::array<boost::asio::const_buffer, 2> buffers = {
      {asio::const_buffer(reinterpret_cast<uint8_t*>(&request_length_), 4),
       asio::buffer(current_request_.message.data(),
                    current_request_.message.size())}};

  auto callback =
      std::bind(&self_type::wait_for_response, this, ph::_1, ph::_2);

  asio::async_write(socket_, buffers, callback);
}

template <class Handler>
void length_framed_unbuffered_connection::reconnect(Handler on_connection,
                                                    size_t endpoint_index) {
  RIAKPP_CHECK_LT(endpoint_index, endpoints_.size());

  if (socket_.is_open()) socket_.close();
  socket_.async_connect(
      endpoints_[endpoint_index],
      [this, endpoint_index, on_connection](boost::system::error_code error) {
        if (error) {
          if (endpoint_index == endpoints_.size() - 1) {
            if (socket_.is_open()) socket_.close();
            fail(error);
          } else {
            reconnect(on_connection, endpoint_index + 1);
          }
        } else {
          on_connection();
        }
      });
}

void length_framed_unbuffered_connection::wait_for_response(
    boost::system::error_code error, size_t) {
  std::string().swap(current_request_.message);
  if (error) {
    fail(error);
    return;
  }
  auto length_buffer = asio::buffer(
      reinterpret_cast<uint8_t*>(&response_length_), sizeof(response_length_));
  auto callback =
      std::bind(&self_type::wait_for_response_body, this, ph::_1, ph::_2);
  asio::async_read(socket_, length_buffer, callback);
}

void length_framed_unbuffered_connection::wait_for_response_body(
    boost::system::error_code error, size_t) {
  if (error) {
    fail(error);
    return;
  }
  auto callback = std::bind(&self_type::on_response, this, ph::_1, ph::_2);

  response_length_ = riak::byte_order::network_to_host_long(response_length_);
  response_.resize(response_length_);
  auto response_buffer = asio::buffer(&response_[0], response_length_);
  asio::async_read(socket_, response_buffer, callback);
}

void length_framed_unbuffered_connection::on_response(
    boost::system::error_code error, size_t) {
  if (error) {
    fail(error);
    return;
  }

  if (current_request_.on_response) {
    auto response_closure = std::bind(current_request_.on_response,
                                      std::move(response_), std::error_code{});
    reset();
    io_service_.dispatch(response_closure);
  }
}

void length_framed_unbuffered_connection::fail(
    boost::system::error_code error) {
  // Convert boost::system_error to std::system_error.
  fail(std::make_error_code(static_cast<std::errc>(error.value())));
}

void length_framed_unbuffered_connection::fail(std::error_code error) {
  if (current_request_.on_response) {
    auto callback =
        std::bind(current_request_.on_response, std::string{}, error);
    io_service_.dispatch(callback);
  } else {
    reset();
    if (socket_.is_open()) socket_.close();
  }
}

void length_framed_unbuffered_connection::reset() {
  current_request_.reset();
  std::string().swap(response_);
  response_length_ = request_length_ = 0;
}

}  // namespace riak
<commit_msg>minor naming inconsistency in lfb<commit_after>#include "length_framed_unbuffered_connection.hpp"

#include <array>

#include <boost/asio/write.hpp>
#include <boost/asio/read.hpp>

#include "byte_order.hpp"
#include "check.hpp"

namespace riak {

namespace ph = std::placeholders;
namespace asio = boost::asio;
namespace ip = boost::asio::ip;

length_framed_unbuffered_connection::length_framed_unbuffered_connection(
    boost::asio::io_service& io_service,
    const std::vector<boost::asio::ip::tcp::endpoint>& endpoints)
    : io_service_{io_service},
      socket_{io_service},
      endpoints_{endpoints} {}

void length_framed_unbuffered_connection::send_and_consume_request(
    request& new_request) {
  current_request_ = new_request;
  if (!socket_.is_open()) {
    reconnect(std::bind(&self_type::send_current_request, this));
  } else {
    send_current_request();
  }
}

void length_framed_unbuffered_connection::send_current_request() {
  request_length_ = current_request_.message.size();
  request_length_ = riak::byte_order::host_to_network_long(request_length_);
  std::array<boost::asio::const_buffer, 2> buffers = {
      {asio::const_buffer(reinterpret_cast<uint8_t*>(&request_length_), 4),
       asio::buffer(current_request_.message.data(),
                    current_request_.message.size())}};

  auto callback =
      std::bind(&self_type::wait_for_response, this, ph::_1, ph::_2);

  asio::async_write(socket_, buffers, callback);
}

template <class Handler>
void length_framed_unbuffered_connection::reconnect(Handler on_connection,
                                                    size_t endpoint_index) {
  RIAKPP_CHECK_LT(endpoint_index, endpoints_.size());

  if (socket_.is_open()) socket_.close();
  socket_.async_connect(
      endpoints_[endpoint_index],
      [this, endpoint_index, on_connection](boost::system::error_code error) {
        if (error) {
          if (endpoint_index == endpoints_.size() - 1) {
            if (socket_.is_open()) socket_.close();
            fail(error);
          } else {
            reconnect(on_connection, endpoint_index + 1);
          }
        } else {
          on_connection();
        }
      });
}

void length_framed_unbuffered_connection::wait_for_response(
    boost::system::error_code error, size_t) {
  std::string().swap(current_request_.message);
  if (error) {
    fail(error);
    return;
  }
  auto length_buffer = asio::buffer(
      reinterpret_cast<uint8_t*>(&response_length_), sizeof(response_length_));
  auto callback =
      std::bind(&self_type::wait_for_response_body, this, ph::_1, ph::_2);
  asio::async_read(socket_, length_buffer, callback);
}

void length_framed_unbuffered_connection::wait_for_response_body(
    boost::system::error_code error, size_t) {
  if (error) {
    fail(error);
    return;
  }
  auto callback = std::bind(&self_type::on_response, this, ph::_1, ph::_2);

  response_length_ = riak::byte_order::network_to_host_long(response_length_);
  response_.resize(response_length_);
  auto response_buffer = asio::buffer(&response_[0], response_length_);
  asio::async_read(socket_, response_buffer, callback);
}

void length_framed_unbuffered_connection::on_response(
    boost::system::error_code error, size_t) {
  if (error) {
    fail(error);
    return;
  }

  if (current_request_.on_response) {
    auto response_closure = std::bind(current_request_.on_response,
                                      std::move(response_), std::error_code{});
    reset();
    io_service_.dispatch(response_closure);
  }
}

void length_framed_unbuffered_connection::fail(
    boost::system::error_code error) {
  // Convert boost::system_error to std::system_error.
  fail(std::make_error_code(static_cast<std::errc>(error.value())));
}

void length_framed_unbuffered_connection::fail(std::error_code error) {
  if (current_request_.on_response) {
    auto response_closure =
        std::bind(current_request_.on_response, std::string{}, error);
    io_service_.dispatch(response_closure);
  } else {
    reset();
    if (socket_.is_open()) socket_.close();
  }
}

void length_framed_unbuffered_connection::reset() {
  current_request_.reset();
  std::string().swap(response_);
  response_length_ = request_length_ = 0;
}

}  // namespace riak
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// limitations under the License.

#pragma once

#include <array>
#include <cstdint>
#include <limits>
#include <memory>
#include <utility>

namespace polymorphic {
	namespace detail {

		// We have a lot of intermediate functions. We want to make sure that we forward
		// the parameters correctly. For non-reference parameters, we always move them.
		template <typename T> struct fwd_helper { using type = T&&; };
		template <typename T> struct fwd_helper<T&> { using type = T&; };
		template <typename T> struct fwd_helper<T&&> { using type = T&&; };

		template <typename T, typename U> decltype(auto) fwd(U&& u) {
			return static_cast<typename fwd_helper<T>::type>(u);
		}

		struct clone {};

		struct holder {
			void* ptr;
			virtual ~holder() {}
		};

		template <typename T> struct holder_imp : holder {
			T t_;
			holder_imp(T t) : t_(std::move(t)) { ptr = &t_; }
		};

		template <typename T> std::unique_ptr<holder> poly_extend(clone, const T& t) {
			return std::make_unique<holder_imp<T>>(t);
		}

		template <typename T> using ptr = T*;

		template <typename T> struct type {};

		template<typename T, typename Signature>
		struct trampoline;

		template<typename T, typename Return, typename Method, typename... Parameters>
		struct trampoline<T, Return(Method, Parameters...)> {
			static auto jump(void* t, Parameters... parameters) -> Return {
				return poly_extend(Method{},
					*static_cast<T*>(t),
					fwd<Parameters>(parameters)...);
			}
		};

		template<typename T, typename Return, typename Method, typename... Parameters>
		struct trampoline<T, Return(Method, Parameters...)const> {
			static auto jump(const void* t, Parameters... parameters) ->Return {
				return poly_extend(Method{},
					*static_cast<const T*>(t),
					fwd<Parameters>(parameters)...);
			}
		};

		using vtable_fun = ptr<void()>;

		template<typename T, typename... Signatures>
		inline const vtable_fun vtable_entries[] = { reinterpret_cast<vtable_fun>(trampoline<T,Signatures>::jump)... };

		template <size_t I, typename Signature> struct vtable_caller;

		template <size_t I, typename Method, typename Return, typename... Parameters>
		struct vtable_caller<I, Return(Method, Parameters...)> {

			static decltype(auto) call_imp(const vtable_fun* vt,
				Method,
				void* t, Parameters... parameters) {
				return reinterpret_cast<fun_ptr>(vt[I])(
					t, fwd<Parameters>(parameters)...);
			}

			static constexpr auto get_index(type<Return(Method, Parameters...)>) { return I; }

			using is_const = std::false_type;
			using fun_ptr = ptr<Return(void*, Parameters...)>;
		};

		template <size_t I, typename Method, typename Return, typename... Parameters>
		struct vtable_caller<I, Return(Method, Parameters...) const> {

			static decltype(auto) call_imp(const vtable_fun* vt,
				Method,
				const void* t, Parameters... parameters) {
				return reinterpret_cast<fun_ptr>(vt[I])(
					t, fwd<Parameters>(parameters)...);
			}

			static constexpr auto get_index(type<Return(Method, Parameters...)const>) { return I; }

			using is_const = std::true_type;
			using fun_ptr = ptr<Return(const void*, Parameters...)>;
		};

		template <typename Sequence, typename... Signatures> struct vtable_imp;

		template<typename OtherImp, typename... Signatures>
		static constexpr int get_offset() {
			constexpr std::array<int, sizeof...(Signatures)> ar{ static_cast<int>(OtherImp::get_index(type<Signatures>{}))... };
			auto first = ar[0];
			auto previous = first;
			for (int i = 1; i < ar.size(); ++i) {
				if (ar[i] != previous + 1) {
					return -1;
				}
				previous = ar[i];
			}
			return first;
		}

		template <size_t... I, typename... Signatures>
		struct vtable_imp<std::index_sequence<I...>, Signatures...>
			: vtable_caller<I, Signatures>... {
			using vtable_caller<I,Signatures>::call_imp...;
			using vtable_caller<I,Signatures>::get_index...;

			static constexpr bool all_const() {
				return std::conjunction_v<typename vtable_caller<I,Signatures>::is_const...>;
			}

			template <typename T>
			vtable_imp(type<T> t) : vptr_(&vtable_entries<T, Signatures...>[0]) {}

			const vtable_fun* vptr_;

			template <typename OtherSequence, typename... OtherSignatures>
			vtable_imp(const vtable_imp<OtherSequence, OtherSignatures...>& other)
				: vptr_(other.vptr_ + get_offset<vtable_imp<OtherSequence, OtherSignatures...>, Signatures...>())
			{
				static_assert(get_offset<vtable_imp<OtherSequence, OtherSignatures...>, Signatures...>() != -1);
			}

			vtable_imp(const vtable_imp&) = default;

			template <typename VoidType, typename Method, typename... Parameters>
			decltype(auto) call(Method method, VoidType t,
				Parameters&&... parameters) const {
				return vtable_imp::call_imp(vptr_, method, t,
					std::forward<Parameters>(parameters)...);
			}
		};

		template <typename... Signatures>
		using vtable =
			vtable_imp<std::make_index_sequence<sizeof...(Signatures)>, Signatures...>;

		template <typename T> std::false_type is_vtable(const T*);

		template <typename Sequence, typename... Signatures>
		std::true_type is_vtable(const vtable_imp<Sequence, Signatures...>&);

		template <typename T, typename = std::void_t<>>
		struct is_polymorphic : std::false_type {};

		template <typename T>
		struct is_polymorphic<
			T, std::void_t<decltype(std::declval<const T&>().get_vtable())>>
			: decltype(is_vtable(std::declval<const T&>().get_vtable())) {};

	} // namespace detail

	template <typename... Signatures> class ref {
		using vtable_t = detail::vtable<Signatures...>;

		vtable_t vt_;
		std::conditional_t<vtable_t::all_const(), const void*, void*> t_;

	public:
		template <typename T>
		ref(T& t) : ref(t, detail::is_polymorphic<std::decay_t<T>>{}) {}

		template<typename T>
		ref(T& t, std::false_type) : vt_(detail::type<std::decay_t<T>>()), t_(&t) {}

		template<typename Poly>
		ref(Poly& other, std::true_type) : vt_(other.get_vtable()), t_(other.get_ptr()) {

		}

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

		const vtable_t& get_vtable() const { return vt_; }

		auto get_ptr() const { return t_; }

		template <typename Method, typename... Parameters>
		decltype(auto) call(Parameters&&... parameters) const {
			return vtable_t::call_imp(vt_.vptr_,Method{}, t_,
				std::forward<Parameters>(parameters)...);
		}
	};

	using copyable = std::unique_ptr<detail::holder>(detail::clone) const;

	namespace detail {

		template <bool all_const, typename... Signatures> class object_imp {
			using vtable_t = const detail::vtable<Signatures...>;

			vtable_t vt_;
			std::unique_ptr<holder> t_;

		public:
			const auto& get_vtable() const { return vt_; }
			template <typename T, typename = std::enable_if_t<
				!detail::is_polymorphic<std::decay_t<T>>::value>>
				object_imp(T t)
				: vt_(detail::type<T>{}),
				t_(std::make_unique<detail::holder_imp<T>>(std::move(t))) {}

			template <typename Poly, typename = std::enable_if_t<detail::is_polymorphic<
				std::decay_t<Poly>>::value>>
				object_imp(const Poly& other)
				: vt_(other.get_vtable()),
				t_(other ? other.template call<detail::clone>() : nullptr) {}

			object_imp(const object_imp& other)
				: vt_{ other.get_vtable() },
				t_(other ? other.call<detail::clone>() : nullptr) {}

			object_imp(object_imp&&) = default;

			object_imp& operator=(object_imp&&) = default;

			object_imp& operator=(const object_imp& other) { (*this) = ref(other); }

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

			void* get_ptr() { return t_ ? t_->ptr : nullptr; }
			const void* get_ptr() const { return t_ ? t_->ptr : nullptr; }

			template <typename Method, typename... Parameters>
			decltype(auto) call(Parameters&&... parameters) {
				return vt_.call(Method{}, get_ptr(),
					std::forward<Parameters>(parameters)...);
			}

			template <typename Method, typename... Parameters>
			decltype(auto) call(Parameters&&... parameters) const {
				return vt_.call(Method{}, get_ptr(),
					std::forward<Parameters>(parameters)...);
			}
		};

		template <typename... Signatures> class object_imp<true, Signatures...> {
			using vtable_t = const detail::vtable<Signatures...>;

			vtable_t vt_;
			std::shared_ptr<const holder> t_;

		public:
			const auto& get_vtable() const { return vt_; }
			template <typename T, typename = std::enable_if_t<
				!detail::is_polymorphic<std::decay_t<T>>::value>>
				object_imp(T t)
				: vt_(detail::type<T>{}),
				t_(std::make_shared<holder_imp<T>>(std::move(t))) {}

			template <typename Poly, typename = std::enable_if_t<detail::is_polymorphic<
				std::decay_t<Poly>>::value>>
				object_imp(const Poly& other)
				: vt_(other.get_vtable()),
				t_(other ? other.template call<detail::clone>() : nullptr) {}

			template <typename... OtherSignatures>
			object_imp(const object_imp<true, OtherSignatures...>& other)
				: vt_(other.get_vtable()), t_(other.t_) {}

			object_imp(const object_imp&) = default;

			object_imp(object_imp&&) = default;

			object_imp& operator=(object_imp&&) = default;

			object_imp& operator=(const object_imp&) = default;

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

			const void* get_ptr() const { return t_ ? t_->ptr : nullptr; }

			template <typename Method, typename... Parameters>
			decltype(auto) call(Parameters&&... parameters) const {
				return vt_.call(Method{}, get_ptr(),
					std::forward<Parameters>(parameters)...);
			}
		};

	} // namespace detail

	template <typename... Signatures>
	using object = detail::object_imp<detail::vtable<Signatures...>::all_const(),
		Signatures..., copyable >;

} // namespace polymorphic
<commit_msg>WIP simplifying polymorphic<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// limitations under the License.

#pragma once

#include <array>
#include <cstdint>
#include <limits>
#include <memory>
#include <utility>

namespace polymorphic {
	namespace detail {

		// We have a lot of intermediate functions. We want to make sure that we forward
		// the parameters correctly. For non-reference parameters, we always move them.
		template <typename T> struct fwd_helper { using type = T&&; };
		template <typename T> struct fwd_helper<T&> { using type = T&; };
		template <typename T> struct fwd_helper<T&&> { using type = T&&; };

		template <typename T, typename U> decltype(auto) fwd(U&& u) {
			return static_cast<typename fwd_helper<T>::type>(u);
		}

		struct clone {};

		struct holder {
			void* ptr;
			virtual ~holder() {}
		};

		template <typename T> struct holder_imp : holder {
			T t_;
			holder_imp(T t) : t_(std::move(t)) { ptr = &t_; }
		};

		template <typename T> std::unique_ptr<holder> poly_extend(clone, const T& t) {
			return std::make_unique<holder_imp<T>>(t);
		}

		template <typename T> using ptr = T*;

		template <typename T> struct type {};

		template<typename T, typename Signature>
		struct trampoline;

		template<typename T, typename Return, typename Method, typename... Parameters>
		struct trampoline<T, Return(Method, Parameters...)> {
			static auto jump(void* t, Parameters... parameters) -> Return {
				return poly_extend(Method{},
					*static_cast<T*>(t),
					fwd<Parameters>(parameters)...);
			}
		};

		template<typename T, typename Return, typename Method, typename... Parameters>
		struct trampoline<T, Return(Method, Parameters...)const> {
			static auto jump(const void* t, Parameters... parameters) ->Return {
				return poly_extend(Method{},
					*static_cast<const T*>(t),
					fwd<Parameters>(parameters)...);
			}
		};

		using vtable_fun = ptr<void()>;

		template<typename T, typename... Signatures>
		inline const vtable_fun vtable_entries[] = { reinterpret_cast<vtable_fun>(trampoline<T,Signatures>::jump)... };

		template <size_t I, typename Signature> struct vtable_caller;

		template <size_t I, typename Method, typename Return, typename... Parameters>
		struct vtable_caller<I, Return(Method, Parameters...)> {

			static decltype(auto) call_imp(const vtable_fun* vt,
				Method,
				void* t, Parameters... parameters) {
				return reinterpret_cast<fun_ptr>(vt[I])(
					t, fwd<Parameters>(parameters)...);
			}

			static constexpr auto get_index(type<Return(Method, Parameters...)>) { return I; }

			using is_const = std::false_type;
			using fun_ptr = ptr<Return(void*, Parameters...)>;
		};

		template <size_t I, typename Method, typename Return, typename... Parameters>
		struct vtable_caller<I, Return(Method, Parameters...) const> {

			static decltype(auto) call_imp(const vtable_fun* vt,
				Method,
				const void* t, Parameters... parameters) {
				return reinterpret_cast<fun_ptr>(vt[I])(
					t, fwd<Parameters>(parameters)...);
			}

			static constexpr auto get_index(type<Return(Method, Parameters...)const>) { return I; }

			using is_const = std::true_type;
			using fun_ptr = ptr<Return(const void*, Parameters...)>;
		};

		template <typename Sequence, typename... Signatures> struct vtable_imp;

		template<typename OtherImp, typename... Signatures>
		static constexpr int get_offset() {
			constexpr std::array<int, sizeof...(Signatures)> ar{ static_cast<int>(OtherImp::get_index(type<Signatures>{}))... };
			auto first = ar[0];
			auto previous = first;
			for (int i = 1; i < ar.size(); ++i) {
				if (ar[i] != previous + 1) {
					return -1;
				}
				previous = ar[i];
			}
			return first;
		}

		template <size_t... I, typename... Signatures>
		struct vtable_imp<std::index_sequence<I...>, Signatures...>
			: vtable_caller<I, Signatures>... {
			using vtable_caller<I, Signatures>::call_imp...;
			using vtable_caller<I, Signatures>::get_index...;

			static constexpr bool all_const() {
				return std::conjunction_v<typename vtable_caller<I, Signatures>::is_const...>;
			}

			template <typename T>
			vtable_imp(type<T> t) : vptr_(&vtable_entries<T, Signatures...>[0]) {}

			const vtable_fun* vptr_;

			template <typename OtherSequence, typename... OtherSignatures>
			vtable_imp(const vtable_imp<OtherSequence, OtherSignatures...>& other)
				: vptr_(other.vptr_ + get_offset<vtable_imp<OtherSequence, OtherSignatures...>, Signatures...>())
			{
				static_assert(get_offset<vtable_imp<OtherSequence, OtherSignatures...>, Signatures...>() != -1);
			}

			vtable_imp(const vtable_imp&) = default;

			template <typename VoidType, typename Method, typename... Parameters>
			decltype(auto) call(Method method, VoidType t,
				Parameters&&... parameters) const {
				return vtable_imp::call_imp(vptr_, method, t,
					std::forward<Parameters>(parameters)...);
			}
		};

		template <typename... Signatures>
		using vtable =
			vtable_imp<std::make_index_sequence<sizeof...(Signatures)>, Signatures...>;

		template <typename T>
		struct is_polymorphic : std::false_type {};

		template<typename Sequence, typename... Signatures>
		class ref_impl;

		template<typename Sequence, typename... Signatures>
		class obj_impl;

		template<typename Sequence, typename... Signatures>
		struct is_polymorphic<ref_impl<Sequence, Signatures...>> :std::true_type {};

		template<typename Sequence, typename... Signatures>
		struct is_polymorphic<obj_impl<Sequence, Signatures...>> :std::true_type {};

		template <size_t... I, typename... Signatures>
		class ref_impl<std::index_sequence<I...>, Signatures...> :private vtable_caller<I, Signatures>... {

			const detail::vtable_fun* vptr_;
			std::conditional_t<std::conjunction_v<typename vtable_caller<I, Signatures>::is_const...>, const void*, void*> t_;

		public:
			template <typename T>
			ref_impl(T& t) : ref_impl(t, detail::is_polymorphic<std::decay_t<T>>{}) {}

			template<typename T>
			ref_impl(T& t, std::false_type) : vptr_(&detail::vtable_entries<std::decay_t<T>,Signatures...>[0]), t_(&t) {}

			template<typename Poly>
			ref_impl(Poly& other, std::true_type) : vptr_(other.vptr_ + get_offset<Poly,Signatures...>()), t_(other.get_ptr()) {
				static_assert(get_offset<Poly, Signatures...>() != -1);
			}

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

			auto get_ptr() const { return t_; }

			template <typename Method, typename... Parameters>
			decltype(auto) call(Parameters&&... parameters) const {
				return this->call_imp(vptr_, Method{}, t_,
					std::forward<Parameters>(parameters)...);
			}
		};

	} // namespace detail

	template<typename... Signatures>
	using ref = detail::ref_impl < std::make_index_sequence<sizeof...(Signatures)>, Signatures...>;

	using copyable = std::unique_ptr<detail::holder>(detail::clone) const;

	namespace detail {

		template <bool all_const, typename... Signatures> class object_imp {
			using vtable_t = const detail::vtable<Signatures...>;

			vtable_t vt_;
			std::unique_ptr<holder> t_;

		public:
			const auto& get_vtable() const { return vt_; }
			template <typename T, typename = std::enable_if_t<
				!detail::is_polymorphic<std::decay_t<T>>::value>>
				object_imp(T t)
				: vt_(detail::type<T>{}),
				t_(std::make_unique<detail::holder_imp<T>>(std::move(t))) {}

			template <typename Poly, typename = std::enable_if_t<detail::is_polymorphic<
				std::decay_t<Poly>>::value>>
				object_imp(const Poly& other)
				: vt_(other.get_vtable()),
				t_(other ? other.template call<detail::clone>() : nullptr) {}

			object_imp(const object_imp& other)
				: vt_{ other.get_vtable() },
				t_(other ? other.call<detail::clone>() : nullptr) {}

			object_imp(object_imp&&) = default;

			object_imp& operator=(object_imp&&) = default;

			object_imp& operator=(const object_imp& other) { (*this) = ref<Signatures...>(other); }

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

			void* get_ptr() { return t_ ? t_->ptr : nullptr; }
			const void* get_ptr() const { return t_ ? t_->ptr : nullptr; }

			template <typename Method, typename... Parameters>
			decltype(auto) call(Parameters&&... parameters) {
				return vt_.call(Method{}, get_ptr(),
					std::forward<Parameters>(parameters)...);
			}

			template <typename Method, typename... Parameters>
			decltype(auto) call(Parameters&&... parameters) const {
				return vt_.call(Method{}, get_ptr(),
					std::forward<Parameters>(parameters)...);
			}
		};

		template <typename... Signatures> class object_imp<true, Signatures...> {
			using vtable_t = const detail::vtable<Signatures...>;

			vtable_t vt_;
			std::shared_ptr<const holder> t_;

		public:
			const auto& get_vtable() const { return vt_; }
			template <typename T, typename = std::enable_if_t<
				!detail::is_polymorphic<std::decay_t<T>>::value>>
				object_imp(T t)
				: vt_(detail::type<T>{}),
				t_(std::make_shared<holder_imp<T>>(std::move(t))) {}

			template <typename Poly, typename = std::enable_if_t<detail::is_polymorphic<
				std::decay_t<Poly>>::value>>
				object_imp(const Poly& other)
				: vt_(other.get_vtable()),
				t_(other ? other.template call<detail::clone>() : nullptr) {}

			template <typename... OtherSignatures>
			object_imp(const object_imp<true, OtherSignatures...>& other)
				: vt_(other.get_vtable()), t_(other.t_) {}

			object_imp(const object_imp&) = default;

			object_imp(object_imp&&) = default;

			object_imp& operator=(object_imp&&) = default;

			object_imp& operator=(const object_imp&) = default;

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

			const void* get_ptr() const { return t_ ? t_->ptr : nullptr; }

			template <typename Method, typename... Parameters>
			decltype(auto) call(Parameters&&... parameters) const {
				return vt_.call(Method{}, get_ptr(),
					std::forward<Parameters>(parameters)...);
			}
		};

		template<bool all_const,typename... Signatures>
		struct is_polymorphic<object_imp<all_const,Signatures...>> :std::true_type {};

	} // namespace detail

	template <typename... Signatures>
	using object = detail::object_imp<detail::vtable<Signatures...>::all_const(),
		Signatures..., copyable >;

} // namespace polymorphic
<|endoftext|>


<commit_before>#include "static_controller.hpp"
#include "file_system.hpp"
#include "content_type_map.hpp"
#include "router.hpp"
#include "settings.hpp"
#include "log.hpp"

namespace msrv {

StaticController::StaticController(
    Request* request, const Path& targetDir, const ContentTypeMap& contentTypes)
    : ControllerBase(request), targetDir_(targetDir), contentTypes_(contentTypes)
{
}

StaticController::~StaticController() = default;

std::string StaticController::getNormalizedPath()
{
    const auto& fullPath = request()->path;

    if (fullPath.empty())
        throw InvalidRequestException("empty request path");

    auto isDirectory = fullPath.back() == '/';
    auto path = optionalParam<std::string>("path");

    if (!path || path->empty())
    {
        if (isDirectory)
            return "index.html";
        else
            return std::string();
    }
    else
    {
        if (isDirectory)
            return *path + "/index.html";
        else
            return *path;
    }
}

ResponsePtr StaticController::redirectToDirectory()
{
    return Response::temporaryRedirect(request()->path + "/");
}

ResponsePtr StaticController::getFile()
{
    auto requestPath = getNormalizedPath();
    if (requestPath.empty())
        return redirectToDirectory();

    auto filePath = (targetDir_ / pathFromUtf8(requestPath)).lexically_normal();

    if (!isSubpath(targetDir_.native(), filePath.native()))
        return Response::notFound();

    auto handle = file_io::open(filePath);
    if (!handle) {
        return Response::notFound();
    }

    auto info = file_io::queryInfo(handle.get());

    switch (info.type) {
        case FileType::REGULAR:
        {
            const auto& contentType = contentTypes_.byFilePath(filePath);
            return Response::file(std::move(filePath), std::move(handle), std::move(info), contentType);
        }

        case FileType::DIRECTORY:
            return redirectToDirectory();

        default:
            return Response::notFound();
    }
}

void StaticController::defineRoutes(
    Router* router,
    WorkQueue* workQueue,
    SettingsDataPtr settings,
    const ContentTypeMap& contentTypes)
{
    for (auto& kv : settings->urlMappings) {
        if (kv.first.empty() || kv.first == "/") {
            logError("root url mapping is not allowed, use 'webRoot' instead");
            continue;
        }

        if (kv.second.empty()) {
            logError("url mapping '%s' has empty target", kv.first.c_str());
            continue;
        }

        logInfo("using url mapping '%s' -> '%s'", kv.first.c_str(), kv.second.c_str());
        defineRoutes(router, workQueue, kv.first, kv.second, contentTypes);
    }

    if (!settings->webRoot.empty())
        defineRoutes(router, workQueue, "/", settings->webRoot, contentTypes);
}

void StaticController::defineRoutes(
    Router* router,
    WorkQueue* workQueue,
    const std::string& urlPrefix,
    const std::string& targetDir,
    const ContentTypeMap& contentTypes)
{
    if (urlPrefix.find(':') != std::string::npos) {
        logError("url mapping '%s' contains reserved character ':'", urlPrefix.c_str());
        return;
    }

    std::string prefix;

    if (urlPrefix.empty() || urlPrefix.front() != '/')
        prefix = "/" + urlPrefix;
    else
        prefix = urlPrefix;

    if (prefix.back() != '/')
        prefix.push_back('/');

    auto target = pathFromUtf8(targetDir).lexically_normal();
    if (!target.is_absolute()) {
        logError("url mapping '%s' target should be absolute, got '%s'", urlPrefix.c_str(), targetDir.c_str());
        return;
    }

    auto routes = router->defineRoutes<StaticController>();

    routes.createWith([=](Request* request)
    {
        return new StaticController(request, target, contentTypes);
    });

    routes.useWorkQueue(workQueue);

    routes.get(prefix, &StaticController::getFile);
    routes.get(prefix + ":path*", &StaticController::getFile);
}

}
<commit_msg>server/static_controller: don't try to open directories<commit_after>#include "static_controller.hpp"
#include "file_system.hpp"
#include "content_type_map.hpp"
#include "router.hpp"
#include "settings.hpp"
#include "log.hpp"

namespace msrv {

StaticController::StaticController(
    Request* request, const Path& targetDir, const ContentTypeMap& contentTypes)
    : ControllerBase(request), targetDir_(targetDir), contentTypes_(contentTypes)
{
}

StaticController::~StaticController() = default;

std::string StaticController::getNormalizedPath()
{
    const auto& fullPath = request()->path;

    if (fullPath.empty())
        throw InvalidRequestException("empty request path");

    auto isDirectory = fullPath.back() == '/';
    auto path = optionalParam<std::string>("path");

    if (!path || path->empty())
    {
        if (isDirectory)
            return "index.html";
        else
            return std::string();
    }
    else
    {
        if (isDirectory)
            return *path + "/index.html";
        else
            return *path;
    }
}

ResponsePtr StaticController::redirectToDirectory()
{
    return Response::temporaryRedirect(request()->path + "/");
}

ResponsePtr StaticController::getFile()
{
    auto requestPath = getNormalizedPath();
    if (requestPath.empty())
        return redirectToDirectory();

    auto filePath = (targetDir_ / pathFromUtf8(requestPath)).lexically_normal();

    if (!isSubpath(targetDir_.native(), filePath.native()))
        return Response::notFound();

    auto info = file_io::queryInfo(filePath);

    switch (info.type)
    {
        case FileType::REGULAR:
        {
            auto handle = file_io::open(filePath);
            if (!handle)
                return Response::notFound();

            const auto& contentType = contentTypes_.byFilePath(filePath);
            return Response::file(std::move(filePath), std::move(handle), std::move(info), contentType);
        }

        case FileType::DIRECTORY:
            return redirectToDirectory();

        default:
            return Response::notFound();
    }
}

void StaticController::defineRoutes(
    Router* router,
    WorkQueue* workQueue,
    SettingsDataPtr settings,
    const ContentTypeMap& contentTypes)
{
    for (auto& kv : settings->urlMappings) {
        if (kv.first.empty() || kv.first == "/") {
            logError("root url mapping is not allowed, use 'webRoot' instead");
            continue;
        }

        if (kv.second.empty()) {
            logError("url mapping '%s' has empty target", kv.first.c_str());
            continue;
        }

        logInfo("using url mapping '%s' -> '%s'", kv.first.c_str(), kv.second.c_str());
        defineRoutes(router, workQueue, kv.first, kv.second, contentTypes);
    }

    if (!settings->webRoot.empty())
        defineRoutes(router, workQueue, "/", settings->webRoot, contentTypes);
}

void StaticController::defineRoutes(
    Router* router,
    WorkQueue* workQueue,
    const std::string& urlPrefix,
    const std::string& targetDir,
    const ContentTypeMap& contentTypes)
{
    if (urlPrefix.find(':') != std::string::npos) {
        logError("url mapping '%s' contains reserved character ':'", urlPrefix.c_str());
        return;
    }

    std::string prefix;

    if (urlPrefix.empty() || urlPrefix.front() != '/')
        prefix = "/" + urlPrefix;
    else
        prefix = urlPrefix;

    if (prefix.back() != '/')
        prefix.push_back('/');

    auto target = pathFromUtf8(targetDir).lexically_normal();
    if (!target.is_absolute()) {
        logError("url mapping '%s' target should be absolute, got '%s'", urlPrefix.c_str(), targetDir.c_str());
        return;
    }

    auto routes = router->defineRoutes<StaticController>();

    routes.createWith([=](Request* request)
    {
        return new StaticController(request, target, contentTypes);
    });

    routes.useWorkQueue(workQueue);

    routes.get(prefix, &StaticController::getFile);
    routes.get(prefix + ":path*", &StaticController::getFile);
}

}
<|endoftext|>


<commit_before>#include "ImageLoader.h"
#include "RenderContext.h"
#include "GUM_AsyncTask.h"
#include <gum/Config.h>
#include "Image.h"

#include <gimg_import.h>
#include <gimg_typedef.h>
#include <gimg_pvr.h>
#include <gimg_etc2.h>
#include <bimp/FileLoader.h>
#include <bimp/BIMP_ImportStream.h>
#include <timp/TextureFormat.h>
#include <timp/TextureLoader.h>
#include <unirender/UR_RenderContext.h>

#include <stdlib.h>

namespace gum
{

ImageLoader::ImageLoader(const std::string& filepath)
	: m_filepath(filepath)
	, m_id(0)
	, m_format(0)
	, m_width(0)
	, m_height(0)
{
}

bool ImageLoader::Load()
{
	if (m_filepath.find(".ept") != std::string::npos) {
		return LoadBin();
	} else {
		return LoadRaw();
	}
}

class FileLoader : public bimp::FileLoader
{
public:
	FileLoader(const std::string& filepath, bool use_cache, void (*parser_cb)(const void* data, size_t size, void* ud), void* ud)
		: bimp::FileLoader(filepath, use_cache)
		, m_parser_cb(parser_cb)
		, m_ud(ud)
	{}

protected:
	virtual void OnLoad(bimp::ImportStream& is)
	{
		m_parser_cb(is.Stream(), is.Size(), m_ud);
	}

private:
	void (*m_parser_cb)(const void* data, size_t size, void* ud);
	void* m_ud;

}; // FileLoader

static
void _load_cb(const char* filepath, void (*unpack)(const void* data, size_t size, void* ud), void* ud)
{
	FileLoader loader(filepath, false, unpack, ud);
	loader.Load();
}

static
void _parser_cb(const void* data, size_t size, void* ud)
{
	timp::TextureLoader loader(static_cast<const char*>(data), size);
	loader.Load();

	Image* img = static_cast<Image*>(ud);
	const void* pixels = loader.GetData();
	int width = loader.GetWidth(),
		height = loader.GetHeight();
	int format = loader.GetFormat();
	switch (format)
	{
	case timp::TEXTURE_RGBA4: case timp::TEXTURE_RGBA8:
		RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
		break;
	case timp::TEXTURE_PVR2:
#if defined( __APPLE__ ) && !defined(__MACOSX)
		RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#endif
		break;
	case timp::TEXTURE_PVR4:
		{
#if defined( __APPLE__ ) && !defined(__MACOSX)
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#else
			uint8_t* uncompressed = gimg_pvr_decode(static_cast<const uint8_t*>(pixels), width, height);
			gimg_revert_y(uncompressed, width, height, GPF_RGBA);
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), uncompressed, width, height);
			free(uncompressed);
#endif
		}
		break;
	case timp::TEXTURE_ETC1:
		break;
	case timp::TEXTURE_ETC2:
		{
#ifdef __ANDROID__
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#elif defined( __APPLE__ ) && !defined(__MACOSX)
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#elif defined _WIN32
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#else
			uint8_t* uncompressed = gimg_etc2_decode(static_cast<const uint8_t*>(pixels), width, height, ETC2PACKAGE_RGBA_NO_MIPMAPS);
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), uncompressed, width, height);
			free(uncompressed);
#endif // __ANDROID__
		}
		break;
	}
	img->SetLoadFinished(true);
}

static
void _release_cb(void* ud)
{
	Image* img = static_cast<Image*>(ud);
	img->RemoveReference();
}

bool ImageLoader::AsyncLoad(int format, int width, int height, Image* img)
{
	if (m_filepath.find(".ept") == std::string::npos) {
		return false;
	}

	m_id = RenderContext::Instance()->GetImpl()->CreateTextureID(width, height, format);
	m_format = format;
	m_width = width;
	m_height = height;

	img->SetLoadFinished(false);
	img->AddReference();
	AsyncTask::Instance()->Load(m_filepath, _load_cb, _parser_cb, _release_cb, img);

	return true;
}

bool ImageLoader::LoadRaw()
{
	int w, h, fmt;
	uint8_t* pixels = gimg_import(m_filepath.c_str(), &w, &h, &fmt);
	if (!pixels) {
		return false;
	}

	if (fmt == GPF_RGBA && Config::Instance()->GetPreMulAlpha()) {
		gimg_pre_mul_alpha(pixels, w, h);
	}

	m_width = w;
	m_height = h;

	timp::TEXTURE_FORMAT tf = timp::TEXTURE_INVALID;
	switch (fmt)
	{
	case GPF_ALPHA: case GPF_LUMINANCE: case GPF_LUMINANCE_ALPHA:
		tf = timp::TEXTURE_A8;
		break;
	case GPF_RGB:
		tf = timp::TEXTURE_RGB;
		break;
	case GPF_RGBA:
		tf = timp::TEXTURE_RGBA8;
		break;
	}

	m_format = tf;
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(pixels, w, h, tf);
	free(pixels);

	return true;
}

bool ImageLoader::LoadBin()
{
	bool ret = true;

	timp::TextureLoader loader(m_filepath);
	loader.Load();

	m_format = loader.GetFormat();
	m_width  = loader.GetWidth();
	m_height = loader.GetHeight();
	switch (m_format)
	{
	case timp::TEXTURE_RGBA4: case timp::TEXTURE_RGBA8:
		m_id = RenderContext::Instance()->GetImpl()->CreateTexture(static_cast<const uint8_t*>(loader.GetData()), m_width, m_height, m_format);
		break;
	case timp::TEXTURE_PVR2:
		ret = DecodePVR2(loader.GetData());
		break;
	case timp::TEXTURE_PVR4:
		ret = DecodePVR4(loader.GetData());
		break;
	case timp::TEXTURE_ETC1:
		ret = false;
		break;
	case timp::TEXTURE_ETC2:
		ret = DecodeETC2(loader.GetData());
		break;
	}

	return ret;
}

bool ImageLoader::DecodePVR2(const void* data)
{
#if defined( __APPLE__ ) && !defined(__MACOSX)
//	int internal_format = 0;
//	internal_format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, ur::TEXTURE_PVR2);
	return true;
#else
	return false;
#endif
}

bool ImageLoader::DecodePVR4(const void* data)
{
#if defined( __APPLE__ ) && !defined(__MACOSX)
//	int internal_format = 0;
//	internal_format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, ur::TEXTURE_PVR4);
#else
	uint8_t* uncompressed = gimg_pvr_decode(static_cast<const uint8_t*>(data), m_width, m_height);
	gimg_revert_y(uncompressed, m_width, m_height, GPF_RGBA);
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(uncompressed, m_width, m_height, timp::TEXTURE_RGBA8);
	free(uncompressed);
#endif
	return true;
}

bool ImageLoader::DecodeETC2(const void* data)
{
#ifdef __ANDROID__
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, timp::TEXTURE_ETC2);
#elif defined( __APPLE__ ) && !defined(__MACOSX)
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, timp::TEXTURE_ETC2);
#elif defined _WIN32
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, timp::TEXTURE_ETC2);
#else
	uint8_t* uncompressed = gimg_etc2_decode(static_cast<const uint8_t*>(data), m_width, m_height, ETC2PACKAGE_RGBA_NO_MIPMAPS);
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(uncompressed, m_width, m_height, timp::TEXTURE_RGBA8);
	free(uncompressed);
#endif // __ANDROID__
	return true;
}

}
<commit_msg>[FIXED] etc2 on mac<commit_after>#include "ImageLoader.h"
#include "RenderContext.h"
#include "GUM_AsyncTask.h"
#include <gum/Config.h>
#include "Image.h"

#include <gimg_import.h>
#include <gimg_typedef.h>
#include <gimg_pvr.h>
#include <gimg_etc2.h>
#include <bimp/FileLoader.h>
#include <bimp/BIMP_ImportStream.h>
#include <timp/TextureFormat.h>
#include <timp/TextureLoader.h>
#include <unirender/UR_RenderContext.h>

#include <stdlib.h>

namespace gum
{

ImageLoader::ImageLoader(const std::string& filepath)
	: m_filepath(filepath)
	, m_id(0)
	, m_format(0)
	, m_width(0)
	, m_height(0)
{
}

bool ImageLoader::Load()
{
	if (m_filepath.find(".ept") != std::string::npos) {
		return LoadBin();
	} else {
		return LoadRaw();
	}
}

class FileLoader : public bimp::FileLoader
{
public:
	FileLoader(const std::string& filepath, bool use_cache, void (*parser_cb)(const void* data, size_t size, void* ud), void* ud)
		: bimp::FileLoader(filepath, use_cache)
		, m_parser_cb(parser_cb)
		, m_ud(ud)
	{}

protected:
	virtual void OnLoad(bimp::ImportStream& is)
	{
		m_parser_cb(is.Stream(), is.Size(), m_ud);
	}

private:
	void (*m_parser_cb)(const void* data, size_t size, void* ud);
	void* m_ud;

}; // FileLoader

static
void _load_cb(const char* filepath, void (*unpack)(const void* data, size_t size, void* ud), void* ud)
{
	FileLoader loader(filepath, false, unpack, ud);
	loader.Load();
}

static
void _parser_cb(const void* data, size_t size, void* ud)
{
	timp::TextureLoader loader(static_cast<const char*>(data), size);
	loader.Load();

	Image* img = static_cast<Image*>(ud);
	const void* pixels = loader.GetData();
	int width = loader.GetWidth(),
		height = loader.GetHeight();
	int format = loader.GetFormat();
	switch (format)
	{
	case timp::TEXTURE_RGBA4: case timp::TEXTURE_RGBA8:
		RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
		break;
	case timp::TEXTURE_PVR2:
#if defined( __APPLE__ ) && !defined(__MACOSX)
		RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#endif
		break;
	case timp::TEXTURE_PVR4:
		{
#if defined( __APPLE__ ) && !defined(__MACOSX)
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#else
			uint8_t* uncompressed = gimg_pvr_decode(static_cast<const uint8_t*>(pixels), width, height);
			gimg_revert_y(uncompressed, width, height, GPF_RGBA);
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), uncompressed, width, height);
			free(uncompressed);
#endif
		}
		break;
	case timp::TEXTURE_ETC1:
		break;
	case timp::TEXTURE_ETC2:
		{
#ifdef __ANDROID__
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#elif defined( __APPLE__ ) && !defined(__MACOSX)
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#elif defined _WIN32
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), pixels, width, height);
#else
			uint8_t* uncompressed = gimg_etc2_decode(static_cast<const uint8_t*>(pixels), width, height, ETC2PACKAGE_RGBA_NO_MIPMAPS);
			RenderContext::Instance()->GetImpl()->UpdateTexture(img->GetTexID(), uncompressed, width, height);
			free(uncompressed);
#endif // __ANDROID__
		}
		break;
	}
	img->SetLoadFinished(true);
}

static
void _release_cb(void* ud)
{
	Image* img = static_cast<Image*>(ud);
	img->RemoveReference();
}

bool ImageLoader::AsyncLoad(int format, int width, int height, Image* img)
{
	if (m_filepath.find(".ept") == std::string::npos) {
		return false;
	}

	int real_fmt = format;
#if defined( __APPLE__ ) && defined(__MACOSX)
	if (real_fmt == timp::TEXTURE_ETC2) {
		real_fmt = timp::TEXTURE_RGBA8;
	}
#endif

	m_id = RenderContext::Instance()->GetImpl()->CreateTextureID(width, height, real_fmt);
	m_format = format;
	m_width = width;
	m_height = height;

	img->SetLoadFinished(false);
	img->AddReference();
	AsyncTask::Instance()->Load(m_filepath, _load_cb, _parser_cb, _release_cb, img);

	return true;
}

bool ImageLoader::LoadRaw()
{
	int w, h, fmt;
	uint8_t* pixels = gimg_import(m_filepath.c_str(), &w, &h, &fmt);
	if (!pixels) {
		return false;
	}

	if (fmt == GPF_RGBA && Config::Instance()->GetPreMulAlpha()) {
		gimg_pre_mul_alpha(pixels, w, h);
	}

	m_width = w;
	m_height = h;

	timp::TEXTURE_FORMAT tf = timp::TEXTURE_INVALID;
	switch (fmt)
	{
	case GPF_ALPHA: case GPF_LUMINANCE: case GPF_LUMINANCE_ALPHA:
		tf = timp::TEXTURE_A8;
		break;
	case GPF_RGB:
		tf = timp::TEXTURE_RGB;
		break;
	case GPF_RGBA:
		tf = timp::TEXTURE_RGBA8;
		break;
	}

	m_format = tf;
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(pixels, w, h, tf);
	free(pixels);

	return true;
}

bool ImageLoader::LoadBin()
{
	bool ret = true;

	timp::TextureLoader loader(m_filepath);
	loader.Load();

	m_format = loader.GetFormat();
	m_width  = loader.GetWidth();
	m_height = loader.GetHeight();
	switch (m_format)
	{
	case timp::TEXTURE_RGBA4: case timp::TEXTURE_RGBA8:
		m_id = RenderContext::Instance()->GetImpl()->CreateTexture(static_cast<const uint8_t*>(loader.GetData()), m_width, m_height, m_format);
		break;
	case timp::TEXTURE_PVR2:
		ret = DecodePVR2(loader.GetData());
		break;
	case timp::TEXTURE_PVR4:
		ret = DecodePVR4(loader.GetData());
		break;
	case timp::TEXTURE_ETC1:
		ret = false;
		break;
	case timp::TEXTURE_ETC2:
		ret = DecodeETC2(loader.GetData());
		break;
	}

	return ret;
}

bool ImageLoader::DecodePVR2(const void* data)
{
#if defined( __APPLE__ ) && !defined(__MACOSX)
//	int internal_format = 0;
//	internal_format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, ur::TEXTURE_PVR2);
	return true;
#else
	return false;
#endif
}

bool ImageLoader::DecodePVR4(const void* data)
{
#if defined( __APPLE__ ) && !defined(__MACOSX)
//	int internal_format = 0;
//	internal_format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, ur::TEXTURE_PVR4);
#else
	uint8_t* uncompressed = gimg_pvr_decode(static_cast<const uint8_t*>(data), m_width, m_height);
	gimg_revert_y(uncompressed, m_width, m_height, GPF_RGBA);
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(uncompressed, m_width, m_height, timp::TEXTURE_RGBA8);
	free(uncompressed);
#endif
	return true;
}

bool ImageLoader::DecodeETC2(const void* data)
{
#ifdef __ANDROID__
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, timp::TEXTURE_ETC2);
#elif defined( __APPLE__ ) && !defined(__MACOSX)
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, timp::TEXTURE_ETC2);
#elif defined _WIN32
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(data, m_width, m_height, timp::TEXTURE_ETC2);
#else
	uint8_t* uncompressed = gimg_etc2_decode(static_cast<const uint8_t*>(data), m_width, m_height, ETC2PACKAGE_RGBA_NO_MIPMAPS);
	m_id = RenderContext::Instance()->GetImpl()->CreateTexture(uncompressed, m_width, m_height, timp::TEXTURE_RGBA8);
	free(uncompressed);
#endif // __ANDROID__
	return true;
}

}
<|endoftext|>


<commit_before>/*==============================================================================

  Program: 3D Slicer

  Copyright (c) 2010 Kitware Inc.

  See COPYRIGHT.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  This file was originally developed by Julien Finet, Kitware Inc.
  and was partially funded by NIH grant 3P41RR013218-12S1

==============================================================================*/

// Qt includes
#include <QDebug>
#include <QMap>
#include <QMimeData>
#include <QSharedPointer>
#include <QStack>
#include <QStringList>
#include <QVector>

// OpenIGTLinkIF GUI includes
#include "qMRMLSceneIGTLConnectorModel.h"

// qMRMLWidgets includes
#include <qMRMLSceneDisplayableModel.h>

// OpenIGTLinkIF MRML includes
#include "vtkMRMLIGTLConnectorNode.h"

// MRML includes
#include <vtkMRMLScene.h>
#include <vtkMRMLNode.h>
#include <vtkMRMLAnnotationNode.h>
#include <vtkMRMLDisplayableHierarchyNode.h>

// VTK includes
#include <vtkVariantArray.h>

//------------------------------------------------------------------------------
qMRMLSceneIGTLConnectorModel::qMRMLSceneIGTLConnectorModel(QObject *vparent)
  :qMRMLSceneDisplayableModel(vparent)
{
  this->setListenNodeModifiedEvent(true);
  this->setIDColumn(-1);
  this->setHorizontalHeaderLabels(
        QStringList() << "Name" << "Type" << "Status" << "Hostname" << "Port");
}

//------------------------------------------------------------------------------
qMRMLSceneIGTLConnectorModel::~qMRMLSceneIGTLConnectorModel()
{
}

//------------------------------------------------------------------------------
QStandardItem* qMRMLSceneIGTLConnectorModel::insertNode(vtkMRMLNode* node, QStandardItem* parent, int row)
{
  QStandardItem* insertedItem = this->Superclass::insertNode(node, parent, row);
  if (this->listenNodeModifiedEvent() &&
      node->IsA("vtkMRMLIGTLConnectorNode"))
    {
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::ConnectedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::DisconnectedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::ActivatedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::DeactivatedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    }
  return insertedItem;
}

//------------------------------------------------------------------------------
void qMRMLSceneIGTLConnectorModel::updateNodeFromItemData(vtkMRMLNode* node, QStandardItem* item)
{
  //int oldChecked = node->GetSelected();
  vtkMRMLIGTLConnectorNode* cnode = vtkMRMLIGTLConnectorNode::SafeDownCast(node);
  if (!cnode)
    {
    return;
    }
  this->qMRMLSceneDisplayableModel::updateNodeFromItemData(node, item);

  switch (item->column())
    {
    case qMRMLSceneIGTLConnectorModel::NameColumn:
      {
      cnode->SetName(item->text().toLatin1());
      break;
      }
    case qMRMLSceneIGTLConnectorModel::TypeColumn:
      {
      }
    case qMRMLSceneIGTLConnectorModel::StatusColumn:
      {
      }
    case qMRMLSceneIGTLConnectorModel::HostnameColumn:
      {
      }
    case qMRMLSceneIGTLConnectorModel::PortColumn:
      {
      }
    default:
      break;
    }
}

//------------------------------------------------------------------------------
void qMRMLSceneIGTLConnectorModel::updateItemDataFromNode(QStandardItem* item, vtkMRMLNode* node, int column)
{
  vtkMRMLIGTLConnectorNode* cnode = vtkMRMLIGTLConnectorNode::SafeDownCast(node);
  if (!cnode)
    {
    return;
    }
  switch (column)
    {
    case qMRMLSceneIGTLConnectorModel::NameColumn:
      {
      item->setText(cnode->GetName());
      break;
      }
    case qMRMLSceneIGTLConnectorModel::TypeColumn:
      {
      Q_ASSERT(cnode->GetType() < vtkMRMLIGTLConnectorNode::NUM_TYPE);
      item->setText(QString(vtkMRMLIGTLConnectorNode::ConnectorTypeStr[cnode->GetType()]));
      break;
      }
    case qMRMLSceneIGTLConnectorModel::StatusColumn:
      {
      Q_ASSERT(cnode->GetState() < vtkMRMLIGTLConnectorNode::NUM_STATE);
      item->setText(QString(vtkMRMLIGTLConnectorNode::ConnectorStateStr[cnode->GetState()]));
      break;
      }
    case qMRMLSceneIGTLConnectorModel::HostnameColumn:
      {
      if (cnode->GetType() == vtkMRMLIGTLConnectorNode::TYPE_CLIENT)
        {
        item->setText(QString(cnode->GetServerHostname()));
        }
      else
        {
        item->setText(QString("--"));
        }
      break;
      }
    case qMRMLSceneIGTLConnectorModel::PortColumn:
      {
      item->setText(QString("%1").arg(cnode->GetServerPort()));
      break;
      }
    default:
      break;
    }
}

//------------------------------------------------------------------------------
QFlags<Qt::ItemFlag> qMRMLSceneIGTLConnectorModel::nodeFlags(vtkMRMLNode* node, int column)const
{
  QFlags<Qt::ItemFlag> flags = this->qMRMLSceneDisplayableModel::nodeFlags(node, column);
  // remove the ItemIsEditable flag from any possible item (typically at column 0)
  flags = flags & ~Qt::ItemIsEditable;
  // and set it to the right column
  switch(column)
    {
    //case qMRMLSceneIGTLConnectorModel::TextColumn:
    //  flags = flags | Qt::ItemIsEditable;
    //  break;
    default:
      break;
    }
  return flags;
}

//------------------------------------------------------------------------------
vtkMRMLNode* qMRMLSceneIGTLConnectorModel::parentNode(vtkMRMLNode* node)const
{
  if (node == NULL)
    {
    return 0;
    }

  // MRML Displayable nodes (inherits from transformable)
  vtkMRMLDisplayableNode *displayableNode = vtkMRMLDisplayableNode::SafeDownCast(node);
  vtkMRMLDisplayableHierarchyNode * displayableHierarchyNode = NULL;
  if (displayableNode &&
      displayableNode->GetScene() &&
      displayableNode->GetID())
    {
    // get the displayable hierarchy node associated with this displayable node
    displayableHierarchyNode = vtkMRMLDisplayableHierarchyNode::GetDisplayableHierarchyNode(displayableNode->GetScene(), displayableNode->GetID());

    if (displayableHierarchyNode)
      {
      if (displayableHierarchyNode->GetHideFromEditors())
        {
        // this is a hidden hierarchy node, so we do not want to display it
        // instead, we will return the parent of the hidden hierarchy node
        // to be used as the parent for the displayableNode
        return displayableHierarchyNode->GetParentNode();
        }
      return displayableHierarchyNode;
      }
    }
  if (displayableHierarchyNode == NULL)
    {
    // the passed in node might have been a hierarchy node instead, try to
    // cast it
    displayableHierarchyNode = vtkMRMLDisplayableHierarchyNode::SafeDownCast(node);
    }
  if (displayableHierarchyNode)
    {
    // return it's parent
    return displayableHierarchyNode->GetParentNode();
    }
  return 0;
}

//-----------------------------------------------------------------------------
/// Set and observe the logic
//-----------------------------------------------------------------------------
void qMRMLSceneIGTLConnectorModel::setLogic(vtkSlicerOpenIGTLinkIFLogic* logic)
{
  if (!logic)
    {
    return;
    }
  this->Logic = logic;
}
<commit_msg>COMP: qMRMLSceneIGTConnectorModel - Include only required header<commit_after>/*==============================================================================

  Program: 3D Slicer

  Copyright (c) 2010 Kitware Inc.

  See COPYRIGHT.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  This file was originally developed by Julien Finet, Kitware Inc.
  and was partially funded by NIH grant 3P41RR013218-12S1

==============================================================================*/

// Qt includes
#include <QDebug>
#include <QMap>
#include <QMimeData>
#include <QSharedPointer>
#include <QStack>
#include <QStringList>
#include <QVector>

// OpenIGTLinkIF GUI includes
#include "qMRMLSceneIGTLConnectorModel.h"

// qMRMLWidgets includes
#include <qMRMLSceneDisplayableModel.h>

// OpenIGTLinkIF MRML includes
#include "vtkMRMLIGTLConnectorNode.h"

// MRML includes
#include <vtkMRMLScene.h>
#include <vtkMRMLNode.h>
#include <vtkMRMLDisplayableHierarchyNode.h>
#include <vtkMRMLDisplayableNode.h>

// VTK includes
#include <vtkVariantArray.h>

//------------------------------------------------------------------------------
qMRMLSceneIGTLConnectorModel::qMRMLSceneIGTLConnectorModel(QObject *vparent)
  :qMRMLSceneDisplayableModel(vparent)
{
  this->setListenNodeModifiedEvent(true);
  this->setIDColumn(-1);
  this->setHorizontalHeaderLabels(
        QStringList() << "Name" << "Type" << "Status" << "Hostname" << "Port");
}

//------------------------------------------------------------------------------
qMRMLSceneIGTLConnectorModel::~qMRMLSceneIGTLConnectorModel()
{
}

//------------------------------------------------------------------------------
QStandardItem* qMRMLSceneIGTLConnectorModel::insertNode(vtkMRMLNode* node, QStandardItem* parent, int row)
{
  QStandardItem* insertedItem = this->Superclass::insertNode(node, parent, row);
  if (this->listenNodeModifiedEvent() &&
      node->IsA("vtkMRMLIGTLConnectorNode"))
    {
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::ConnectedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::DisconnectedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::ActivatedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::DeactivatedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    }
  return insertedItem;
}

//------------------------------------------------------------------------------
void qMRMLSceneIGTLConnectorModel::updateNodeFromItemData(vtkMRMLNode* node, QStandardItem* item)
{
  //int oldChecked = node->GetSelected();
  vtkMRMLIGTLConnectorNode* cnode = vtkMRMLIGTLConnectorNode::SafeDownCast(node);
  if (!cnode)
    {
    return;
    }
  this->qMRMLSceneDisplayableModel::updateNodeFromItemData(node, item);

  switch (item->column())
    {
    case qMRMLSceneIGTLConnectorModel::NameColumn:
      {
      cnode->SetName(item->text().toLatin1());
      break;
      }
    case qMRMLSceneIGTLConnectorModel::TypeColumn:
      {
      }
    case qMRMLSceneIGTLConnectorModel::StatusColumn:
      {
      }
    case qMRMLSceneIGTLConnectorModel::HostnameColumn:
      {
      }
    case qMRMLSceneIGTLConnectorModel::PortColumn:
      {
      }
    default:
      break;
    }
}

//------------------------------------------------------------------------------
void qMRMLSceneIGTLConnectorModel::updateItemDataFromNode(QStandardItem* item, vtkMRMLNode* node, int column)
{
  vtkMRMLIGTLConnectorNode* cnode = vtkMRMLIGTLConnectorNode::SafeDownCast(node);
  if (!cnode)
    {
    return;
    }
  switch (column)
    {
    case qMRMLSceneIGTLConnectorModel::NameColumn:
      {
      item->setText(cnode->GetName());
      break;
      }
    case qMRMLSceneIGTLConnectorModel::TypeColumn:
      {
      Q_ASSERT(cnode->GetType() < vtkMRMLIGTLConnectorNode::NUM_TYPE);
      item->setText(QString(vtkMRMLIGTLConnectorNode::ConnectorTypeStr[cnode->GetType()]));
      break;
      }
    case qMRMLSceneIGTLConnectorModel::StatusColumn:
      {
      Q_ASSERT(cnode->GetState() < vtkMRMLIGTLConnectorNode::NUM_STATE);
      item->setText(QString(vtkMRMLIGTLConnectorNode::ConnectorStateStr[cnode->GetState()]));
      break;
      }
    case qMRMLSceneIGTLConnectorModel::HostnameColumn:
      {
      if (cnode->GetType() == vtkMRMLIGTLConnectorNode::TYPE_CLIENT)
        {
        item->setText(QString(cnode->GetServerHostname()));
        }
      else
        {
        item->setText(QString("--"));
        }
      break;
      }
    case qMRMLSceneIGTLConnectorModel::PortColumn:
      {
      item->setText(QString("%1").arg(cnode->GetServerPort()));
      break;
      }
    default:
      break;
    }
}

//------------------------------------------------------------------------------
QFlags<Qt::ItemFlag> qMRMLSceneIGTLConnectorModel::nodeFlags(vtkMRMLNode* node, int column)const
{
  QFlags<Qt::ItemFlag> flags = this->qMRMLSceneDisplayableModel::nodeFlags(node, column);
  // remove the ItemIsEditable flag from any possible item (typically at column 0)
  flags = flags & ~Qt::ItemIsEditable;
  // and set it to the right column
  switch(column)
    {
    //case qMRMLSceneIGTLConnectorModel::TextColumn:
    //  flags = flags | Qt::ItemIsEditable;
    //  break;
    default:
      break;
    }
  return flags;
}

//------------------------------------------------------------------------------
vtkMRMLNode* qMRMLSceneIGTLConnectorModel::parentNode(vtkMRMLNode* node)const
{
  if (node == NULL)
    {
    return 0;
    }

  // MRML Displayable nodes (inherits from transformable)
  vtkMRMLDisplayableNode *displayableNode = vtkMRMLDisplayableNode::SafeDownCast(node);
  vtkMRMLDisplayableHierarchyNode * displayableHierarchyNode = NULL;
  if (displayableNode &&
      displayableNode->GetScene() &&
      displayableNode->GetID())
    {
    // get the displayable hierarchy node associated with this displayable node
    displayableHierarchyNode = vtkMRMLDisplayableHierarchyNode::GetDisplayableHierarchyNode(displayableNode->GetScene(), displayableNode->GetID());

    if (displayableHierarchyNode)
      {
      if (displayableHierarchyNode->GetHideFromEditors())
        {
        // this is a hidden hierarchy node, so we do not want to display it
        // instead, we will return the parent of the hidden hierarchy node
        // to be used as the parent for the displayableNode
        return displayableHierarchyNode->GetParentNode();
        }
      return displayableHierarchyNode;
      }
    }
  if (displayableHierarchyNode == NULL)
    {
    // the passed in node might have been a hierarchy node instead, try to
    // cast it
    displayableHierarchyNode = vtkMRMLDisplayableHierarchyNode::SafeDownCast(node);
    }
  if (displayableHierarchyNode)
    {
    // return it's parent
    return displayableHierarchyNode->GetParentNode();
    }
  return 0;
}

//-----------------------------------------------------------------------------
/// Set and observe the logic
//-----------------------------------------------------------------------------
void qMRMLSceneIGTLConnectorModel::setLogic(vtkSlicerOpenIGTLinkIFLogic* logic)
{
  if (!logic)
    {
    return;
    }
  this->Logic = logic;
}
<|endoftext|>


<commit_before>/*!
    \file named_mutex.cpp
    \brief Named mutex synchronization primitive implementation
    \author Ivan Shynkarenka
    \date 15.04.2016
    \copyright MIT License
*/

#include "threads/named_mutex.h"

#include "errors/exceptions.h"
#include "errors/fatal.h"

#include <algorithm>

#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
#include "system/shared_type.h"
#include <pthread.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#undef max
#undef min
#endif

namespace CppCommon {

//! @cond INTERNALS

class NamedMutex::Impl
{
public:
    Impl(const std::string& name) : _name(name)
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        , _shared(name)
#endif
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        // Only the owner should initializate a named mutex
        if (_shared.owner())
        {
            pthread_mutexattr_t mutex_attribute;
            int result = pthread_mutexattr_init(&mutex_attribute);
            if (result != 0)
                throwex SystemException("Failed to initialize a named mutex attribute!", result);
            result = pthread_mutexattr_setpshared(&mutex_attribute, PTHREAD_PROCESS_SHARED);
            if (result != 0)
                throwex SystemException("Failed to set a named mutex process shared attribute!", result);
            result = pthread_mutex_init(&_shared->mutex, &mutex_attribute);
            if (result != 0)
                throwex SystemException("Failed to initialize a named mutex!", result);
            result = pthread_mutexattr_destroy(&mutex_attribute);
            if (result != 0)
                throwex SystemException("Failed to destroy a named mutex attribute!", result);
        }
#elif defined(_WIN32) || defined(_WIN64)
        _mutex = CreateMutexA(nullptr, FALSE, name.c_str());
        if (_mutex == nullptr)
            throwex SystemException("Failed to create or open a named mutex!");
#endif
    }

    ~Impl()
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        // Only the owner should destroy a named mutex
        if (_shared.owner())
        {
            int result = pthread_mutex_destroy(&_shared->mutex);
            if (result != 0)
                fatality(SystemException("Failed to destroy a named mutex!", result));
        }
#elif defined(_WIN32) || defined(_WIN64)
        if (!CloseHandle(_mutex))
            fatality(SystemException("Failed to close a named mutex!"));
#endif
    }

    const std::string& name() const
    {
        return _name;
    }

    bool TryLock()
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        int result = pthread_mutex_trylock(&_shared->mutex);
        if ((result != 0) && (result != EBUSY))
            throwex SystemException("Failed to try lock a named mutex!", result);
        return (result == 0);
#elif defined(_WIN32) || defined(_WIN64)
        DWORD result = WaitForSingleObject(_mutex, 0);
        if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
            throwex SystemException("Failed to try lock a named mutex!");
        return (result == WAIT_OBJECT_0);
#endif
    }

    bool TryLockFor(const Timespan& timespan)
    {
        if (timespan < 0)
            return TryLock();
#if defined(__CYGWIN__)
        // Calculate a finish timestamp
        Timestamp finish = NanoTimestamp() + timespan;

        // Try to acquire lock at least one time
        if (TryLock())
            return true;
        else
        {
            // Try lock or yield for the given timespan
            while (NanoTimestamp() < finish)
            {
                if (TryLock())
                    return true;
                else
                    Thread::Yield();
            }

            // Failed to acquire lock
            return false;
        }
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        struct timespec timeout;
        timeout.tv_sec = timespan.seconds();
        timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
        int result = pthread_mutex_timedlock(&_shared->mutex, &timeout);
        if ((result != 0) && (result != ETIMEDOUT))
            throwex SystemException("Failed to try lock a named mutex for the given timeout!", result);
        return (result == 0);
#elif defined(_WIN32) || defined(_WIN64)
        DWORD result = WaitForSingleObject(_mutex, (DWORD)std::max(1ll, timespan.milliseconds()));
        if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
            throwex SystemException("Failed to try lock a named mutex for the given timeout!");
        return (result == WAIT_OBJECT_0);
#endif
    }

    void Lock()
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        int result = pthread_mutex_lock(&_shared->mutex);
        if (result != 0)
            throwex SystemException("Failed to lock a named mutex!", result);
#elif defined(_WIN32) || defined(_WIN64)
        DWORD result = WaitForSingleObject(_mutex, INFINITE);
        if (result != WAIT_OBJECT_0)
            throwex SystemException("Failed to lock a named mutex!");
#endif
    }

    void Unlock()
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        int result = pthread_mutex_unlock(&_shared->mutex);
        if (result != 0)
            throwex SystemException("Failed to unlock a named mutex!", result);
#elif defined(_WIN32) || defined(_WIN64)
        if (!ReleaseMutex(_mutex))
            throwex SystemException("Failed to unlock a named mutex!");
#endif
    }

private:
    std::string _name;
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    // Shared mutex structure
    struct MutexHeader
    {
        pthread_mutex_t mutex;
    };

    // Shared mutex structure wrapper
    SharedType<MutexHeader> _shared;
#elif defined(_WIN32) || defined(_WIN64)
    HANDLE _mutex;
#endif
};

//! @endcond

NamedMutex::NamedMutex(const std::string& name) : _pimpl(std::make_unique<Impl>(name))
{
}

NamedMutex::NamedMutex(NamedMutex&& mutex) noexcept : _pimpl(std::move(mutex._pimpl))
{
}

NamedMutex::~NamedMutex()
{
}

NamedMutex& NamedMutex::operator=(NamedMutex&& mutex) noexcept
{
    _pimpl = std::move(mutex._pimpl);
    return *this;
}

const std::string& NamedMutex::name() const
{
    return _pimpl->name();
}

bool NamedMutex::TryLock()
{
    return _pimpl->TryLock();
}

bool NamedMutex::TryLockFor(const Timespan& timespan)
{
    return _pimpl->TryLockFor(timespan);
}

void NamedMutex::Lock()
{
    _pimpl->Lock();
}

void NamedMutex::Unlock()
{
    _pimpl->Unlock();
}

} // namespace CppCommon
<commit_msg>Fix Cygwin build<commit_after>/*!
    \file named_mutex.cpp
    \brief Named mutex synchronization primitive implementation
    \author Ivan Shynkarenka
    \date 15.04.2016
    \copyright MIT License
*/

#include "threads/named_mutex.h"

#include "errors/exceptions.h"
#include "errors/fatal.h"

#include <algorithm>

#if defined(__CYGWIN__)
#include "threads/thread.h"
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
#include "system/shared_type.h"
#include <pthread.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#undef max
#undef min
#endif

namespace CppCommon {

//! @cond INTERNALS

class NamedMutex::Impl
{
public:
    Impl(const std::string& name) : _name(name)
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        , _shared(name)
#endif
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        // Only the owner should initializate a named mutex
        if (_shared.owner())
        {
            pthread_mutexattr_t mutex_attribute;
            int result = pthread_mutexattr_init(&mutex_attribute);
            if (result != 0)
                throwex SystemException("Failed to initialize a named mutex attribute!", result);
            result = pthread_mutexattr_setpshared(&mutex_attribute, PTHREAD_PROCESS_SHARED);
            if (result != 0)
                throwex SystemException("Failed to set a named mutex process shared attribute!", result);
            result = pthread_mutex_init(&_shared->mutex, &mutex_attribute);
            if (result != 0)
                throwex SystemException("Failed to initialize a named mutex!", result);
            result = pthread_mutexattr_destroy(&mutex_attribute);
            if (result != 0)
                throwex SystemException("Failed to destroy a named mutex attribute!", result);
        }
#elif defined(_WIN32) || defined(_WIN64)
        _mutex = CreateMutexA(nullptr, FALSE, name.c_str());
        if (_mutex == nullptr)
            throwex SystemException("Failed to create or open a named mutex!");
#endif
    }

    ~Impl()
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        // Only the owner should destroy a named mutex
        if (_shared.owner())
        {
            int result = pthread_mutex_destroy(&_shared->mutex);
            if (result != 0)
                fatality(SystemException("Failed to destroy a named mutex!", result));
        }
#elif defined(_WIN32) || defined(_WIN64)
        if (!CloseHandle(_mutex))
            fatality(SystemException("Failed to close a named mutex!"));
#endif
    }

    const std::string& name() const
    {
        return _name;
    }

    bool TryLock()
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        int result = pthread_mutex_trylock(&_shared->mutex);
        if ((result != 0) && (result != EBUSY))
            throwex SystemException("Failed to try lock a named mutex!", result);
        return (result == 0);
#elif defined(_WIN32) || defined(_WIN64)
        DWORD result = WaitForSingleObject(_mutex, 0);
        if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
            throwex SystemException("Failed to try lock a named mutex!");
        return (result == WAIT_OBJECT_0);
#endif
    }

    bool TryLockFor(const Timespan& timespan)
    {
        if (timespan < 0)
            return TryLock();
#if defined(__CYGWIN__)
        // Calculate a finish timestamp
        Timestamp finish = NanoTimestamp() + timespan;

        // Try to acquire lock at least one time
        if (TryLock())
            return true;
        else
        {
            // Try lock or yield for the given timespan
            while (NanoTimestamp() < finish)
            {
                if (TryLock())
                    return true;
                else
                    Thread::Yield();
            }

            // Failed to acquire lock
            return false;
        }
#elif defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        struct timespec timeout;
        timeout.tv_sec = timespan.seconds();
        timeout.tv_nsec = timespan.nanoseconds() % 1000000000;
        int result = pthread_mutex_timedlock(&_shared->mutex, &timeout);
        if ((result != 0) && (result != ETIMEDOUT))
            throwex SystemException("Failed to try lock a named mutex for the given timeout!", result);
        return (result == 0);
#elif defined(_WIN32) || defined(_WIN64)
        DWORD result = WaitForSingleObject(_mutex, (DWORD)std::max(1ll, timespan.milliseconds()));
        if ((result != WAIT_OBJECT_0) && (result != WAIT_TIMEOUT))
            throwex SystemException("Failed to try lock a named mutex for the given timeout!");
        return (result == WAIT_OBJECT_0);
#endif
    }

    void Lock()
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        int result = pthread_mutex_lock(&_shared->mutex);
        if (result != 0)
            throwex SystemException("Failed to lock a named mutex!", result);
#elif defined(_WIN32) || defined(_WIN64)
        DWORD result = WaitForSingleObject(_mutex, INFINITE);
        if (result != WAIT_OBJECT_0)
            throwex SystemException("Failed to lock a named mutex!");
#endif
    }

    void Unlock()
    {
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
        int result = pthread_mutex_unlock(&_shared->mutex);
        if (result != 0)
            throwex SystemException("Failed to unlock a named mutex!", result);
#elif defined(_WIN32) || defined(_WIN64)
        if (!ReleaseMutex(_mutex))
            throwex SystemException("Failed to unlock a named mutex!");
#endif
    }

private:
    std::string _name;
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    // Shared mutex structure
    struct MutexHeader
    {
        pthread_mutex_t mutex;
    };

    // Shared mutex structure wrapper
    SharedType<MutexHeader> _shared;
#elif defined(_WIN32) || defined(_WIN64)
    HANDLE _mutex;
#endif
};

//! @endcond

NamedMutex::NamedMutex(const std::string& name) : _pimpl(std::make_unique<Impl>(name))
{
}

NamedMutex::NamedMutex(NamedMutex&& mutex) noexcept : _pimpl(std::move(mutex._pimpl))
{
}

NamedMutex::~NamedMutex()
{
}

NamedMutex& NamedMutex::operator=(NamedMutex&& mutex) noexcept
{
    _pimpl = std::move(mutex._pimpl);
    return *this;
}

const std::string& NamedMutex::name() const
{
    return _pimpl->name();
}

bool NamedMutex::TryLock()
{
    return _pimpl->TryLock();
}

bool NamedMutex::TryLockFor(const Timespan& timespan)
{
    return _pimpl->TryLockFor(timespan);
}

void NamedMutex::Lock()
{
    _pimpl->Lock();
}

void NamedMutex::Unlock()
{
    _pimpl->Unlock();
}

} // namespace CppCommon
<|endoftext|>


<commit_before>/*
	 Jamoma Class for representing parameters for modules, plug-ins, etc.
	 Copyright © 2010 by Timothy Place

	 License: This code is licensed under the terms of the "New BSD License"
	 http://creativecommons.org/licenses/BSD/
*/

#include "TTGraphObject.h"
#include "TTParameter.h"

#define thisTTClass			TTParameter
#define thisTTClassName		"parameter"
#define thisTTClassTags		"plugtastic, parameter"

TT_OBJECT_CONSTRUCTOR,
	mOwner(NULL)
{
	addAttributeWithSetter(Name,	kTypeSymbol);
	addAttributeWithSetter(Value,	kTypeFloat64);
	addAttribute(RangeBottom,		kTypeFloat64);
	addAttribute(RangeTop,			kTypeFloat64);
	addAttribute(Default,			kTypeFloat64);
	addAttribute(Style,				kTypeSymbol);

	mDictionary.setSchema(TT("attribute"));

	setAttributeValue(TT("name"), TT("my parameter"));
	setAttributeValue(TT("rangeBottom"), 0.0);
	setAttributeValue(TT("rangeTop"), 1.0);
	setAttributeValue(TT("default"), 0.5);
	setAttributeValue(TT("style"), TT("generic"));
	setAttributeValue(TT("value"), 0.0);
}

TTParameter::~PlugtasticParameter()
{
	;
}

TTErr TTParameter::setName(const TTValue& newValue)
{
	mName = newValue;
	mDictionary.remove(TT("name"));
	mDictionary.append(TT("name"), newValue);
	return kTTErrNone;
}

TTErr TTParameter::setValue(const TTValue& newValue)
{
	mValue = newValue;
	mDictionary.setValue(newValue);
	return push(mDictionary);
}

TTErr TTParameter::setOwner(TTGraphObjectPtr newOwner)
{
	mOwner = newOwner;
	return kTTErrNone;
}

TTErr TTParameter::push(const TTDictionary& aDictionary)
{
	if (mOwner) {
		return mOwner->push(aDictionary);
	}
	else {
		return kTTErrGeneric;
	}
}

<commit_msg>TTParameter typo fix<commit_after>/*
	 Jamoma Class for representing parameters for modules, plug-ins, etc.
	 Copyright © 2010 by Timothy Place

	 License: This code is licensed under the terms of the "New BSD License"
	 http://creativecommons.org/licenses/BSD/
*/

#include "TTGraphObject.h"
#include "TTParameter.h"

#define thisTTClass			TTParameter
#define thisTTClassName		"parameter"
#define thisTTClassTags		"plugtastic, parameter"

TT_OBJECT_CONSTRUCTOR,
	mOwner(NULL)
{
	addAttributeWithSetter(Name,	kTypeSymbol);
	addAttributeWithSetter(Value,	kTypeFloat64);
	addAttribute(RangeBottom,		kTypeFloat64);
	addAttribute(RangeTop,			kTypeFloat64);
	addAttribute(Default,			kTypeFloat64);
	addAttribute(Style,				kTypeSymbol);

	mDictionary.setSchema(TT("attribute"));

	setAttributeValue(TT("name"), TT("my parameter"));
	setAttributeValue(TT("rangeBottom"), 0.0);
	setAttributeValue(TT("rangeTop"), 1.0);
	setAttributeValue(TT("default"), 0.5);
	setAttributeValue(TT("style"), TT("generic"));
	setAttributeValue(TT("value"), 0.0);
}

TTParameter::~TTParameter()
{
	;
}

TTErr TTParameter::setName(const TTValue& newValue)
{
	mName = newValue;
	mDictionary.remove(TT("name"));
	mDictionary.append(TT("name"), newValue);
	return kTTErrNone;
}

TTErr TTParameter::setValue(const TTValue& newValue)
{
	mValue = newValue;
	mDictionary.setValue(newValue);
	return push(mDictionary);
}

TTErr TTParameter::setOwner(TTGraphObjectPtr newOwner)
{
	mOwner = newOwner;
	return kTTErrNone;
}

TTErr TTParameter::push(const TTDictionary& aDictionary)
{
	if (mOwner) {
		return mOwner->push(aDictionary);
	}
	else {
		return kTTErrGeneric;
	}
}

<|endoftext|>


<commit_before>// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#ifndef ROSETTASTONE_CARD_ENUMS_HPP
#define ROSETTASTONE_CARD_ENUMS_HPP

#include <string>
#include <string_view>

namespace RosettaStone
{
//! \brief An enumerator for identifying the class of the card.
enum class CardClass
{
#define X(a) a,
#include "CardClass.def"
#undef X
};

const std::string CARD_CLASS_STR[] = {
#define X(a) #a,
#include "CardClass.def"
#undef X
};

//! \brief An enumerator for identifying the set of the card.
enum class CardSet
{
#define X(a) a,
#include "CardSet.def"
#undef X
};

const std::string CARD_SET_STR[] = {
#define X(a) #a,
#include "CardSet.def"
#undef X
};

//! \brief An enumerator for identifying the type of the card.
enum class CardType
{
#define X(a) a,
#include "CardType.def"
#undef X
};

const std::string CARD_TYPE_STR[] = {
#define X(a) #a,
#include "CardType.def"
#undef X
};

//! \brief An enumerator for identifying the faction of the card.
enum class Faction
{
#define X(a) a,
#include "Faction.def"
#undef X
};

const std::string FACTION_STR[] = {
#define X(a) #a,
#include "Faction.def"
#undef X
};

//! \brief An enumerator for identifying the game tag of the card.
enum class GameTag
{
#define X(a) a,
#include "GameTag.def"
#undef X
};

const std::string GAME_TAG_STR[] = {
#define X(a) #a,
#include "GameTag.def"
#undef X
};

//! \brief An enumerator for identifying the play requirement of the card.
enum class PlayReq
{
#define X(a) a,
#include "PlayReq.def"
#undef X
};

const std::string PLAY_REQ_STR[] = {
#define X(a) #a,
#include "PlayReq.def"
#undef X
};

//! \brief An enumerator for identifying the race of the card.
enum class Race
{
#define X(a) a,
#include "Race.def"
#undef X
};

const std::string RACE_STR[] = {
#define X(a) #a,
#include "Race.def"
#undef X
};

//! \brief An enumerator for identifying the rarity of the card.
enum class Rarity
{
#define X(a) a,
#include "Rarity.def"
#undef X
};

const std::string RARITY_STR[] = {
#define X(a) #a,
#include "Rarity.def"
#undef X
};

//! \brief An enumerator for identifying the locale of the card.
enum class Locale
{
    UNKNOWN,
    enUS,
    enGB,
    frFR,
    deDE,
    koKR,
    esES,
    esMX,
    ruRU,
    zhTW,
    zhCN,
    itIT,
    ptBR,
    plPL,
    ptPT,
    jaJP,
    thTH
};

//! \brief An enumerator for identifying the mulligan state.
enum class Mulligan
{
    INVALID,
    INPUT,
    DEALING,
    WAITING,
    DONE
};

//! \brief An enumerator for identifying the choice type of the card.
enum class ChoiceType
{
    INVALID,
    MULLIGAN,
    GENERAL
};

//! \brief An enumerator for identifying the format type of the card.
enum class FormatType
{
    UNKNOWN,
    WILD,
    STANDARD
};

//! \brief An enumerator for identifying the play state.
enum class PlayState
{
    INVALID,
    PLAYING,
    WINNING,
    LOSING,
    WON,
    LOST,
    TIED,
    DISCONNECTED,
    CONCEDED
};

//! \brief An enumerator for indicating the state of the card.
enum class State
{
    INVALID,
    LOADING,
    RUNNING,
    COMPLETE
};

//! \brief An enumerator for indicating the game step.
enum class Step
{
    INVALID,
    BEGIN_FIRST,
    BEGIN_SHUFFLE,
    BEGIN_DRAW,
    BEGIN_MULLIGAN,
    MAIN_BEGIN,
    MAIN_READY,
    MAIN_RESOURCE,
    MAIN_DRAW,
    MAIN_START,
    MAIN_ACTION,
    MAIN_COMBAT,
    MAIN_END,
    MAIN_NEXT,
    FINAL_WRAPUP,
    FINAL_GAMEOVER,
    MAIN_CLEANUP,
    MAIN_START_TRIGGERS
};

//! \brief An enumerator for indicating the game zone.
enum class Zone
{
    INVALID,
    PLAY,
    DECK,
    HAND,
    GRAVEYARD,
    REMOVEDFROMGAME,
    SETASIDE,
    SECRET
};

template <class T>
T StrToEnum(const std::string_view&);
template <class T>
std::string_view EnumToStr(T);

#define STR2ENUM(TYPE, ARRAY)                                                \
    template <>                                                              \
    inline TYPE StrToEnum<TYPE>(const std::string_view& str)                 \
    {                                                                        \
        for (std::size_t i = 0; i < (sizeof(ARRAY) / sizeof(ARRAY[0])); ++i) \
        {                                                                    \
            if (ARRAY[i] == str)                                             \
            {                                                                \
                return TYPE(i);                                              \
            }                                                                \
        }                                                                    \
                                                                             \
        return TYPE(0);                                                      \
    }

#define ENUM2STR(TYPE, ARRAY)                       \
    template <>                                     \
    inline std::string_view EnumToStr<TYPE>(TYPE v) \
    {                                               \
        return ARRAY[static_cast<int>(v)];          \
    }

#define ENUM_AND_STR(TYPE, ARRAY) \
    STR2ENUM(TYPE, ARRAY)         \
    ENUM2STR(TYPE, ARRAY)

ENUM_AND_STR(CardClass, CARD_CLASS_STR)
ENUM_AND_STR(CardSet, CARD_SET_STR)
ENUM_AND_STR(CardType, CARD_TYPE_STR)
ENUM_AND_STR(Faction, FACTION_STR)
ENUM_AND_STR(GameTag, GAME_TAG_STR)
ENUM_AND_STR(PlayReq, PLAY_REQ_STR)
ENUM_AND_STR(Race, RACE_STR)
ENUM_AND_STR(Rarity, RARITY_STR)
}  // namespace RosettaStone

#endif  // ROSETTASTONE_CARD_ENUMS_HPP<commit_msg>refactor: Change enum name ('Zone' -> 'ZoneType')<commit_after>// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

// We are making my contributions/submissions to this project solely in our
// personal capacity and are not conveying any rights to any intellectual
// property of any third parties.

#ifndef ROSETTASTONE_CARD_ENUMS_HPP
#define ROSETTASTONE_CARD_ENUMS_HPP

#include <string>
#include <string_view>

namespace RosettaStone
{
//! \brief An enumerator for identifying the class of the card.
enum class CardClass
{
#define X(a) a,
#include "CardClass.def"
#undef X
};

const std::string CARD_CLASS_STR[] = {
#define X(a) #a,
#include "CardClass.def"
#undef X
};

//! \brief An enumerator for identifying the set of the card.
enum class CardSet
{
#define X(a) a,
#include "CardSet.def"
#undef X
};

const std::string CARD_SET_STR[] = {
#define X(a) #a,
#include "CardSet.def"
#undef X
};

//! \brief An enumerator for identifying the type of the card.
enum class CardType
{
#define X(a) a,
#include "CardType.def"
#undef X
};

const std::string CARD_TYPE_STR[] = {
#define X(a) #a,
#include "CardType.def"
#undef X
};

//! \brief An enumerator for identifying the faction of the card.
enum class Faction
{
#define X(a) a,
#include "Faction.def"
#undef X
};

const std::string FACTION_STR[] = {
#define X(a) #a,
#include "Faction.def"
#undef X
};

//! \brief An enumerator for identifying the game tag of the card.
enum class GameTag
{
#define X(a) a,
#include "GameTag.def"
#undef X
};

const std::string GAME_TAG_STR[] = {
#define X(a) #a,
#include "GameTag.def"
#undef X
};

//! \brief An enumerator for identifying the play requirement of the card.
enum class PlayReq
{
#define X(a) a,
#include "PlayReq.def"
#undef X
};

const std::string PLAY_REQ_STR[] = {
#define X(a) #a,
#include "PlayReq.def"
#undef X
};

//! \brief An enumerator for identifying the race of the card.
enum class Race
{
#define X(a) a,
#include "Race.def"
#undef X
};

const std::string RACE_STR[] = {
#define X(a) #a,
#include "Race.def"
#undef X
};

//! \brief An enumerator for identifying the rarity of the card.
enum class Rarity
{
#define X(a) a,
#include "Rarity.def"
#undef X
};

const std::string RARITY_STR[] = {
#define X(a) #a,
#include "Rarity.def"
#undef X
};

//! \brief An enumerator for identifying the locale of the card.
enum class Locale
{
    UNKNOWN,
    enUS,
    enGB,
    frFR,
    deDE,
    koKR,
    esES,
    esMX,
    ruRU,
    zhTW,
    zhCN,
    itIT,
    ptBR,
    plPL,
    ptPT,
    jaJP,
    thTH
};

//! \brief An enumerator for identifying the mulligan state.
enum class Mulligan
{
    INVALID,
    INPUT,
    DEALING,
    WAITING,
    DONE
};

//! \brief An enumerator for identifying the choice type of the card.
enum class ChoiceType
{
    INVALID,
    MULLIGAN,
    GENERAL
};

//! \brief An enumerator for identifying the format type of the card.
enum class FormatType
{
    UNKNOWN,
    WILD,
    STANDARD
};

//! \brief An enumerator for identifying the play state.
enum class PlayState
{
    INVALID,
    PLAYING,
    WINNING,
    LOSING,
    WON,
    LOST,
    TIED,
    DISCONNECTED,
    CONCEDED
};

//! \brief An enumerator for indicating the state of the card.
enum class State
{
    INVALID,
    LOADING,
    RUNNING,
    COMPLETE
};

//! \brief An enumerator for indicating the game step.
enum class Step
{
    INVALID,
    BEGIN_FIRST,
    BEGIN_SHUFFLE,
    BEGIN_DRAW,
    BEGIN_MULLIGAN,
    MAIN_BEGIN,
    MAIN_READY,
    MAIN_RESOURCE,
    MAIN_DRAW,
    MAIN_START,
    MAIN_ACTION,
    MAIN_COMBAT,
    MAIN_END,
    MAIN_NEXT,
    FINAL_WRAPUP,
    FINAL_GAMEOVER,
    MAIN_CLEANUP,
    MAIN_START_TRIGGERS
};

//! \brief An enumerator for indicating the type of zone.
enum class ZoneType
{
    INVALID,
    PLAY,
    DECK,
    HAND,
    GRAVEYARD,
    REMOVEDFROMGAME,
    SETASIDE,
    SECRET
};

template <class T>
T StrToEnum(const std::string_view&);
template <class T>
std::string_view EnumToStr(T);

#define STR2ENUM(TYPE, ARRAY)                                                \
    template <>                                                              \
    inline TYPE StrToEnum<TYPE>(const std::string_view& str)                 \
    {                                                                        \
        for (std::size_t i = 0; i < (sizeof(ARRAY) / sizeof(ARRAY[0])); ++i) \
        {                                                                    \
            if (ARRAY[i] == str)                                             \
            {                                                                \
                return TYPE(i);                                              \
            }                                                                \
        }                                                                    \
                                                                             \
        return TYPE(0);                                                      \
    }

#define ENUM2STR(TYPE, ARRAY)                       \
    template <>                                     \
    inline std::string_view EnumToStr<TYPE>(TYPE v) \
    {                                               \
        return ARRAY[static_cast<int>(v)];          \
    }

#define ENUM_AND_STR(TYPE, ARRAY) \
    STR2ENUM(TYPE, ARRAY)         \
    ENUM2STR(TYPE, ARRAY)

ENUM_AND_STR(CardClass, CARD_CLASS_STR)
ENUM_AND_STR(CardSet, CARD_SET_STR)
ENUM_AND_STR(CardType, CARD_TYPE_STR)
ENUM_AND_STR(Faction, FACTION_STR)
ENUM_AND_STR(GameTag, GAME_TAG_STR)
ENUM_AND_STR(PlayReq, PLAY_REQ_STR)
ENUM_AND_STR(Race, RACE_STR)
ENUM_AND_STR(Rarity, RARITY_STR)
}  // namespace RosettaStone

#endif  // ROSETTASTONE_CARD_ENUMS_HPP<|endoftext|>