<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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
 *
 *   http://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. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#define BOOST_TEST_MODULE SecurityTest
#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <thrift/transport/TSSLServerSocket.h>
#include <thrift/transport/TSSLSocket.h>
#include <thrift/transport/TTransport.h>
#include "TestPortFixture.h"
#include <vector>
#ifdef __linux__
#include <signal.h>
#endif

using apache::thrift::transport::TSSLServerSocket;
using apache::thrift::transport::TServerTransport;
using apache::thrift::transport::TSSLSocket;
using apache::thrift::transport::TSSLSocketFactory;
using apache::thrift::transport::TTransport;
using apache::thrift::transport::TTransportException;
using apache::thrift::transport::TTransportFactory;

boost::filesystem::path keyDir;
boost::filesystem::path certFile(const std::string& filename)
{
    return keyDir / filename;
}
boost::mutex gMutex;

struct GlobalFixture
{
    GlobalFixture()
    {
        using namespace boost::unit_test::framework;
		for (int i = 0; i < master_test_suite().argc; ++i)
		{
			BOOST_TEST_MESSAGE(boost::format("argv[%1%] = \"%2%\"") % i % master_test_suite().argv[i]);
		}

    #ifdef __linux__
		// OpenSSL calls send() without MSG_NOSIGPIPE so writing to a socket that has
		// disconnected can cause a SIGPIPE signal...
		signal(SIGPIPE, SIG_IGN);
    #endif

		TSSLSocketFactory::setManualOpenSSLInitialization(true);
		apache::thrift::transport::initializeOpenSSL();

		keyDir = boost::filesystem::current_path().parent_path().parent_path().parent_path() / "test" / "keys";
		if (!boost::filesystem::exists(certFile("server.crt")))
		{
			keyDir = boost::filesystem::path(master_test_suite().argv[master_test_suite().argc - 1]);
			if (!boost::filesystem::exists(certFile("server.crt")))
			{
				throw std::invalid_argument("The last argument to this test must be the directory containing the test certificate(s).");
			}
		}
    }

    virtual ~GlobalFixture()
    {
		apache::thrift::transport::cleanupOpenSSL();
#ifdef __linux__
		signal(SIGPIPE, SIG_DFL);
#endif
    }
};

#if (BOOST_VERSION >= 105900)
BOOST_GLOBAL_FIXTURE(GlobalFixture);
#else
BOOST_GLOBAL_FIXTURE(GlobalFixture)
#endif

struct SecurityFixture : public TestPortFixture
{
    void server(apache::thrift::transport::SSLProtocol protocol)
    {
        try
        {
            boost::mutex::scoped_lock lock(mMutex);

            boost::shared_ptr<TSSLSocketFactory> pServerSocketFactory;
            boost::shared_ptr<TSSLServerSocket> pServerSocket;

            pServerSocketFactory.reset(new TSSLSocketFactory(static_cast<apache::thrift::transport::SSLProtocol>(protocol)));
            pServerSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
            pServerSocketFactory->loadCertificate(certFile("server.crt").string().c_str());
            pServerSocketFactory->loadPrivateKey(certFile("server.key").string().c_str());
            pServerSocketFactory->server(true);
            pServerSocket.reset(new TSSLServerSocket("localhost", m_serverPort, pServerSocketFactory));
            boost::shared_ptr<TTransport> connectedClient;

            try
            {
                pServerSocket->listen();
                mCVar.notify_one();
                lock.unlock();

                connectedClient = pServerSocket->accept();
                uint8_t buf[2];
                buf[0] = 'O';
                buf[1] = 'K';
                connectedClient->write(&buf[0], 2);
                connectedClient->flush();
            }

            catch (apache::thrift::transport::TTransportException& ex)
            {
                boost::mutex::scoped_lock lock(gMutex);
                BOOST_TEST_MESSAGE(boost::format("SRV %1% Exception: %2%") % boost::this_thread::get_id() % ex.what());
            }

            if (connectedClient)
            {
                connectedClient->close();
                connectedClient.reset();
            }

            pServerSocket->close();
            pServerSocket.reset();
        }
        catch (std::exception& ex)
        {
            BOOST_FAIL(boost::format("%1%: %2%") % typeid(ex).name() % ex.what());
        }
    }

    void client(apache::thrift::transport::SSLProtocol protocol)
    {
        try
        {
            boost::shared_ptr<TSSLSocketFactory> pClientSocketFactory;
            boost::shared_ptr<TSSLSocket> pClientSocket;

            try
            {
                pClientSocketFactory.reset(new TSSLSocketFactory(static_cast<apache::thrift::transport::SSLProtocol>(protocol)));
                pClientSocketFactory->authenticate(true);
                pClientSocketFactory->loadCertificate(certFile("client.crt").string().c_str());
                pClientSocketFactory->loadPrivateKey(certFile("client.key").string().c_str());
                pClientSocketFactory->loadTrustedCertificates(certFile("CA.pem").string().c_str());
                pClientSocket = pClientSocketFactory->createSocket("localhost", m_serverPort);
                pClientSocket->open();

                uint8_t buf[3];
                buf[0] = 0;
                buf[1] = 0;
                BOOST_CHECK_EQUAL(2, pClientSocket->read(&buf[0], 2));
                BOOST_CHECK_EQUAL(0, memcmp(&buf[0], "OK", 2));
                mConnected = true;
            }
            catch (apache::thrift::transport::TTransportException& ex)
            {
                boost::mutex::scoped_lock lock(gMutex);
                BOOST_TEST_MESSAGE(boost::format("CLI %1% Exception: %2%") % boost::this_thread::get_id() % ex.what());
            }

            if (pClientSocket)
            {
                pClientSocket->close();
                pClientSocket.reset();
            }
        }
        catch (std::exception& ex)
        {
            BOOST_FAIL(boost::format("%1%: %2%") % typeid(ex).name() % ex.what());
        }
    }

    static const char *protocol2str(size_t protocol)
    {
        static const char *strings[apache::thrift::transport::LATEST + 1] =
        {
                "SSLTLS",
                "SSLv2",
                "SSLv3",
                "TLSv1_0",
                "TLSv1_1",
                "TLSv1_2"
        };
        return strings[protocol];
    }

    boost::mutex mMutex;
    boost::condition_variable mCVar;
    bool mConnected;
};

BOOST_FIXTURE_TEST_SUITE(BOOST_TEST_MODULE, SecurityFixture)

BOOST_AUTO_TEST_CASE(ssl_security_matrix)
{
    try
    {
        // matrix of connection success between client and server with different SSLProtocol selections
        bool matrix[apache::thrift::transport::LATEST + 1][apache::thrift::transport::LATEST + 1] =
        {
    //   server    = SSLTLS   SSLv2    SSLv3    TLSv1_0  TLSv1_1  TLSv1_2
    // client
    /* SSLTLS  */  { true,    false,   false,   true,    true,    true    },
    /* SSLv2   */  { false,   false,   false,   false,   false,   false   },
    /* SSLv3   */  { false,   false,   true,    false,   false,   false   },
    /* TLSv1_0 */  { true,    false,   false,   true,    false,   false   },
    /* TLSv1_1 */  { true,    false,   false,   false,   true,    false   },
    /* TLSv1_2 */  { true,    false,   false,   false,   false,   true    }
        };

        for (size_t si = 0; si <= apache::thrift::transport::LATEST; ++si)
        {
            for (size_t ci = 0; ci <= apache::thrift::transport::LATEST; ++ci)
            {
                if (si == 1 || ci == 1)
                {
                    // Skip all SSLv2 cases - protocol not supported
                    continue;
                }

                boost::mutex::scoped_lock lock(mMutex);

                BOOST_TEST_MESSAGE(boost::format("TEST: Server = %1%, Client = %2%")
                    % protocol2str(si) % protocol2str(ci));

                mConnected = false;
                boost::thread_group threads;
                threads.create_thread(boost::bind(&SecurityFixture::server, this, static_cast<apache::thrift::transport::SSLProtocol>(si)));
                mCVar.wait(lock);           // wait for listen() to succeed
                lock.unlock();
                threads.create_thread(boost::bind(&SecurityFixture::client, this, static_cast<apache::thrift::transport::SSLProtocol>(ci)));
                threads.join_all();

                BOOST_CHECK_MESSAGE(mConnected == matrix[ci][si],
                        boost::format("      Server = %1%, Client = %2% expected mConnected == %3% but was %4%")
                            % protocol2str(si) % protocol2str(ci) % matrix[ci][si] % mConnected);
            }
        }
    }
    catch (std::exception& ex)
    {
        BOOST_FAIL(boost::format("%1%: %2%") % typeid(ex).name() % ex.what());
    }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>THRIFT-3621 Fix lib/cpp/test/SecurityTest.cpp to use ephemeral ports Client: Test (C++) Patch: John Sirois<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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
 *
 *   http://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. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#define BOOST_TEST_MODULE SecurityTest
#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <thrift/transport/TSSLServerSocket.h>
#include <thrift/transport/TSSLSocket.h>
#include <thrift/transport/TTransport.h>
#include <vector>
#ifdef __linux__
#include <signal.h>
#endif

using apache::thrift::transport::TSSLServerSocket;
using apache::thrift::transport::TServerTransport;
using apache::thrift::transport::TSSLSocket;
using apache::thrift::transport::TSSLSocketFactory;
using apache::thrift::transport::TTransport;
using apache::thrift::transport::TTransportException;
using apache::thrift::transport::TTransportFactory;

boost::filesystem::path keyDir;
boost::filesystem::path certFile(const std::string& filename)
{
    return keyDir / filename;
}
boost::mutex gMutex;

struct GlobalFixture
{
    GlobalFixture()
    {
        using namespace boost::unit_test::framework;
		for (int i = 0; i < master_test_suite().argc; ++i)
		{
			BOOST_TEST_MESSAGE(boost::format("argv[%1%] = \"%2%\"") % i % master_test_suite().argv[i]);
		}

    #ifdef __linux__
		// OpenSSL calls send() without MSG_NOSIGPIPE so writing to a socket that has
		// disconnected can cause a SIGPIPE signal...
		signal(SIGPIPE, SIG_IGN);
    #endif

		TSSLSocketFactory::setManualOpenSSLInitialization(true);
		apache::thrift::transport::initializeOpenSSL();

		keyDir = boost::filesystem::current_path().parent_path().parent_path().parent_path() / "test" / "keys";
		if (!boost::filesystem::exists(certFile("server.crt")))
		{
			keyDir = boost::filesystem::path(master_test_suite().argv[master_test_suite().argc - 1]);
			if (!boost::filesystem::exists(certFile("server.crt")))
			{
				throw std::invalid_argument("The last argument to this test must be the directory containing the test certificate(s).");
			}
		}
    }

    virtual ~GlobalFixture()
    {
		apache::thrift::transport::cleanupOpenSSL();
#ifdef __linux__
		signal(SIGPIPE, SIG_DFL);
#endif
    }
};

#if (BOOST_VERSION >= 105900)
BOOST_GLOBAL_FIXTURE(GlobalFixture);
#else
BOOST_GLOBAL_FIXTURE(GlobalFixture)
#endif

struct SecurityFixture
{
    void server(apache::thrift::transport::SSLProtocol protocol)
    {
        try
        {
            boost::mutex::scoped_lock lock(mMutex);

            boost::shared_ptr<TSSLSocketFactory> pServerSocketFactory;
            boost::shared_ptr<TSSLServerSocket> pServerSocket;

            pServerSocketFactory.reset(new TSSLSocketFactory(static_cast<apache::thrift::transport::SSLProtocol>(protocol)));
            pServerSocketFactory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
            pServerSocketFactory->loadCertificate(certFile("server.crt").string().c_str());
            pServerSocketFactory->loadPrivateKey(certFile("server.key").string().c_str());
            pServerSocketFactory->server(true);
            pServerSocket.reset(new TSSLServerSocket("localhost", 0, pServerSocketFactory));
            boost::shared_ptr<TTransport> connectedClient;

            try
            {
                pServerSocket->listen();
                mPort = pServerSocket->getPort();
                mCVar.notify_one();
                lock.unlock();

                connectedClient = pServerSocket->accept();
                uint8_t buf[2];
                buf[0] = 'O';
                buf[1] = 'K';
                connectedClient->write(&buf[0], 2);
                connectedClient->flush();
            }

            catch (apache::thrift::transport::TTransportException& ex)
            {
                boost::mutex::scoped_lock lock(gMutex);
                BOOST_TEST_MESSAGE(boost::format("SRV %1% Exception: %2%") % boost::this_thread::get_id() % ex.what());
            }

            if (connectedClient)
            {
                connectedClient->close();
                connectedClient.reset();
            }

            pServerSocket->close();
            pServerSocket.reset();
        }
        catch (std::exception& ex)
        {
            BOOST_FAIL(boost::format("%1%: %2%") % typeid(ex).name() % ex.what());
        }
    }

    void client(apache::thrift::transport::SSLProtocol protocol)
    {
        try
        {
            boost::shared_ptr<TSSLSocketFactory> pClientSocketFactory;
            boost::shared_ptr<TSSLSocket> pClientSocket;

            try
            {
                pClientSocketFactory.reset(new TSSLSocketFactory(static_cast<apache::thrift::transport::SSLProtocol>(protocol)));
                pClientSocketFactory->authenticate(true);
                pClientSocketFactory->loadCertificate(certFile("client.crt").string().c_str());
                pClientSocketFactory->loadPrivateKey(certFile("client.key").string().c_str());
                pClientSocketFactory->loadTrustedCertificates(certFile("CA.pem").string().c_str());
                pClientSocket = pClientSocketFactory->createSocket("localhost", mPort);
                pClientSocket->open();

                uint8_t buf[3];
                buf[0] = 0;
                buf[1] = 0;
                BOOST_CHECK_EQUAL(2, pClientSocket->read(&buf[0], 2));
                BOOST_CHECK_EQUAL(0, memcmp(&buf[0], "OK", 2));
                mConnected = true;
            }
            catch (apache::thrift::transport::TTransportException& ex)
            {
                boost::mutex::scoped_lock lock(gMutex);
                BOOST_TEST_MESSAGE(boost::format("CLI %1% Exception: %2%") % boost::this_thread::get_id() % ex.what());
            }

            if (pClientSocket)
            {
                pClientSocket->close();
                pClientSocket.reset();
            }
        }
        catch (std::exception& ex)
        {
            BOOST_FAIL(boost::format("%1%: %2%") % typeid(ex).name() % ex.what());
        }
    }

    static const char *protocol2str(size_t protocol)
    {
        static const char *strings[apache::thrift::transport::LATEST + 1] =
        {
                "SSLTLS",
                "SSLv2",
                "SSLv3",
                "TLSv1_0",
                "TLSv1_1",
                "TLSv1_2"
        };
        return strings[protocol];
    }

    boost::mutex mMutex;
    boost::condition_variable mCVar;
    int mPort;
    bool mConnected;
};

BOOST_FIXTURE_TEST_SUITE(BOOST_TEST_MODULE, SecurityFixture)

BOOST_AUTO_TEST_CASE(ssl_security_matrix)
{
    try
    {
        // matrix of connection success between client and server with different SSLProtocol selections
        bool matrix[apache::thrift::transport::LATEST + 1][apache::thrift::transport::LATEST + 1] =
        {
    //   server    = SSLTLS   SSLv2    SSLv3    TLSv1_0  TLSv1_1  TLSv1_2
    // client
    /* SSLTLS  */  { true,    false,   false,   true,    true,    true    },
    /* SSLv2   */  { false,   false,   false,   false,   false,   false   },
    /* SSLv3   */  { false,   false,   true,    false,   false,   false   },
    /* TLSv1_0 */  { true,    false,   false,   true,    false,   false   },
    /* TLSv1_1 */  { true,    false,   false,   false,   true,    false   },
    /* TLSv1_2 */  { true,    false,   false,   false,   false,   true    }
        };

        for (size_t si = 0; si <= apache::thrift::transport::LATEST; ++si)
        {
            for (size_t ci = 0; ci <= apache::thrift::transport::LATEST; ++ci)
            {
                if (si == 1 || ci == 1)
                {
                    // Skip all SSLv2 cases - protocol not supported
                    continue;
                }

                boost::mutex::scoped_lock lock(mMutex);

                BOOST_TEST_MESSAGE(boost::format("TEST: Server = %1%, Client = %2%")
                    % protocol2str(si) % protocol2str(ci));

                mConnected = false;
                boost::thread_group threads;
                threads.create_thread(boost::bind(&SecurityFixture::server, this, static_cast<apache::thrift::transport::SSLProtocol>(si)));
                mCVar.wait(lock);           // wait for listen() to succeed
                lock.unlock();
                threads.create_thread(boost::bind(&SecurityFixture::client, this, static_cast<apache::thrift::transport::SSLProtocol>(ci)));
                threads.join_all();

                BOOST_CHECK_MESSAGE(mConnected == matrix[ci][si],
                        boost::format("      Server = %1%, Client = %2% expected mConnected == %3% but was %4%")
                            % protocol2str(si) % protocol2str(ci) % matrix[ci][si] % mConnected);
            }
        }
    }
    catch (std::exception& ex)
    {
        BOOST_FAIL(boost::format("%1%: %2%") % typeid(ex).name() % ex.what());
    }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#pragma once
/*
* Covariant Script C/C++ Native Interface Extension
*
* Licensed under the Covariant Innovation General Public License,
* Version 1.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://covariant.cn/licenses/LICENSE-1.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.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2019 Michael Lee(李登淳)
* Email: mikecovlee@163.com
* Github: https://github.com/mikecovlee
*/
#include <covscript/core/core.hpp>

namespace cs_impl {
// Compatible Type Conversions
// bool->cs::boolean
// signed short int->cs::number
	template<>
	struct type_conversion_cs<signed short int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<signed short int> {
		using target_type=cs::number;
	};
// unsigned short int->cs::number
	template<>
	struct type_conversion_cs<unsigned short int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<unsigned short int> {
		using target_type=cs::number;
	};
// signed int->cs::number
	template<>
	struct type_conversion_cs<signed int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<signed int> {
		using target_type=cs::number;
	};
// unsigned int->cs::number
	template<>
	struct type_conversion_cs<unsigned int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<unsigned int> {
		using target_type=cs::number;
	};
// signed long int->cs::number
	template<>
	struct type_conversion_cs<signed long int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<signed long int> {
		using target_type=cs::number;
	};
// unsigned long int->cs::number
	template<>
	struct type_conversion_cs<unsigned long int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<unsigned long int> {
		using target_type=cs::number;
	};
// signed long long int->cs::number
	template<>
	struct type_conversion_cs<signed long long int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<signed long long int> {
		using target_type=cs::number;
	};
// unsigned long long int->cs::number
	template<>
	struct type_conversion_cs<unsigned long long int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<unsigned long long int> {
		using target_type=cs::number;
	};
// signed char->cs::char
	template<>
	struct type_conversion_cs<signed char> {
		using source_type=char;
	};

	template<>
	struct type_conversion_cpp<signed char> {
		using target_type=char;
	};
// unsigned char->cs::char
	template<>
	struct type_conversion_cs<unsigned char> {
		using source_type=char;
	};

	template<>
	struct type_conversion_cpp<unsigned char> {
		using target_type=char;
	};
// float->cs::number
	template<>
	struct type_conversion_cs<float> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<float> {
		using target_type=cs::number;
	};
// double->cs::number
	template<>
	struct type_conversion_cs<double> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<double> {
		using target_type=cs::number;
	};
// long double->cs::number
	template<>
	struct type_conversion_cs<long double> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<long double> {
		using target_type=cs::number;
	};
// std::string->cs::string
// const char*->cs::string
	template<>
	struct type_conversion_cs<const char*> {
		using source_type=cs::string;
	};

	template<>
	struct type_conversion_cpp<const char*> {
		using target_type=cs::string;
	};

	template<>
	struct type_convertor<cs::string, const char*> {
		template<typename T>
		static const char* convert(const cs::string& str)
		{
			return str.c_str();
		}
	};
}

namespace cni_namespace_impl {
	class cni_register final {
	public:
		template<typename T>
		cni_register(const cs::namespace_t& ns, const char* name, T&& val)
		{
			ns->add_var(name, std::forward<T>(val));
		}
	};
}

#define CNI_NAME_MIXER(PREFIX, NAME) static cni_namespace_impl::cni_register PREFIX##NAME
#define CNI_REGISTER(NAME, ARGS) CNI_NAME_MIXER(_cni_register_, NAME)(__cni_namespace, #NAME, ARGS);
#define BEGIN_CNI_ROOT_NAMESPACE namespace __cni_root_namespace{cs::namespace_t __cni_namespace=cs::make_shared_namespace<cs::name_space>();
#define END_CNI_ROOT_NAMESAPCE }void cs_extension_main(cs::name_space *ns) {ns->copy_namespace(*__cni_root_namespace::__cni_namespace);}
#define BEGIN_CNI_NAMESPACE(NAME) namespace NAME{cs::namespace_t __cni_namespace=cs::make_shared_namespace<cs::name_space>();
#define END_CNI_NAMESPACE(NAME) } CNI_REGISTER(NAME, cs::make_namespace(NAME::__cni_namespace))
#define CNI_NORMAL(NAME) CNI_REGISTER(NAME, cs::make_cni(NAME, false))
#define CNI_CONST(NAME) CNI_REGISTER(NAME, cs::make_cni(NAME, true))<commit_msg>Update cni.hpp<commit_after>#pragma once
/*
* Covariant Script C/C++ Native Interface Extension
*
* Licensed under the Covariant Innovation General Public License,
* Version 1.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://covariant.cn/licenses/LICENSE-1.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.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright (C) 2019 Michael Lee(李登淳)
* Email: mikecovlee@163.com
* Github: https://github.com/mikecovlee
*/
#include <covscript/core/core.hpp>

// Define this macro to disable all standard type conversion
#ifndef CNI_DISABLE_STD_CONVERSION
namespace cs_impl {
// Compatible Type Conversions
// bool->cs::boolean
// signed short int->cs::number
	template<>
	struct type_conversion_cs<signed short int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<signed short int> {
		using target_type=cs::number;
	};
// unsigned short int->cs::number
	template<>
	struct type_conversion_cs<unsigned short int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<unsigned short int> {
		using target_type=cs::number;
	};
// signed int->cs::number
	template<>
	struct type_conversion_cs<signed int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<signed int> {
		using target_type=cs::number;
	};
// unsigned int->cs::number
	template<>
	struct type_conversion_cs<unsigned int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<unsigned int> {
		using target_type=cs::number;
	};
// signed long int->cs::number
	template<>
	struct type_conversion_cs<signed long int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<signed long int> {
		using target_type=cs::number;
	};
// unsigned long int->cs::number
	template<>
	struct type_conversion_cs<unsigned long int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<unsigned long int> {
		using target_type=cs::number;
	};
// signed long long int->cs::number
	template<>
	struct type_conversion_cs<signed long long int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<signed long long int> {
		using target_type=cs::number;
	};
// unsigned long long int->cs::number
	template<>
	struct type_conversion_cs<unsigned long long int> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<unsigned long long int> {
		using target_type=cs::number;
	};
// signed char->cs::char
	template<>
	struct type_conversion_cs<signed char> {
		using source_type=char;
	};

	template<>
	struct type_conversion_cpp<signed char> {
		using target_type=char;
	};
// unsigned char->cs::char
	template<>
	struct type_conversion_cs<unsigned char> {
		using source_type=char;
	};

	template<>
	struct type_conversion_cpp<unsigned char> {
		using target_type=char;
	};
// float->cs::number
	template<>
	struct type_conversion_cs<float> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<float> {
		using target_type=cs::number;
	};
// double->cs::number
	template<>
	struct type_conversion_cs<double> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<double> {
		using target_type=cs::number;
	};
// long double->cs::number
	template<>
	struct type_conversion_cs<long double> {
		using source_type=cs::number;
	};

	template<>
	struct type_conversion_cpp<long double> {
		using target_type=cs::number;
	};
// std::string->cs::string
// const char*->cs::string
	template<>
	struct type_conversion_cs<const char*> {
		using source_type=cs::string;
	};

	template<>
	struct type_conversion_cpp<const char*> {
		using target_type=cs::string;
	};

	template<>
	struct type_convertor<cs::string, const char*> {
		template<typename T>
		static const char* convert(const cs::string& str)
		{
			return str.c_str();
		}
	};
}
#endif

namespace cni_namespace_impl {
	class cni_register final {
	public:
		template<typename T>
		cni_register(const cs::namespace_t& ns, const char* name, T&& val)
		{
			ns->add_var(name, std::forward<T>(val));
		}
	};
}

#define CNI_NAME_MIXER(PREFIX, NAME) static cni_namespace_impl::cni_register PREFIX##NAME
#define CNI_REGISTER(NAME, ARGS) CNI_NAME_MIXER(_cni_register_, NAME)(__cni_namespace, #NAME, ARGS);
#define BEGIN_CNI_ROOT_NAMESPACE namespace __cni_root_namespace{cs::namespace_t __cni_namespace=cs::make_shared_namespace<cs::name_space>();
#define END_CNI_ROOT_NAMESAPCE }void cs_extension_main(cs::name_space *ns) {ns->copy_namespace(*__cni_root_namespace::__cni_namespace);}
#define BEGIN_CNI_NAMESPACE(NAME) namespace NAME{cs::namespace_t __cni_namespace=cs::make_shared_namespace<cs::name_space>();
#define END_CNI_NAMESPACE(NAME) } CNI_REGISTER(NAME, cs::make_namespace(NAME::__cni_namespace))
#define CNI_NORMAL(NAME) CNI_REGISTER(NAME, cs::make_cni(NAME, false))
#define CNI_CONST(NAME) CNI_REGISTER(NAME, cs::make_cni(NAME, true))<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2013 libczmq++ developers (see AUTHORS)
 *
 * This file is part of libczmq++.
 *
 * libczmq++ is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef LIBCZMQPP_SOCKET_HPP
#define LIBCZMQPP_SOCKET_HPP

#include <string>
#include <czmq++/define.hpp>
#include <czmq++/context.hpp>

namespace czmqpp {

class CZMQPP_API socket
{
public:
    socket();
    socket(void* self);
    socket(socket&& other);
    socket(const socket&) = delete;
    socket(context& ctx, int type);

    // context will delete the self_ for us.
    // We can call this explicitly though.
    void destroy(context& ctx);

    void* self();
    void* self() const;

#include "socket_opt.hpp"

    int bind(const std::string& address);
    int connect(const std::string& address);

private:
    void* self_;
};

bool operator==(const socket& sock_a, const socket& sock_b);

} // namespace czmqpp

#endif

<commit_msg>Make operator == linkable again<commit_after>/*
 * Copyright (c) 2011-2013 libczmq++ developers (see AUTHORS)
 *
 * This file is part of libczmq++.
 *
 * libczmq++ is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef LIBCZMQPP_SOCKET_HPP
#define LIBCZMQPP_SOCKET_HPP

#include <string>
#include <czmq++/define.hpp>
#include <czmq++/context.hpp>

namespace czmqpp {

class CZMQPP_API socket
{
public:
    socket();
    socket(void* self);
    socket(socket&& other);
    socket(const socket&) = delete;
    socket(context& ctx, int type);

    // context will delete the self_ for us.
    // We can call this explicitly though.
    void destroy(context& ctx);

    void* self();
    void* self() const;

#include "socket_opt.hpp"

    int bind(const std::string& address);
    int connect(const std::string& address);

private:
    void* self_;
};

CZMQPP_API bool operator==(const socket& sock_a, const socket& sock_b);

} // namespace czmqpp

#endif

<|endoftext|>


<commit_before>#pragma once
#ifndef IBOTPP_LOADER_HPP
#define IBOTPP_LOADER_HPP

#include <string>
#include <boost/container/vector.hpp>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/raw_ostream.h>

namespace ibotpp {
	class loader {
	private:
		llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diag_ids;
		llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diag_options;
		clang::DiagnosticsEngine diag_engine;
		llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> invocation;
		clang::CompilerInstance compiler;

	public:
		loader(void)
				: diag_ids(new clang::DiagnosticIDs()),
				  diag_options(new clang::DiagnosticOptions()),
				  diag_engine(diag_ids, diag_options.get(),
					new clang::TextDiagnosticPrinter(llvm::errs(), diag_options.get())),
				  invocation(new clang::CompilerInvocation()) {
			compiler.createDiagnostics();
			if(!compiler.hasDiagnostics()) {
				throw std::runtime_error("compiler instance does not have diagnostics");
			}
		}

		std::unique_ptr<llvm::Module> load(const std::string &path) {
			boost::container::vector<const char *> args;
			args.emplace_back(path.c_str());
			clang::CompilerInvocation::CreateFromArgs(*invocation, args.data(),
			                                          args.data() + args.size(),
			                                          diag_engine);
			compiler.setInvocation(invocation.get());
			clang::EmitLLVMOnlyAction action;
			if(!compiler.ExecuteAction(action)) {
				throw std::runtime_error("failed to execute action");
			}
			return action.takeModule();
		}
	};
}

#endif
<commit_msg>loader: require module.pch to be included<commit_after>#pragma once
#ifndef IBOTPP_LOADER_HPP
#define IBOTPP_LOADER_HPP

#include <string>
#include <boost/container/vector.hpp>
#include <clang/CodeGen/CodeGenAction.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/raw_ostream.h>

namespace ibotpp {
	class loader {
	private:
		llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diag_ids;
		llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diag_options;
		clang::DiagnosticsEngine diag_engine;
		llvm::IntrusiveRefCntPtr<clang::CompilerInvocation> invocation;
		clang::CompilerInstance compiler;

	public:
		loader(void)
				: diag_ids(new clang::DiagnosticIDs()),
				  diag_options(new clang::DiagnosticOptions()),
				  diag_engine(diag_ids, diag_options.get(),
					new clang::TextDiagnosticPrinter(llvm::errs(), diag_options.get())),
				  invocation(new clang::CompilerInvocation()) {
			compiler.createDiagnostics();
			if(!compiler.hasDiagnostics()) {
				throw std::runtime_error("compiler instance does not have diagnostics");
			}
		}

		std::unique_ptr<llvm::Module> load(const std::string &path) {
			return load_llvm_module(path);
		}

		std::unique_ptr<llvm::Module> load_llvm_module(const std::string &path) {
			boost::container::vector<const char *> args;
			args.emplace_back("-include-pch");
			args.emplace_back("module.pch");
			args.emplace_back(path.c_str());
			clang::CompilerInvocation::CreateFromArgs(*invocation, args.data(),
			                                          args.data() + args.size(),
			                                          diag_engine);
			compiler.setInvocation(invocation.get());
			clang::EmitLLVMOnlyAction action;
			if(!compiler.ExecuteAction(action)) {
				throw std::runtime_error("failed to execute action");
			}
			return action.takeModule();
		}
	};
}

#endif
<|endoftext|>


<commit_before>#pragma once

#ifndef SIPL_IMPROC_IMPROC_H
#define SIPL_IMPROC_IMPROC_H

#include <limits>
#include "matrix/Vector.hpp"
#include "matrix/Matrix.hpp"
#include "improc/NearestNeighborInterpolator.hpp"
#include "improc/BilinearInterpolator.hpp"
#include "improc/Utility.hpp"

namespace sipl
{

enum class InterpolateType { NEAREST_NEIGHBOR, BILINEAR };

// Specialized inverse for mat33d
static inline Matrix33d inv(const Matrix33d& m)
{
    double determinant = m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) -
                         m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
                         m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0));
    Matrix33d inverse = {{m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1),
                          m(0, 2) * m(2, 1) - m(0, 1) * m(2, 2),
                          m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)},
                         {m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2),
                          m(0, 0) * m(2, 2) - m(0, 2) * m(2, 0),
                          m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)},
                         {m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0),
                          m(0, 1) * m(2, 0) - m(0, 0) * m(2, 1),
                          m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)}};
    return inverse / determinant;
}

template <typename ElementType, typename InternalType>
MatrixX<ElementType> projective_transform(const MatrixX<ElementType>& image,
                                          const Matrix33d& transform,
                                          const InterpolateType interpolator)
{
    // 1. Figure out sizes of new matrix
    auto c0 = homogenize(transform * Vector3d{0, 0, 1});
    auto c1 = homogenize(transform * Vector3d{0, image.dims[0], 1});
    auto c2 = homogenize(transform * Vector3d{image.dims[1], 0, 1});
    auto c3 = homogenize(transform * Vector3d{image.dims[1], image.dims[0], 1});

    // Raise or lower values as needed
    for (int32_t i = 0; i < 3; ++i) {
        c0[i] = std::round(c0[i]);
    }
    for (int32_t i = 0; i < 3; ++i) {
        c1[i] = std::round(c1[i]);
    }
    for (int32_t i = 0; i < 3; ++i) {
        c2[i] = std::round(c2[i]);
    }
    for (int32_t i = 0; i < 3; ++i) {
        c3[i] = std::round(c3[i]);
    }

    int32_t ymin = int32_t(std::min({c0[1], c1[1], c2[1], c3[1]}));
    int32_t ymax = int32_t(std::max({c0[1], c1[1], c2[1], c3[1]}));
    int32_t xmin = int32_t(std::min({c0[0], c1[0], c2[0], c3[0]}));
    int32_t xmax = int32_t(std::max({c0[0], c1[0], c2[0], c3[0]}));

    // Create new matrix
    Matrix33d inverse = inv(transform);
    MatrixX<ElementType> new_image(ymax - ymin, xmax - xmin);

    // Start filling it
    for (int32_t i = 0; i < new_image.dims[0]; ++i) {
        for (int32_t j = 0; j < new_image.dims[1]; ++j) {
            Vector3d uv{j + xmin, i + ymin, 1};
            Vector3d xy = homogenize(inverse * uv);
            const double x = xy[0];
            const double y = xy[1];

            // Skip any points outside image space
            if (x < 0 || int32_t(x) >= image.dims[1] || y < 0 ||
                int32_t(y) >= image.dims[0]) {
                new_image(i, j) = ElementType(0);
                continue;
            }

            // Need to interpolate
            switch (interpolator) {
            case InterpolateType::NEAREST_NEIGHBOR:
                new_image(i, j) =
                    NearestNeighborInterpolator::interpolate<ElementType,
                                                             InternalType>(
                        image, x, y);
                break;
            case InterpolateType::BILINEAR:
                new_image(i, j) =
                    BilinearInterpolator::interpolate<ElementType,
                                                      InternalType>(
                        image, x, y);
                break;
            }
        }
    }

    return new_image;
}

MatrixX<uint8_t> color_to_grayscale(const MatrixX<RgbPixel>& color)
{
    MatrixX<uint8_t> grayscale(color.dims[0], color.dims[1]);
    for (int32_t i = 0; i < color.dims[0]; ++i) {
        for (int32_t j = 0; j < color.dims[1]; ++j) {
            RgbPixel p = color(i, j);
            grayscale(i, j) = clamp(0.299 * p[0] + 0.587 * p[1] + 0.114 * p[2]);
        }
    }

    return grayscale;
}

// XXX only works for integral-typed matrices for now, need to figure out how to
// get it to work for Vector-type matrices
template <typename Dtype>
MatrixX<Dtype> rotate_image(
    const MatrixX<Dtype>& in_mat,
    const double degrees,
    const InterpolateType type = InterpolateType::BILINEAR)
{
    const double rads = degrees * M_PI / 180;
    Matrix33d rotation_matrix{{std::cos(rads), std::sin(rads), 0},
                              {-std::sin(rads), std::cos(rads), 0},
                              {0, 0, 1}};
    return projective_transform<Dtype, double>(in_mat, rotation_matrix, type);
}

template <typename Dtype>
VectorX<int32_t> histogram(const MatrixX<Dtype>& mat)
{
    const auto max = std::numeric_limits<Dtype>::max();
    VectorX<int32_t> hist(max);
    for (int32_t i = 0; i < mat.size(); ++i) {
        hist[mat[i]]++;
    }
    return hist;
}
}

#endif
<commit_msg>Change return type of histogram to be uint32_t since we won't have negative numbers<commit_after>#pragma once

#ifndef SIPL_IMPROC_IMPROC_H
#define SIPL_IMPROC_IMPROC_H

#include <limits>
#include "matrix/Vector.hpp"
#include "matrix/Matrix.hpp"
#include "improc/NearestNeighborInterpolator.hpp"
#include "improc/BilinearInterpolator.hpp"
#include "improc/Utility.hpp"

namespace sipl
{

enum class InterpolateType { NEAREST_NEIGHBOR, BILINEAR };

// Specialized inverse for mat33d
static inline Matrix33d inv(const Matrix33d& m)
{
    double determinant = m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) -
                         m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
                         m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0));
    Matrix33d inverse = {{m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1),
                          m(0, 2) * m(2, 1) - m(0, 1) * m(2, 2),
                          m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)},
                         {m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2),
                          m(0, 0) * m(2, 2) - m(0, 2) * m(2, 0),
                          m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)},
                         {m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0),
                          m(0, 1) * m(2, 0) - m(0, 0) * m(2, 1),
                          m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)}};
    return inverse / determinant;
}

template <typename ElementType, typename InternalType>
MatrixX<ElementType> projective_transform(const MatrixX<ElementType>& image,
                                          const Matrix33d& transform,
                                          const InterpolateType interpolator)
{
    // 1. Figure out sizes of new matrix
    auto c0 = homogenize(transform * Vector3d{0, 0, 1});
    auto c1 = homogenize(transform * Vector3d{0, image.dims[0], 1});
    auto c2 = homogenize(transform * Vector3d{image.dims[1], 0, 1});
    auto c3 = homogenize(transform * Vector3d{image.dims[1], image.dims[0], 1});

    // Raise or lower values as needed
    for (int32_t i = 0; i < 3; ++i) {
        c0[i] = std::round(c0[i]);
    }
    for (int32_t i = 0; i < 3; ++i) {
        c1[i] = std::round(c1[i]);
    }
    for (int32_t i = 0; i < 3; ++i) {
        c2[i] = std::round(c2[i]);
    }
    for (int32_t i = 0; i < 3; ++i) {
        c3[i] = std::round(c3[i]);
    }

    int32_t ymin = int32_t(std::min({c0[1], c1[1], c2[1], c3[1]}));
    int32_t ymax = int32_t(std::max({c0[1], c1[1], c2[1], c3[1]}));
    int32_t xmin = int32_t(std::min({c0[0], c1[0], c2[0], c3[0]}));
    int32_t xmax = int32_t(std::max({c0[0], c1[0], c2[0], c3[0]}));

    // Create new matrix
    Matrix33d inverse = inv(transform);
    MatrixX<ElementType> new_image(ymax - ymin, xmax - xmin);

    // Start filling it
    for (int32_t i = 0; i < new_image.dims[0]; ++i) {
        for (int32_t j = 0; j < new_image.dims[1]; ++j) {
            Vector3d uv{j + xmin, i + ymin, 1};
            Vector3d xy = homogenize(inverse * uv);
            const double x = xy[0];
            const double y = xy[1];

            // Skip any points outside image space
            if (x < 0 || int32_t(x) >= image.dims[1] || y < 0 ||
                int32_t(y) >= image.dims[0]) {
                new_image(i, j) = ElementType(0);
                continue;
            }

            // Need to interpolate
            switch (interpolator) {
            case InterpolateType::NEAREST_NEIGHBOR:
                new_image(i, j) =
                    NearestNeighborInterpolator::interpolate<ElementType,
                                                             InternalType>(
                        image, x, y);
                break;
            case InterpolateType::BILINEAR:
                new_image(i, j) =
                    BilinearInterpolator::interpolate<ElementType,
                                                      InternalType>(
                        image, x, y);
                break;
            }
        }
    }

    return new_image;
}

MatrixX<uint8_t> color_to_grayscale(const MatrixX<RgbPixel>& color)
{
    MatrixX<uint8_t> grayscale(color.dims[0], color.dims[1]);
    for (int32_t i = 0; i < color.dims[0]; ++i) {
        for (int32_t j = 0; j < color.dims[1]; ++j) {
            RgbPixel p = color(i, j);
            grayscale(i, j) = clamp(0.299 * p[0] + 0.587 * p[1] + 0.114 * p[2]);
        }
    }

    return grayscale;
}

// XXX only works for integral-typed matrices for now, need to figure out how to
// get it to work for Vector-type matrices
template <typename Dtype>
MatrixX<Dtype> rotate_image(
    const MatrixX<Dtype>& in_mat,
    const double degrees,
    const InterpolateType type = InterpolateType::BILINEAR)
{
    const double rads = degrees * M_PI / 180;
    Matrix33d rotation_matrix{{std::cos(rads), std::sin(rads), 0},
                              {-std::sin(rads), std::cos(rads), 0},
                              {0, 0, 1}};
    return projective_transform<Dtype, double>(in_mat, rotation_matrix, type);
}

template <typename Dtype>
VectorX<uint32_t> histogram(const MatrixX<Dtype>& mat)
{
    const auto max = std::numeric_limits<Dtype>::max();
    VectorX<uint32_t> hist(max);
    for (int32_t i = 0; i < mat.size(); ++i) {
        hist[mat[i]]++;
    }
    return hist;
}
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file libport/cmath.hxx
/// \brief Portable <cmath>

# include <libport/config.h>

namespace libport
{

  /*--------.
  | round.  |
  `--------*/

# if defined LIBPORT_HAVE_ROUND
#  define ROUND_IF(True, False) True
# else
#  define ROUND_IF(True, False) False
# endif

# define ROUND(Type)                                            \
  inline Type round(Type v)                                     \
  {                                                             \
    return                                                      \
      ROUND_IF(::round(v),                                      \
               std::sgn(v) * std::floor(std::fabs(v) + 0.5));   \
  }
  ROUND(float);
  ROUND(double);
  ROUND(long double);

# undef ROUND
# undef ROUND_IF

  /*--------.
  | trunc.  |
  `--------*/

# if defined LIBPORT_HAVE_TRUNC
#  define TRUNC_IF(True, False) True
# else
#  define TRUNC_IF(True, False) False
# endif

# define TRUNC(Type)                                            \
  inline Type trunc(Type v)                                     \
  {                                                             \
    return                                                      \
      TRUNC_IF(::trunc(v),                                      \
               v < 0. ? ceil(v) : floor(v));                    \
  }
  TRUNC(float);
  TRUNC(double);
  TRUNC(long double);

# undef TRUNC
# undef TRUNC_IF

}
<commit_msg>msvc: use ::sgn, not std::sgn.<commit_after>/*
 * Copyright (C) 2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file libport/cmath.hxx
/// \brief Portable <cmath>

# include <libport/config.h>

namespace libport
{

  /*--------.
  | round.  |
  `--------*/

# if defined LIBPORT_HAVE_ROUND
#  define ROUND_IF(True, False) True
# else
#  define ROUND_IF(True, False) False
# endif

# define ROUND(Type)                                            \
  inline Type round(Type v)                                     \
  {                                                             \
    return                                                      \
      ROUND_IF(::round(v),                                      \
               (v < 0. ? -1. : 1.0)                             \
               * std::floor(std::fabs(v) + 0.5));               \
  }
  ROUND(float);
  ROUND(double);
  ROUND(long double);

# undef ROUND
# undef ROUND_IF

  /*--------.
  | trunc.  |
  `--------*/

# if defined LIBPORT_HAVE_TRUNC
#  define TRUNC_IF(True, False) True
# else
#  define TRUNC_IF(True, False) False
# endif

# define TRUNC(Type)                                            \
  inline Type trunc(Type v)                                     \
  {                                                             \
    return                                                      \
      TRUNC_IF(::trunc(v),                                      \
               v < 0. ? ceil(v) : floor(v));                    \
  }
  TRUNC(float);
  TRUNC(double);
  TRUNC(long double);

# undef TRUNC
# undef TRUNC_IF

}
<|endoftext|>


<commit_before>/**
 ** \file libport/timer.hxx
 ** \brief Inline methods for libport/timer.hh.
 */

#ifndef LIBPORT_TIMER_HXX
# define LIBPORT_TIMER_HXX

# include <libport/timer.hh>
# include <libport/contract.hh>

namespace libport
{

  inline
  void
  timer::push(int i)
  {
    precondition(intmap.find(i) != intmap.end());
    push(intmap[i]);
  }

  inline
  void
  timer::pop(const std::string& task_name)
  {
    precondition(tasksmap[task_name] == tasks.top());
    pop();
  }

  inline
  void
  timer::pop(const int i)
  {
    pop(intmap[i]);
  }

  inline
  void
  timer::dump_on_destruction(std::ostream& out)
  {
    dump_stream = &out;
  }

  inline
  void
  timer::start()
  {
    total.start();
  }

  inline
  void
  timer::stop()
  {
    total.stop();
  }

  inline
  timer::time::time() :
    user(0), sys(0), wall(0)
  { }

  inline
  timer::time&
  timer::time::operator +=(const time& rhs)
  {
    wall += rhs.wall;
    user += rhs.user;
    sys += rhs.sys;
    return *this;
  }

} // namespace libport

#endif // !LIBPORT_TIMER_HXX
<commit_msg>NDEBUG fix.<commit_after>/**
 ** \file libport/timer.hxx
 ** \brief Inline methods for libport/timer.hh.
 */

#ifndef LIBPORT_TIMER_HXX
# define LIBPORT_TIMER_HXX

# include <libport/timer.hh>
# include <libport/contract.hh>

namespace libport
{

  inline
  void
  timer::push(int i)
  {
    precondition(intmap.find(i) != intmap.end());
    push(intmap[i]);
  }

  inline
  void
  timer::pop(const std::string&
# ifndef NDEBUG
             task_name
# endif
    )
  {
    precondition(tasksmap[task_name] == tasks.top());
    pop();
  }

  inline
  void
  timer::pop(const int i)
  {
    pop(intmap[i]);
  }

  inline
  void
  timer::dump_on_destruction(std::ostream& out)
  {
    dump_stream = &out;
  }

  inline
  void
  timer::start()
  {
    total.start();
  }

  inline
  void
  timer::stop()
  {
    total.stop();
  }

  inline
  timer::time::time() :
    user(0), sys(0), wall(0)
  { }

  inline
  timer::time&
  timer::time::operator +=(const time& rhs)
  {
    wall += rhs.wall;
    user += rhs.user;
    sys += rhs.sys;
    return *this;
  }

} // namespace libport

#endif // !LIBPORT_TIMER_HXX
<|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.

#include <Rosetta/Games/Game.hpp>
#include <Rosetta/Models/Entity.hpp>
#include <Rosetta/Models/Player.hpp>
#include <Rosetta/Models/Spell.hpp>

#include <utility>

namespace RosettaStone
{
Entity::Entity(Player& _owner, Card& _card, std::map<GameTag, int> tags)
    : owner(&_owner), card(_card), m_gameTags(std::move(tags))
{
    for (auto& gameTag : _card.gameTags)
    {
        Entity::SetGameTag(gameTag.first, gameTag.second);
    }

    id = tags[GameTag::ENTITY_ID];
    auraEffects = new AuraEffects(this);
}

Entity::Entity(const Entity& ent)
{
    FreeMemory();

    owner = ent.owner;
    card = ent.card;

    auraEffects = ent.auraEffects;
    onGoingEffect = ent.onGoingEffect;
    m_gameTags = ent.m_gameTags;
}

Entity::Entity(Entity&& ent) noexcept
{
    FreeMemory();

    owner = ent.owner;
    card = ent.card;

    auraEffects = ent.auraEffects;
    onGoingEffect = ent.onGoingEffect;
    m_gameTags = ent.m_gameTags;
}

Entity::~Entity()
{
    FreeMemory();
}

Entity& Entity::operator=(const Entity& ent)
{
    if (this == &ent)
    {
        return *this;
    }

    FreeMemory();

    owner = ent.owner;
    card = ent.card;

    auraEffects = ent.auraEffects;
    onGoingEffect = ent.onGoingEffect;
    m_gameTags = ent.m_gameTags;

    return *this;
}

Entity& Entity::operator=(Entity&& ent) noexcept
{
    if (this == &ent)
    {
        return *this;
    }

    FreeMemory();

    owner = ent.owner;
    card = ent.card;

    auraEffects = ent.auraEffects;
    onGoingEffect = ent.onGoingEffect;
    m_gameTags = ent.m_gameTags;

    return *this;
}

void Entity::Reset()
{
    SetGameTag(GameTag::DAMAGE, 0);
    SetGameTag(GameTag::EXHAUSTED, 0);
    SetGameTag(GameTag::ATK, 0);
    SetGameTag(GameTag::HEALTH, 0);
    SetGameTag(GameTag::COST, 0);
    SetGameTag(GameTag::TAUNT, 0);
    SetGameTag(GameTag::FROZEN, 0);
    SetGameTag(GameTag::CHARGE, 0);
    SetGameTag(GameTag::WINDFURY, 0);
    SetGameTag(GameTag::DIVINE_SHIELD, 0);
    SetGameTag(GameTag::STEALTH, 0);
    SetGameTag(GameTag::NUM_ATTACKS_THIS_TURN, 0);
}

int Entity::GetGameTag(GameTag tag) const
{
    int value = 0;

    if (m_gameTags.find(tag) == m_gameTags.end())
    {
        if (auraEffects != nullptr)
        {
            value += auraEffects->GetGameTag(tag);
        }
    }
    else
    {
        value += m_gameTags.at(tag);

        if (auraEffects != nullptr)
        {
            value += auraEffects->GetGameTag(tag);
        }
    }

    return value > 0 ? value : 0;
}

void Entity::SetGameTag(GameTag tag, int value)
{
    m_gameTags.insert_or_assign(tag, value);
}

ZoneType Entity::GetZoneType() const
{
    return static_cast<ZoneType>(GetGameTag(GameTag::ZONE));
}

void Entity::SetZoneType(ZoneType type)
{
    SetGameTag(GameTag::ZONE, static_cast<int>(type));
}

int Entity::GetCost() const
{
    return GetGameTag(GameTag::COST);
}

void Entity::SetCost(int cost)
{
    SetGameTag(GameTag::COST, cost);
}

bool Entity::IsExhausted() const
{
    return GetGameTag(GameTag::EXHAUSTED) == 1;
}

void Entity::SetExhausted(bool exhausted)
{
    SetGameTag(GameTag::EXHAUSTED, static_cast<int>(exhausted));
}

bool Entity::HasCombo() const
{
    return GetGameTag(GameTag::COMBO) == 1;
}

bool Entity::HasOverload() const
{
    return GetGameTag(GameTag::OVERLOAD) > 0;
}

int Entity::GetOverload() const
{
    return GetGameTag(GameTag::OVERLOAD);
}

void Entity::Destroy()
{
    isDestroyed = true;
}

Entity* Entity::GetFromCard(Player& player, Card&& card,
                            std::optional<std::map<GameTag, int>> cardTags,
                            IZone* zone, int id)
{
    std::map<GameTag, int> tags;
    if (cardTags.has_value())
    {
        tags = cardTags.value();
    }

    tags[GameTag::ENTITY_ID] = id > 0 ? id : player.GetGame()->GetNextID();
    tags[GameTag::CONTROLLER] = player.playerID;
    tags[GameTag::ZONE] =
        zone != nullptr ? static_cast<int>(zone->GetType()) : 0;

    Entity* result;

    switch (card.GetCardType())
    {
        case CardType::HERO:
            result = new Hero(player, card, tags);
            break;
        case CardType::HERO_POWER:
            result = new HeroPower(player, card, tags);
            break;
        case CardType::MINION:
            result = new Minion(player, card, tags);
            break;
        case CardType::SPELL:
            result = new Spell(player, card, tags);
            break;
        case CardType::WEAPON:
            result = new Weapon(player, card, tags);
            break;
        default:
            throw std::invalid_argument(
                "Generic::DrawCard() - Invalid card type!");
    }

    return result;
}

void Entity::FreeMemory()
{
    delete auraEffects;
    delete onGoingEffect;

    m_gameTags.clear();
}
}  // namespace RosettaStone
<commit_msg>fix: Change code to set value 0 to erase it<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.

#include <Rosetta/Games/Game.hpp>
#include <Rosetta/Models/Entity.hpp>
#include <Rosetta/Models/Player.hpp>
#include <Rosetta/Models/Spell.hpp>

#include <utility>

namespace RosettaStone
{
Entity::Entity(Player& _owner, Card& _card, std::map<GameTag, int> tags)
    : owner(&_owner), card(_card), m_gameTags(std::move(tags))
{
    for (auto& gameTag : _card.gameTags)
    {
        Entity::SetGameTag(gameTag.first, gameTag.second);
    }

    id = tags[GameTag::ENTITY_ID];
    auraEffects = new AuraEffects(this);
}

Entity::Entity(const Entity& ent)
{
    FreeMemory();

    owner = ent.owner;
    card = ent.card;

    auraEffects = ent.auraEffects;
    onGoingEffect = ent.onGoingEffect;
    m_gameTags = ent.m_gameTags;
}

Entity::Entity(Entity&& ent) noexcept
{
    FreeMemory();

    owner = ent.owner;
    card = ent.card;

    auraEffects = ent.auraEffects;
    onGoingEffect = ent.onGoingEffect;
    m_gameTags = ent.m_gameTags;
}

Entity::~Entity()
{
    FreeMemory();
}

Entity& Entity::operator=(const Entity& ent)
{
    if (this == &ent)
    {
        return *this;
    }

    FreeMemory();

    owner = ent.owner;
    card = ent.card;

    auraEffects = ent.auraEffects;
    onGoingEffect = ent.onGoingEffect;
    m_gameTags = ent.m_gameTags;

    return *this;
}

Entity& Entity::operator=(Entity&& ent) noexcept
{
    if (this == &ent)
    {
        return *this;
    }

    FreeMemory();

    owner = ent.owner;
    card = ent.card;

    auraEffects = ent.auraEffects;
    onGoingEffect = ent.onGoingEffect;
    m_gameTags = ent.m_gameTags;

    return *this;
}

void Entity::Reset()
{
    m_gameTags.erase(GameTag::DAMAGE);
    m_gameTags.erase(GameTag::EXHAUSTED);
    m_gameTags.erase(GameTag::ATK);
    m_gameTags.erase(GameTag::HEALTH);
    m_gameTags.erase(GameTag::COST);
    m_gameTags.erase(GameTag::TAUNT);
    m_gameTags.erase(GameTag::FROZEN);
    m_gameTags.erase(GameTag::CHARGE);
    m_gameTags.erase(GameTag::WINDFURY);
    m_gameTags.erase(GameTag::DIVINE_SHIELD);
    m_gameTags.erase(GameTag::STEALTH);
    m_gameTags.erase(GameTag::NUM_ATTACKS_THIS_TURN);
}

int Entity::GetGameTag(GameTag tag) const
{
    int value = 0;

    if (m_gameTags.find(tag) == m_gameTags.end())
    {
        if (auraEffects != nullptr)
        {
            value += auraEffects->GetGameTag(tag);
        }
    }
    else
    {
        value += m_gameTags.at(tag);

        if (auraEffects != nullptr)
        {
            value += auraEffects->GetGameTag(tag);
        }
    }

    return value > 0 ? value : 0;
}

void Entity::SetGameTag(GameTag tag, int value)
{
    m_gameTags.insert_or_assign(tag, value);
}

ZoneType Entity::GetZoneType() const
{
    return static_cast<ZoneType>(GetGameTag(GameTag::ZONE));
}

void Entity::SetZoneType(ZoneType type)
{
    SetGameTag(GameTag::ZONE, static_cast<int>(type));
}

int Entity::GetCost() const
{
    return GetGameTag(GameTag::COST);
}

void Entity::SetCost(int cost)
{
    SetGameTag(GameTag::COST, cost);
}

bool Entity::IsExhausted() const
{
    return GetGameTag(GameTag::EXHAUSTED) == 1;
}

void Entity::SetExhausted(bool exhausted)
{
    SetGameTag(GameTag::EXHAUSTED, static_cast<int>(exhausted));
}

bool Entity::HasCombo() const
{
    return GetGameTag(GameTag::COMBO) == 1;
}

bool Entity::HasOverload() const
{
    return GetGameTag(GameTag::OVERLOAD) > 0;
}

int Entity::GetOverload() const
{
    return GetGameTag(GameTag::OVERLOAD);
}

void Entity::Destroy()
{
    isDestroyed = true;
}

Entity* Entity::GetFromCard(Player& player, Card&& card,
                            std::optional<std::map<GameTag, int>> cardTags,
                            IZone* zone, int id)
{
    std::map<GameTag, int> tags;
    if (cardTags.has_value())
    {
        tags = cardTags.value();
    }

    tags[GameTag::ENTITY_ID] = id > 0 ? id : player.GetGame()->GetNextID();
    tags[GameTag::CONTROLLER] = player.playerID;
    tags[GameTag::ZONE] =
        zone != nullptr ? static_cast<int>(zone->GetType()) : 0;

    Entity* result;

    switch (card.GetCardType())
    {
        case CardType::HERO:
            result = new Hero(player, card, tags);
            break;
        case CardType::HERO_POWER:
            result = new HeroPower(player, card, tags);
            break;
        case CardType::MINION:
            result = new Minion(player, card, tags);
            break;
        case CardType::SPELL:
            result = new Spell(player, card, tags);
            break;
        case CardType::WEAPON:
            result = new Weapon(player, card, tags);
            break;
        default:
            throw std::invalid_argument(
                "Generic::DrawCard() - Invalid card type!");
    }

    return result;
}

void Entity::FreeMemory()
{
    delete auraEffects;
    delete onGoingEffect;

    m_gameTags.clear();
}
}  // namespace RosettaStone
<|endoftext|>


<commit_before>// Copyright (c) 2018 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.

#include <hspp/Cards/Cards.hpp>
#include <hspp/Models/GameAgent.hpp>
#include <hspp/Policies/Policy.hpp>
#include <hspp/Tasks/PlayerTasks/CombatTask.hpp>
#include <hspp/Tasks/PlayerTasks/GameEndTask.hpp>
#include <hspp/Tasks/PlayerTasks/MulliganTask.hpp>
#include <hspp/Tasks/PlayerTasks/PlayCardTask.hpp>
#include <hspp/Tasks/PlayerTasks/PlayerSettingTask.hpp>
#include <hspp/Tasks/SimpleTasks/DrawTask.hpp>
#include <hspp/Tasks/SimpleTasks/InitAttackCountTask.hpp>
#include <hspp/Tasks/SimpleTasks/ModifyManaTask.hpp>
#include <hspp/Tasks/TaskStatus.hpp>
#include <hspp/Tasks/TaskWrapper.hpp>

#include <random>

using namespace Hearthstonepp::PlayerTasks;
using namespace Hearthstonepp::SimpleTasks;

namespace Hearthstonepp
{
GameAgent::GameAgent(CardClass p1Class, CardClass p2Class, IPolicy* p1Policy,
                     IPolicy* p2Policy, PlayerType firstPlayer)
    : m_game(p1Class, p2Class, firstPlayer)
{
    m_game.GetPlayer1().SetPolicy(p1Policy);
    m_game.GetPlayer2().SetPolicy(p2Policy);
}

GameResult GameAgent::Start()
{
    BeginPhase();

    while (true)
    {
        const bool isGameEnd = MainPhase();
        if (isGameEnd)
        {
            break;
        }
    }

    FinalPhase();

    return GameResult();
}

Game& GameAgent::GetGame()
{
    return m_game;
}

const Game& GameAgent::GetGame() const
{
    return m_game;
}

void GameAgent::BeginPhase()
{
    std::random_device rd;
    std::default_random_engine gen(rd());

    // Get random number: zero or one.
    std::uniform_int_distribution<int> bin(0, 1);

    // Swap user with 50% probability
    if (bin(gen) == 1)
    {
        m_game.SetFirstPlayer(PlayerType::PLAYER1);
        m_game.SetCurrentPlayer(PlayerType::PLAYER1);
    }
    else
    {
        m_game.SetFirstPlayer(PlayerType::PLAYER2);
        m_game.SetCurrentPlayer(PlayerType::PLAYER2);
    }

    Player& firstPlayer = m_game.GetFirstPlayer();
    Player& secondPlayer = m_game.GetFirstPlayer().GetOpponent();

    // Task list of begin phase
    // 1. Both players shuffle the deck.
    // 2. Both players draw cards from the deck.
    // NOTE: The player going first will be given 3 cards
    // while the player going second will be given 4 cards.
    // 3. Both players enter the mulligan stage.
    // NOTE: Each player is shown their randomly selected starting hand and is
    // given the option to redraw as many of those cards as they like. Only one
    // redraw of the selected cards is allowed; there is no chance to redraw
    // again after seeing the results.
    // 4. The player going second receives "The Coin" card.
    // NOTE: The Coin is a special uncollectible spell card granted at the start
    // of each game to whichever player is selected to go second.
    Task::Run(m_game.GetFirstPlayer(), PlayerSettingTask());

    firstPlayer.GetDeck().Shuffle();
    secondPlayer.GetDeck().Shuffle();

    Task::RunMulti(firstPlayer, DrawTask(NUM_DRAW_CARDS_AT_START_FIRST),
                   DoUntil(MulliganTask(), TaskStatus::MULLIGAN_SUCCESS));

    Task::RunMulti(secondPlayer, DrawTask(NUM_DRAW_CARDS_AT_START_SECOND),
                   DoUntil(MulliganTask(), TaskStatus::MULLIGAN_SUCCESS));

    Card coin = Cards::GetInstance().FindCardByID("GAME_005");
    secondPlayer.GetHand().AddCard(
        *Entity::GetFromCard(secondPlayer, std::move(coin)));
}

bool GameAgent::MainPhase()
{
    // Ready for main phase
    PrepareMainPhase();

    // NOTE: It returns isGameEnd flag
    return ProcessMainMenu();
}

void GameAgent::FinalPhase()
{
    Task::Run(m_game.GetCurrentPlayer(), GameEndTask());
}

void GameAgent::PrepareMainPhase()
{
    // Task list of prepare main phase
    // 1. Draw a card from deck.
    // 2. Gain a new mana crystal. (increase maximum mana by 1)
    // NOTE: A player can never have more than 10 maximum mana.
    // 3. Refill all of their non-overloaded mana crystals.
    // 4. Initialize attack count of minions and hero.
    Task::RunMulti(
        m_game.GetCurrentPlayer(), DrawTask(1),
        ModifyManaTask(ManaOperator::ADD, ManaType::MAXIMUM, 1),
        ModifyManaTask(ManaOperator::SET, ManaType::AVAILABLE,
                       m_game.GetCurrentPlayer().GetMaximumMana() + 1),
        InitAttackCountTask());
}

bool GameAgent::ProcessMainMenu()
{
    // Check before starting main phase
    if (IsGameOver())
    {
        return true;
    }

    TaskMeta meta = m_game.GetCurrentPlayer().GetPolicy().Next(m_game);

    // Interface pass menu by the status of TaskMeta
    const auto menu = static_cast<status_t>(meta.GetStatus());

    if (menu == GAME_MAIN_MENU_SIZE - 1)
    {
        // End main end phase
        m_game.FlipCurrentPlayer();
    }
    else
    {
        if (menu < GAME_MAIN_MENU_SIZE - 1)
        {
            // Call action method
            m_mainMenuFuncs[menu](*this);
        }

        // NOTE: It returns isGameEnd flag
        return ProcessMainMenu();
    }

    return false;
}

void GameAgent::PlayCard()
{
    Task::Run(m_game.GetCurrentPlayer(), PlayCardTask());
}

void GameAgent::Combat()
{
    Task::Run(m_game.GetCurrentPlayer(), CombatTask(nullptr, nullptr));
}

bool GameAgent::IsGameOver()
{
    const int healthCurrent = m_game.GetPlayer1().GetHero()->health;
    const int healthOpponent = m_game.GetPlayer2().GetHero()->health;

    return healthCurrent <= 0 || healthOpponent <= 0;
}
}  // namespace Hearthstonepp<commit_msg>[ci skip] [WIP] refactor: Comment Game class related function calls<commit_after>// Copyright (c) 2018 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.

#include <hspp/Cards/Cards.hpp>
#include <hspp/Models/GameAgent.hpp>
#include <hspp/Policies/Policy.hpp>
#include <hspp/Tasks/PlayerTasks/CombatTask.hpp>
#include <hspp/Tasks/PlayerTasks/GameEndTask.hpp>
#include <hspp/Tasks/PlayerTasks/MulliganTask.hpp>
#include <hspp/Tasks/PlayerTasks/PlayCardTask.hpp>
#include <hspp/Tasks/PlayerTasks/PlayerSettingTask.hpp>
#include <hspp/Tasks/SimpleTasks/DrawTask.hpp>
#include <hspp/Tasks/SimpleTasks/InitAttackCountTask.hpp>
#include <hspp/Tasks/SimpleTasks/ModifyManaTask.hpp>
#include <hspp/Tasks/TaskStatus.hpp>
#include <hspp/Tasks/TaskWrapper.hpp>

#include <random>

using namespace Hearthstonepp::PlayerTasks;
using namespace Hearthstonepp::SimpleTasks;

namespace Hearthstonepp
{
GameAgent::GameAgent(CardClass p1Class, CardClass p2Class, IPolicy* p1Policy,
                     IPolicy* p2Policy, PlayerType firstPlayer)
    : m_game(p1Class, p2Class, firstPlayer)
{
    m_game.GetPlayer1().SetPolicy(p1Policy);
    m_game.GetPlayer2().SetPolicy(p2Policy);
}

GameResult GameAgent::Start()
{
    BeginPhase();

    while (true)
    {
        const bool isGameEnd = MainPhase();
        if (isGameEnd)
        {
            break;
        }
    }

    FinalPhase();

    return GameResult();
}

Game& GameAgent::GetGame()
{
    return m_game;
}

const Game& GameAgent::GetGame() const
{
    return m_game;
}

void GameAgent::BeginPhase()
{
    std::random_device rd;
    std::default_random_engine gen(rd());

    // Get random number: zero or one.
    std::uniform_int_distribution<int> bin(0, 1);

    // Swap user with 50% probability
    //if (bin(gen) == 1)
    //{
    //    m_game.SetFirstPlayer(PlayerType::PLAYER1);
    //    m_game.SetCurrentPlayer(PlayerType::PLAYER1);
    //}
    //else
    //{
    //    m_game.SetFirstPlayer(PlayerType::PLAYER2);
    //    m_game.SetCurrentPlayer(PlayerType::PLAYER2);
    //}

    //Player& firstPlayer = m_game.GetFirstPlayer();
    //Player& secondPlayer = m_game.GetFirstPlayer().GetOpponent();

    // Task list of begin phase
    // 1. Both players shuffle the deck.
    // 2. Both players draw cards from the deck.
    // NOTE: The player going first will be given 3 cards
    // while the player going second will be given 4 cards.
    // 3. Both players enter the mulligan stage.
    // NOTE: Each player is shown their randomly selected starting hand and is
    // given the option to redraw as many of those cards as they like. Only one
    // redraw of the selected cards is allowed; there is no chance to redraw
    // again after seeing the results.
    // 4. The player going second receives "The Coin" card.
    // NOTE: The Coin is a special uncollectible spell card granted at the start
    // of each game to whichever player is selected to go second.
    //Task::Run(m_game.GetFirstPlayer(), PlayerSettingTask());

    //firstPlayer.GetDeck().Shuffle();
    //secondPlayer.GetDeck().Shuffle();

    //Task::RunMulti(firstPlayer, DrawTask(NUM_DRAW_CARDS_AT_START_FIRST),
    //               DoUntil(MulliganTask(), TaskStatus::MULLIGAN_SUCCESS));

    //Task::RunMulti(secondPlayer, DrawTask(NUM_DRAW_CARDS_AT_START_SECOND),
    //               DoUntil(MulliganTask(), TaskStatus::MULLIGAN_SUCCESS));

    //Card coin = Cards::GetInstance().FindCardByID("GAME_005");
    //secondPlayer.GetHand().AddCard(
    //    *Entity::GetFromCard(secondPlayer, std::move(coin)));
}

bool GameAgent::MainPhase()
{
    // Ready for main phase
    PrepareMainPhase();

    // NOTE: It returns isGameEnd flag
    return ProcessMainMenu();
}

void GameAgent::FinalPhase()
{
    //Task::Run(m_game.GetCurrentPlayer(), GameEndTask());
}

void GameAgent::PrepareMainPhase()
{
    // Task list of prepare main phase
    // 1. Draw a card from deck.
    // 2. Gain a new mana crystal. (increase maximum mana by 1)
    // NOTE: A player can never have more than 10 maximum mana.
    // 3. Refill all of their non-overloaded mana crystals.
    // 4. Initialize attack count of minions and hero.
    //Task::RunMulti(
    //    m_game.GetCurrentPlayer(), DrawTask(1),
    //    ModifyManaTask(ManaOperator::ADD, ManaType::MAXIMUM, 1),
    //    ModifyManaTask(ManaOperator::SET, ManaType::AVAILABLE,
    //                   m_game.GetCurrentPlayer().GetMaximumMana() + 1),
    //    InitAttackCountTask());
}

bool GameAgent::ProcessMainMenu()
{
    //// Check before starting main phase
    //if (IsGameOver())
    //{
    //    return true;
    //}

    //TaskMeta meta = m_game.GetCurrentPlayer().GetPolicy().Next(m_game);

    //// Interface pass menu by the status of TaskMeta
    //const auto menu = static_cast<status_t>(meta.GetStatus());

    //if (menu == GAME_MAIN_MENU_SIZE - 1)
    //{
    //    // End main end phase
    //    m_game.FlipCurrentPlayer();
    //}
    //else
    //{
    //    if (menu < GAME_MAIN_MENU_SIZE - 1)
    //    {
    //        // Call action method
    //        m_mainMenuFuncs[menu](*this);
    //    }

    //    // NOTE: It returns isGameEnd flag
    //    return ProcessMainMenu();
    //}

    return false;
}

void GameAgent::PlayCard()
{
    //Task::Run(m_game.GetCurrentPlayer(), PlayCardTask());
}

void GameAgent::Combat()
{
    //Task::Run(m_game.GetCurrentPlayer(), CombatTask(nullptr, nullptr));
}

bool GameAgent::IsGameOver()
{
    const int healthCurrent = m_game.GetPlayer1().GetHero()->health;
    const int healthOpponent = m_game.GetPlayer2().GetHero()->health;

    return healthCurrent <= 0 || healthOpponent <= 0;
}
}  // namespace Hearthstonepp<|endoftext|>


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

/*
 * File:   float_sse.hpp
 * Author: annas
 *
 * Created on 7. April 2017, 23:30
 */

#ifndef FLOAT_SSE_HPP
#define FLOAT_SSE_HPP

#include "config.h"
#ifdef ASSTL_USE_SSE

#include <mmintrin.h>
#include <emmintrin.h>
#include <pmmintrin.h>

#include "../algorithm.hpp"
#include "../common.hpp"
#include "../unknown.hpp"

#include "vector2.hpp"
#include "vector3.hpp"
#include "vector4.hpp"

namespace std
{
    namespace math {
        class alignas(16) vecf_sse;

        using vec2f_sse = vecf_sse;
        using vec3f_sse = vecf_sse;
        using vec4f_sse = vecf_sse;

        class alignas(16) vecf_sse : public object {
        public:
            vecf_sse () { m_xmm = _mm_set1_ps(0); }
            vecf_sse (__m128 v) : m_xmm (v) {}
            vecf_sse (const vecf_sse &v) { m_xmm = v.m_xmm; }

            vecf_sse (float v) { m_xmm = _mm_set1_ps(v); }
            vecf_sse (float x, float y) { m_xmm = _mm_set_ps(0,0,y,x); }
            vecf_sse (float x, float y, float z) { m_xmm = _mm_set_ps(0,z,y,x); }
            vecf_sse (float x, float y, float z, float w) { m_xmm = _mm_set_ps(w,z,y,x); }

            vecf_sse (const vec2f &v) { m_xmm = _mm_set_ps(0,0,v.y,v.x); }
            vecf_sse (const vec3f &v) { m_xmm = _mm_set_ps(0,v.z,v.y,v.x); }
            vecf_sse (const vec4f &v) { m_xmm = _mm_set_ps(v.w,v.z,v.y,v.x); }

            vecf_sse (const float *v) { m_xmm = _mm_load_ps(v); }

            float X () const { return ((float*)&m_xmm)[0]; }
            float Y () const { return ((float*)&m_xmm)[1]; }
            float Z () const { return ((float*)&m_xmm)[2]; }
            float W () const { return ((float*)&m_xmm)[3]; }

            __m128 M()  { return m_xmm; }

            void operator *= (const vecf_sse &v) { m_xmm = _mm_mul_ps(m_xmm, v.m_xmm); }
            void operator += (const vecf_sse &v) { m_xmm = _mm_add_ps(m_xmm, v.m_xmm); }
            void operator -= (const vecf_sse &v) { m_xmm = _mm_sub_ps(m_xmm, v.m_xmm); }
            void operator /= (const vecf_sse &v) { m_xmm = _mm_div_ps(m_xmm, v.m_xmm); }

            operator vec2f () { return vec2f(X(), Y()); }
            operator vec3f () { return vec3f(X(), Y(), Z()); }
            operator vec4f () { return vec4f(X(), Y(), Z(), W()); }

        private:
            __m128 m_xmm;
        };
        inline vecf_sse operator + (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_add_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator - (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_sub_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator * (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_mul_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator / (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_div_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator & (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_and_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator ^ (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_xor_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator | (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_or_ps(a.M(), b.M() ));
        }
        inline bool operator == (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() == b.X()) && (a.Y() == b.Y()) && (a.Z() == b.Z()) &&
                    (a.W() == b.W()));
        }
        inline bool operator != (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() != b.X()) && (a.Y() != b.Y()) && (a.Z() != b.Z()) &&
                    (a.W() != b.W()));
        }
        inline bool operator <= (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() <= b.X()) && (a.Y() <= b.Y()) && (a.Z() <= b.Z()) &&
                    (a.W() <= b.W()));
        }
        inline bool operator >= (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() >= b.X()) && (a.Y() >= b.Y()) && (a.Z() >= b.Z()) &&
                    (a.W() >= b.W()));
        }
        inline bool operator < (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() < b.X()) && (a.Y() < b.Y()) && (a.Z() < b.Z()) &&
                    (a.W() < b.W()));
        }
        inline bool operator > (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() > b.X()) && (a.Y() > b.Y()) && (a.Z() > b.Z()) &&
                    (a.W() > b.W()));
        }

        inline vecf_sse shuffle (const vecf_sse &v, int a, int b, int c, int d) const {
            return vecf_sse( _mm_shuffle_ps(v.M(), v.M(), _MM_SHUFFLE(d,c,b,a) ) );
        }
        inline vecf_sse shuffle (const vecf_sse &v1, const vecf_sse &v2, int a, int b, int c, int d) const {
            return vecf_sse( _mm_shuffle_ps(v1.M(), v2.M(), _MM_SHUFFLE(d,c,b,a) ) );
        }
        inline vecf_sse hadd (const vecf_sse &v) const {
            return vecf_sse(_mm_hadd_ps(v.M(), v.M() ));
        }
        inline vecf_sse hadd (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_hadd_ps(a.M(), b.M() ));
        }
        inline vecf_sse hsub (const vecf_sse &v) const {
            return vecf_sse(_mm_hsub_ps(v.M(), v.M() ));
        }
        inline vecf_sse hsub (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_hsub_ps(a.M(), b.M() ));
        }
        inline float sum (const vecf_sse& v) const {
            vecf_sse s = hadd(hadd(v), v);
            float t; _mm_store_ss(&t, s.M());
            return t;
        }
        inline float dot (const vecf_sse &a, const vecf_sse &b) const {
            return sum(a * b);
        }
        inline vecf_sse sqrt (const vecf_sse &v) const {
            return vecf_sse(_mm_sqrt_ps(v.M() ));
        }
        inline vecf_sse rsqrt (const vecf_sse &v) const {
            return vecf_sse(_mm_rsqrt_ps(v.M() ));
        }
        inline vecf_sse min (const vecf_sse &v) const {
            return vecf_sse(_mm_min_ps(v.M() ));
        }
        inline vecf_sse max (const vecf_sse &v) const {
            return vecf_sse(_mm_max_ps(v.M() ));
        }
        inline vecf_sse andnot (const vecf_sse &v) const {
            return vecf_sse(_mm_andnot_ps(v.M() ));
        }
        inline vecf_sse rcp (const vecf_sse &v) const {
            return vecf_sse(_mm_rcp_ps(v.M() ));
        }

    }
}

#endif

#endif /* FLOAT_SSE_HPP */

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

/*
 * File:   float_sse.hpp
 * Author: annas
 *
 * Created on 7. April 2017, 23:30
 */

#ifndef FLOAT_SSE_HPP
#define FLOAT_SSE_HPP

#include "config.h"
#ifdef ASSTL_USE_SSE

#include <mmintrin.h>
#include <emmintrin.h>
#include <pmmintrin.h>

#include "../algorithm.hpp"
#include "../common.hpp"
#include "../unknown.hpp"

namespace std
{
    namespace math {
        class alignas(16) vecf_sse;

        using vec2f_sse = vecf_sse;
        using vec3f_sse = vecf_sse;
        using vec4f_sse = vecf_sse;

        class alignas(16) vecf_sse : public object {
        public:
            vecf_sse () { m_xmm = _mm_set1_ps(0); }
            vecf_sse (__m128 v) : m_xmm (v) {}
            vecf_sse (const vecf_sse &v) { m_xmm = v.m_xmm; }

            vecf_sse (float v) { m_xmm = _mm_set1_ps(v); }
            vecf_sse (float x, float y) { m_xmm = _mm_set_ps(0,0,y,x); }
            vecf_sse (float x, float y, float z) { m_xmm = _mm_set_ps(0,z,y,x); }
            vecf_sse (float x, float y, float z, float w) { m_xmm = _mm_set_ps(w,z,y,x); }

            vecf_sse (const float *v) { m_xmm = _mm_load_ps(v); }

            float X () const { return ((float*)&m_xmm)[0]; }
            float Y () const { return ((float*)&m_xmm)[1]; }
            float Z () const { return ((float*)&m_xmm)[2]; }
            float W () const { return ((float*)&m_xmm)[3]; }

            __m128 M()  { return m_xmm; }

            void operator *= (const vecf_sse &v) { m_xmm = _mm_mul_ps(m_xmm, v.m_xmm); }
            void operator += (const vecf_sse &v) { m_xmm = _mm_add_ps(m_xmm, v.m_xmm); }
            void operator -= (const vecf_sse &v) { m_xmm = _mm_sub_ps(m_xmm, v.m_xmm); }
            void operator /= (const vecf_sse &v) { m_xmm = _mm_div_ps(m_xmm, v.m_xmm); }

        private:
            __m128 m_xmm;
        };
        inline vecf_sse operator + (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_add_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator - (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_sub_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator * (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_mul_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator / (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_div_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator & (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_and_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator ^ (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_xor_ps(a.M(), b.M() ));
        }
        inline vecf_sse operator | (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_or_ps(a.M(), b.M() ));
        }
        inline bool operator == (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() == b.X()) && (a.Y() == b.Y()) && (a.Z() == b.Z()) &&
                    (a.W() == b.W()));
        }
        inline bool operator != (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() != b.X()) && (a.Y() != b.Y()) && (a.Z() != b.Z()) &&
                    (a.W() != b.W()));
        }
        inline bool operator <= (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() <= b.X()) && (a.Y() <= b.Y()) && (a.Z() <= b.Z()) &&
                    (a.W() <= b.W()));
        }
        inline bool operator >= (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() >= b.X()) && (a.Y() >= b.Y()) && (a.Z() >= b.Z()) &&
                    (a.W() >= b.W()));
        }
        inline bool operator < (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() < b.X()) && (a.Y() < b.Y()) && (a.Z() < b.Z()) &&
                    (a.W() < b.W()));
        }
        inline bool operator > (const vecf_sse& a, const vecf_sse& b) {
            return ((a.X() > b.X()) && (a.Y() > b.Y()) && (a.Z() > b.Z()) &&
                    (a.W() > b.W()));
        }

        inline vecf_sse shuffle (const vecf_sse &v, int a, int b, int c, int d) const {
            return vecf_sse( _mm_shuffle_ps(v.M(), v.M(), _MM_SHUFFLE(d,c,b,a) ) );
        }
        inline vecf_sse shuffle (const vecf_sse &v1, const vecf_sse &v2, int a, int b, int c, int d) const {
            return vecf_sse( _mm_shuffle_ps(v1.M(), v2.M(), _MM_SHUFFLE(d,c,b,a) ) );
        }
        inline vecf_sse hadd (const vecf_sse &v) const {
            return vecf_sse(_mm_hadd_ps(v.M(), v.M() ));
        }
        inline vecf_sse hadd (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_hadd_ps(a.M(), b.M() ));
        }
        inline vecf_sse hsub (const vecf_sse &v) const {
            return vecf_sse(_mm_hsub_ps(v.M(), v.M() ));
        }
        inline vecf_sse hsub (const vecf_sse &a, const vecf_sse &b) const {
            return vecf_sse(_mm_hsub_ps(a.M(), b.M() ));
        }
        inline float sum (const vecf_sse& v) const {
            vecf_sse s = hadd(hadd(v), v);
            float t; _mm_store_ss(&t, s.M());
            return t;
        }
        inline float dot (const vecf_sse &a, const vecf_sse &b) const {
            return sum(a * b);
        }
        inline vecf_sse sqrt (const vecf_sse &v) const {
            return vecf_sse(_mm_sqrt_ps(v.M() ));
        }
        inline vecf_sse rsqrt (const vecf_sse &v) const {
            return vecf_sse(_mm_rsqrt_ps(v.M() ));
        }
        inline vecf_sse min (const vecf_sse &v) const {
            return vecf_sse(_mm_min_ps(v.M() ));
        }
        inline vecf_sse max (const vecf_sse &v) const {
            return vecf_sse(_mm_max_ps(v.M() ));
        }
        inline vecf_sse andnot (const vecf_sse &v) const {
            return vecf_sse(_mm_andnot_ps(v.M() ));
        }
        inline vecf_sse rcp (const vecf_sse &v) const {
            return vecf_sse(_mm_rcp_ps(v.M() ));
        }
    }
}

#endif

#endif /* FLOAT_SSE_HPP */

<|endoftext|>