<commit_before>#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <silicium/error_or.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/filesystem/operations.hpp>

namespace buildserver
{
	Si::error_or<bool> file_exists(boost::filesystem::path const &candidate)
	{
		boost::system::error_code ec;
		boost::filesystem::file_status status = boost::filesystem::status(candidate, ec);
		if (status.type() == boost::filesystem::file_not_found)
		{
			return false;
		}
		if (ec)
		{
			return ec;
		}
		return true;
	}

	Si::error_or<boost::optional<boost::filesystem::path>> find_file_in_directories(
		boost::filesystem::path const &filename,
		std::vector<boost::filesystem::path> const &directories)
	{
		for (auto const &directory : directories)
		{
			auto candidate = directory / filename;
			auto result = file_exists(candidate);
			if (result.is_error())
			{
				return result.error();
			}
			if (result.get())
			{
				return std::move(candidate);
			}
		}
		return boost::none;
	}

	Si::error_or<boost::optional<boost::filesystem::path>> find_executable_unix(
		boost::filesystem::path const &filename,
		std::vector<boost::filesystem::path> additional_directories)
	{
		additional_directories.emplace_back("/bin");
		additional_directories.emplace_back("/usr/bin");
		additional_directories.emplace_back("/usr/local/bin");
		return find_file_in_directories(filename, additional_directories);
	}

	struct gcc_location
	{
		boost::filesystem::path gcc, gxx;
	};

	Si::error_or<boost::optional<gcc_location>> find_gcc_unix()
	{
		auto gcc = find_executable_unix("gcc", {});
		if (gcc.is_error())
		{
			return gcc.error();
		}
		if (!gcc.get())
		{
			return boost::none;
		}
		auto gxx = find_file_in_directories("g++", {gcc.get()->parent_path()});
		return Si::map(std::move(gxx), [&gcc](boost::optional<boost::filesystem::path> gxx_path) -> boost::optional<gcc_location>
		{
			if (gxx_path)
			{
				gcc_location result;
				result.gcc = std::move(*gcc.get());
				result.gxx = std::move(*gxx_path);
				return result;
			}
			else
			{
				return boost::none;
			}
		});
	}
}
BOOST_AUTO_TEST_CASE(find_executable_unix_test)
{
	BOOST_CHECK_EQUAL(boost::none, buildserver::find_executable_unix("does-not-exist", {}));

#ifndef _WIN32
	BOOST_CHECK_EQUAL(boost::filesystem::path("/bin/sh"), buildserver::find_executable_unix("sh", {}));
	BOOST_CHECK_EQUAL(boost::none, buildserver::find_file_in_directories("sh", {}));

	auto gnuc = buildserver::find_gcc_unix();
	BOOST_REQUIRE(gnuc.get());
	BOOST_CHECK_EQUAL("/usr/bin/gcc", gnuc.get()->gcc);
	BOOST_CHECK_EQUAL("/usr/bin/g++", gnuc.get()->gxx);
#endif
}
<commit_msg>implement the CMake driver for Linux in C++<commit_after>#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <silicium/error_or.hpp>
#include <silicium/override.hpp>
#include <silicium/process.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/unordered_map.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread/thread.hpp>

namespace buildserver
{
	Si::error_or<bool> file_exists(boost::filesystem::path const &candidate)
	{
		boost::system::error_code ec;
		boost::filesystem::file_status status = boost::filesystem::status(candidate, ec);
		if (status.type() == boost::filesystem::file_not_found)
		{
			return false;
		}
		if (ec)
		{
			return ec;
		}
		return true;
	}

	Si::error_or<boost::optional<boost::filesystem::path>> find_file_in_directories(
		boost::filesystem::path const &filename,
		std::vector<boost::filesystem::path> const &directories)
	{
		for (auto const &directory : directories)
		{
			auto candidate = directory / filename;
			auto result = file_exists(candidate);
			if (result.is_error())
			{
				return result.error();
			}
			if (result.get())
			{
				return std::move(candidate);
			}
		}
		return boost::none;
	}

	Si::error_or<boost::optional<boost::filesystem::path>> find_executable_unix(
		boost::filesystem::path const &filename,
		std::vector<boost::filesystem::path> additional_directories)
	{
		additional_directories.emplace_back("/bin");
		additional_directories.emplace_back("/usr/bin");
		additional_directories.emplace_back("/usr/local/bin");
		return find_file_in_directories(filename, additional_directories);
	}

	struct gcc_location
	{
		boost::filesystem::path gcc, gxx;
	};

	Si::error_or<boost::optional<gcc_location>> find_gcc_unix()
	{
		auto gcc = find_executable_unix("gcc", {});
		if (gcc.is_error())
		{
			return gcc.error();
		}
		if (!gcc.get())
		{
			return boost::none;
		}
		auto gxx = find_file_in_directories("g++", {gcc.get()->parent_path()});
		return Si::map(std::move(gxx), [&gcc](boost::optional<boost::filesystem::path> gxx_path) -> boost::optional<gcc_location>
		{
			if (gxx_path)
			{
				gcc_location result;
				result.gcc = std::move(*gcc.get());
				result.gxx = std::move(*gxx_path);
				return result;
			}
			else
			{
				return boost::none;
			}
		});
	}

	Si::error_or<boost::optional<boost::filesystem::path>> find_cmake_unix()
	{
		return find_executable_unix("cmake", {});
	}

	struct cmake
	{
		virtual ~cmake()
		{
		}
		virtual boost::system::error_code generate(
			boost::filesystem::path const &source,
			boost::filesystem::path const &build,
			boost::unordered_map<std::string, std::string> const &definitions
		) const = 0;
		virtual boost::system::error_code build(
			boost::filesystem::path const &build,
			unsigned cpu_parallelism
		) const = 0;
	};

	struct cmake_exe : cmake
	{
		explicit cmake_exe(
			boost::filesystem::path exe)
			: m_exe(std::move(exe))
		{
		}

		virtual boost::system::error_code generate(
			boost::filesystem::path const &source,
			boost::filesystem::path const &build,
			boost::unordered_map<std::string, std::string> const &definitions
		) const SILICIUM_OVERRIDE
		{
			std::vector<std::string> arguments;
			arguments.emplace_back(source.string());
			for (auto const &definition : definitions)
			{
				//TODO: is this properly encoded in all cases? I guess not
				auto encoded = "-D" + definition.first + "=" + definition.second;
				arguments.emplace_back(std::move(encoded));
			}
			Si::process_parameters parameters;
			parameters.executable = m_exe;
			parameters.current_path = build;
			parameters.arguments = std::move(arguments);
			int const rc = Si::run_process(parameters);
			if (rc != 0)
			{
				throw std::runtime_error("Unexpected CMake return code");
			}
			return {};
		}

		virtual boost::system::error_code build(
			boost::filesystem::path const &build,
			unsigned cpu_parallelism
		) const SILICIUM_OVERRIDE
		{
			//assuming make..
			std::vector<std::string> arguments{"--build", ".", "--", "-j"};
			arguments.emplace_back(boost::lexical_cast<std::string>(cpu_parallelism));
			Si::process_parameters parameters;
			parameters.executable = m_exe;
			parameters.current_path = build;
			parameters.arguments = std::move(arguments);
			int const rc = Si::run_process(parameters);
			if (rc != 0)
			{
				throw std::runtime_error("Unexpected CMake return code");
			}
			return {};
		}

	private:

		boost::filesystem::path m_exe;
	};
}

BOOST_AUTO_TEST_CASE(find_executable_unix_test)
{
	BOOST_CHECK_EQUAL(boost::none, buildserver::find_executable_unix("does-not-exist", {}));

#ifndef _WIN32
	BOOST_CHECK_EQUAL(boost::filesystem::path("/bin/sh"), buildserver::find_executable_unix("sh", {}));
	BOOST_CHECK_EQUAL(boost::none, buildserver::find_file_in_directories("sh", {}));

	auto gnuc = buildserver::find_gcc_unix();
	BOOST_REQUIRE(gnuc.get());
	BOOST_CHECK_EQUAL("/usr/bin/gcc", gnuc.get()->gcc);
	BOOST_CHECK_EQUAL("/usr/bin/g++", gnuc.get()->gxx);
#endif
}

BOOST_AUTO_TEST_CASE(cmake_exe_test)
{
	auto cmake = buildserver::find_cmake_unix().get();
	BOOST_REQUIRE(cmake);
	buildserver::cmake_exe const cmake_driver(*cmake);
	boost::filesystem::path const build_path = "/tmp/buildtest123456";
	boost::filesystem::remove_all(build_path);
	boost::filesystem::create_directories(build_path);
	boost::filesystem::path const dev_path = boost::filesystem::path(__FILE__).parent_path().parent_path().parent_path();
	cmake_driver.generate(dev_path / "buildserver", build_path, {{"SILICIUM_INCLUDE_DIR", (dev_path / "silicium").string()}});
	cmake_driver.build(build_path, boost::thread::hardware_concurrency());
}
<|endoftext|>


<commit_before>#include "msg_pack.h"
#include "mpi_util.h"

//#include <exception>
//#include "log.h" // temporary include

namespace multiverso
{
    //-- area of static member definition ------------------------------------/
    int MPIUtil::mpi_size_ = 0;
    int MPIUtil::mpi_rank_ = 0;
    std::queue<std::shared_ptr<MsgPack>> MPIUtil::send_queue_;
#if defined (_MPI_VERSION_)
    char MPIUtil::recv_buffer_[kMPIBufferSize];
    MPI_Request MPIUtil::recv_request_ = MPI_REQUEST_NULL;

    char MPIUtil::send_buffer_[kMPIBufferSize];
    MPI_Request MPIUtil::send_request_ = MPI_REQUEST_NULL;
#endif
    //-- end of static member definition -------------------------------------/

#if defined (_MPI_VERSION_)
    // Initializes MPI environment
    void MPIUtil::Init(int *argc, char **argv[])
    {
        int flag = 0;
        MPI_Initialized(&flag); // test if MPI has been initialized
        if (!flag) // if MPI not started, start it
        {
            MPI_Init_thread(argc, argv, MPI_THREAD_SERIALIZED, &flag);
        }
        MPI_Comm_size(MPI_COMM_WORLD, &mpi_size_);
        MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank_);
    }

    // Finalizes MPI environment
    void MPIUtil::Close()
    {
        MPI_Finalize();
    }

    std::shared_ptr<MsgPack> MPIUtil::ProbeAndRecv()
    {
        int flag;
        MPI_Status status;
        // test if there is new message comes
        MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status);
        if (flag) // MPI message arrived
        {
            MPI_Recv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
                status.MPI_TAG, MPI_COMM_WORLD, &status);
            std::shared_ptr<MsgPack> request(
                new MsgPack(recv_buffer_, status.count));
            return request;
        }
        return nullptr;
    }

    //// Try to receive messages with MPI non-blocking receiving method.
    //std::shared_ptr<MsgPack> MPIUtil::MPIProbe()
    //{
    //    try{
    //        int flag;
    //        MPI_Status status;
    //        // if there is message being received
    //        if (recv_request_ != MPI_REQUEST_NULL)
    //        {
    //            // test if the receiving completed
    //            MPI_Test(&recv_request_, &flag, &status);
    //            if (flag) // recv completed, deserialize the data into ZMQ messages
    //            {
    //                recv_request_ = MPI_REQUEST_NULL;
    //                std::shared_ptr<MsgPack> request(
    //                    new MsgPack(recv_buffer_, status.count));
    //                return request;
    //            }
    //            else // recv not completed yet
    //            {
    //                return nullptr;
    //            }
    //        }

    //        // test if there is new message comes
    //        MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status);
    //        if (flag) // MPI message arrived
    //        {
    //            //MPI_Irecv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
    //            //    status.MPI_TAG, MPI_COMM_WORLD, &recv_request_);
    //            MPI_Recv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
    //                status.MPI_TAG, MPI_COMM_WORLD, &status);
    //            std::shared_ptr<MsgPack> request(new MsgPack(recv_buffer_, status.count));
    //            return request;
    //        }
    //        return nullptr;
    //    }
    //    catch (std::exception e)
    //    {
    //        Log::Error("Rank=%d Probe\n", mpi_rank_);
    //        throw e;
    //    }
    //}

    // Send messages with MPI non-blocking sending method. Actually, it pushes
    // the message into the queue (if not null), test if last sending has
    // been completed, and send a new one in the queue if so.
    void MPIUtil::Send(std::shared_ptr<MsgPack> msg_pack)
    {
        static int tag = 0;

        // push the send message into the send queue
        if (msg_pack.get() != nullptr)
        {
            send_queue_.push(msg_pack);
        }

        // test if the last send has been completed, return immediately if not
        if (send_request_ != MPI_REQUEST_NULL)
        {
            MPI_Status status;
            int flag;
            MPI_Test(&send_request_, &flag, &status);
            if (flag) // send completed
            {
                send_request_ = MPI_REQUEST_NULL;
            }
            else
            {
                return;
            }
        }

        // if there is message in the send queue, send it
        if (!send_queue_.empty())
        {
            MsgType msg_type;
            MsgArrow msg_arrow;
            int src, dst, size;
            std::shared_ptr<MsgPack> msg_send = send_queue_.front();
            send_queue_.pop();
            msg_send->GetHeaderInfo(&msg_type, &msg_arrow, &src, &dst);
            // serialize the message into MPI send buffer
            msg_send->Serialize(send_buffer_, &size);
            MPI_Isend(send_buffer_, size, MPI_BYTE, dst, tag++, MPI_COMM_WORLD,
                &send_request_);
        }
    }
#endif
}
<commit_msg>fix bug for an irregular usage of MPI<commit_after>#include "msg_pack.h"
#include "mpi_util.h"

//#include <exception>
//#include "log.h" // temporary include

namespace multiverso
{
    //-- area of static member definition ------------------------------------/
    int MPIUtil::mpi_size_ = 0;
    int MPIUtil::mpi_rank_ = 0;
    std::queue<std::shared_ptr<MsgPack>> MPIUtil::send_queue_;
#if defined (_MPI_VERSION_)
    char MPIUtil::recv_buffer_[kMPIBufferSize];
    MPI_Request MPIUtil::recv_request_ = MPI_REQUEST_NULL;

    char MPIUtil::send_buffer_[kMPIBufferSize];
    MPI_Request MPIUtil::send_request_ = MPI_REQUEST_NULL;
#endif
    //-- end of static member definition -------------------------------------/

#if defined (_MPI_VERSION_)
    // Initializes MPI environment
    void MPIUtil::Init(int *argc, char **argv[])
    {
        int flag = 0;
        MPI_Initialized(&flag); // test if MPI has been initialized
        if (!flag) // if MPI not started, start it
        {
            MPI_Init_thread(argc, argv, MPI_THREAD_SERIALIZED, &flag);
        }
        MPI_Comm_size(MPI_COMM_WORLD, &mpi_size_);
        MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank_);
    }

    // Finalizes MPI environment
    void MPIUtil::Close()
    {
        MPI_Finalize();
    }

    std::shared_ptr<MsgPack> MPIUtil::ProbeAndRecv()
    {
        int flag;
		int count = 0;
        MPI_Status status;
        // test if there is new message comes
        MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status);
        if (flag) // MPI message arrived
        {
            MPI_Recv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
                status.MPI_TAG, MPI_COMM_WORLD, &status);
			MPI_Get_count(&status, MPI_BYTE, &count);
            std::shared_ptr<MsgPack> request(
                new MsgPack(recv_buffer_, count));
            return request;
        }
        return nullptr;
    }

    //// Try to receive messages with MPI non-blocking receiving method.
    //std::shared_ptr<MsgPack> MPIUtil::MPIProbe()
    //{
    //    try{
    //        int flag;
	//        int count = 0;
    //        MPI_Status status;
    //        // if there is message being received
    //        if (recv_request_ != MPI_REQUEST_NULL)
    //        {
    //            // test if the receiving completed
    //            MPI_Test(&recv_request_, &flag, &status);
    //            if (flag) // recv completed, deserialize the data into ZMQ messages
    //            {
    //                recv_request_ = MPI_REQUEST_NULL;
			//MPI_Get_count(&status, MPI_BYTE, &count);
    //                std::shared_ptr<MsgPack> request(
    //                    new MsgPack(recv_buffer_, count));
    //                return request;
    //            }
    //            else // recv not completed yet
    //            {
    //                return nullptr;
    //            }
    //        }

    //        // test if there is new message comes
    //        MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status);
    //        if (flag) // MPI message arrived
    //        {
    //            //MPI_Irecv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
    //            //    status.MPI_TAG, MPI_COMM_WORLD, &recv_request_);
    //            MPI_Recv(recv_buffer_, kMPIBufferSize, MPI_BYTE, status.MPI_SOURCE,
    //                status.MPI_TAG, MPI_COMM_WORLD, &status);
	//            MPI_Get_count(&status, MPI_BYTE, &count);
    //            std::shared_ptr<MsgPack> request(new MsgPack(recv_buffer_, count));
    //            return request;
    //        }
    //        return nullptr;
    //    }
    //    catch (std::exception e)
    //    {
    //        Log::Error("Rank=%d Probe\n", mpi_rank_);
    //        throw e;
    //    }
    //}

    // Send messages with MPI non-blocking sending method. Actually, it pushes
    // the message into the queue (if not null), test if last sending has
    // been completed, and send a new one in the queue if so.
    void MPIUtil::Send(std::shared_ptr<MsgPack> msg_pack)
    {
        static int tag = 0;

        // push the send message into the send queue
        if (msg_pack.get() != nullptr)
        {
            send_queue_.push(msg_pack);
        }

        // test if the last send has been completed, return immediately if not
        if (send_request_ != MPI_REQUEST_NULL)
        {
            MPI_Status status;
            int flag;
            MPI_Test(&send_request_, &flag, &status);
            if (flag) // send completed
            {
                send_request_ = MPI_REQUEST_NULL;
            }
            else
            {
                return;
            }
        }

        // if there is message in the send queue, send it
        if (!send_queue_.empty())
        {
            MsgType msg_type;
            MsgArrow msg_arrow;
            int src, dst, size;
            std::shared_ptr<MsgPack> msg_send = send_queue_.front();
            send_queue_.pop();
            msg_send->GetHeaderInfo(&msg_type, &msg_arrow, &src, &dst);
            // serialize the message into MPI send buffer
            msg_send->Serialize(send_buffer_, &size);
            MPI_Isend(send_buffer_, size, MPI_BYTE, dst, tag++, MPI_COMM_WORLD,
                &send_request_);
        }
    }
#endif
}
<|endoftext|>


<commit_before>/*
 * waterspout
 *
 *   - simd abstraction library for audio/image manipulation -
 *
 * Copyright (c) 2013 Lucio Asnaghi
 *
 *
 * The MIT License (MIT)
 *
 * 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.
 */

#include <waterspout.h>

#include <ctime>
#include <stdexcept>
#include <iostream>
#include <iomanip>

using namespace waterspout;

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

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

/**
 * The timer class to measure elapsed time and benchmarking
 */

class timer
{
public:
    timer()
    {
        restart();
    }

    virtual ~timer()
    {
    }

    void restart()
    {
        stopped_ = false;
        clock_start_ = time_now();
        cpu_start_ = clock();
    }

    virtual void stop()
    {
        stopped_ = true;
        cpu_end_ = clock();
        clock_end_ = time_now();
    }

    double cpu_elapsed()
    {
        // return elapsed CPU time in ms
        if (! stopped_)
        {
            stop();
        }

        return ((double)(cpu_end_ - cpu_start_)) / CLOCKS_PER_SEC * 1000.0;
    }

    double clock_elapsed()
    {
        // return elapsed wall clock time in ms
        if (! stopped_)
        {
            stop();
        }

        return (clock_end_ - clock_start_) * 1000.0;
    }

    forcedinline double time_now()
    {
#if defined(WATERSPOUT_COMPILER_MSVC)
        LARGE_INTEGER t, f;
        QueryPerformanceCounter(&t);
        QueryPerformanceFrequency(&f);
        return double(t.QuadPart) / double(f.QuadPart);
#else
        struct timeval t;
        struct timezone tzp;
        gettimeofday(&t, &tzp);
        return t.tv_sec + t.tv_usec * 1e-6;
#endif
    }

protected:
    double clock_start_, clock_end_;
    clock_t cpu_start_, cpu_end_;
    bool stopped_;
};

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

namespace {

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

template<typename T>
void check_buffer_is_value(T* buffer, uint32 size, T value)
{
    for (uint32 i = 0; i < size; ++i)
    {
        if (buffer[i] != value)
        {
            std::clog << "Errors at index "
                      << i << " (" << buffer[i] << "!=" << value << ")" << std::endl;

            throw std::runtime_error("Buffer is not a specific value !");
        }
    }
}

template<typename T>
void check_buffer_is_zero(T* buffer, uint32 size)
{
    check_buffer_is_value(buffer, size, static_cast<T>(0));
}

template<typename T>
void check_buffers_are_equal(T* a, T* b, uint32 size)
{
    for (uint32 i = 0; i < size; ++i)
    {
        if (a[i] != b[i])
        {
            std::clog << "Errors at index "
                      << i << " (" << a[i] << "!=" << b[i] << ")" << std::endl;

            throw std::runtime_error("Buffers are not equal !");
        }
    }
}

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

#define run_typed_test_by_flag(datatype) \
    { \
    datatype## _buffer src_buffer_a1(s); \
    datatype## _buffer src_buffer_a2(s); \
    datatype## _buffer src_buffer_b1(s); \
    datatype## _buffer src_buffer_b2(s); \
    datatype## _buffer dst_buffer_1(s); \
    datatype## _buffer dst_buffer_2(s); \
    \
    std::clog << " - clear_buffer_" << #datatype << std::endl; \
    simd->clear_buffer_ ##datatype (src_buffer_a1.data(), s); \
    fpu->clear_buffer_ ##datatype (src_buffer_a2.data(), s); \
    check_buffers_are_equal(src_buffer_a1.data(), src_buffer_a2.data(), s); \
    \
    std::clog << " - set_buffer_" << #datatype << std::endl; \
    simd->set_buffer_ ##datatype (src_buffer_a1.data(), s, (datatype)1); \
    fpu->set_buffer_ ##datatype (src_buffer_a2.data(), s, (datatype)1); \
    simd->set_buffer_ ##datatype (src_buffer_b1.data(), s, (datatype)500); \
    fpu->set_buffer_ ##datatype (src_buffer_b2.data(), s, (datatype)500); \
    check_buffers_are_equal(src_buffer_a1.data(), src_buffer_a2.data(), s); \
    check_buffers_are_equal(src_buffer_b1.data(), src_buffer_b2.data(), s); \
    \
    std::clog << " - scale_buffer_" << #datatype << std::endl; \
    simd->scale_buffer_ ##datatype (src_buffer_a1.data(), s, 2.0f); \
    fpu->scale_buffer_ ##datatype (src_buffer_a2.data(), s, 2.0f); \
    check_buffers_are_equal(src_buffer_a1.data(), src_buffer_a2.data(), s); \
    \
    std::clog << " - copy_buffer_" << #datatype << std::endl; \
    simd->copy_buffer_ ##datatype (src_buffer_a1.data(), dst_buffer_1.data(), s); \
    fpu->copy_buffer_ ##datatype (src_buffer_a2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << " - add_buffers_" << #datatype << std::endl; \
    simd->add_buffers_ ##datatype (src_buffer_a1.data(), src_buffer_b1.data(), dst_buffer_1.data(), s); \
    fpu->add_buffers_ ##datatype (src_buffer_a2.data(), src_buffer_b2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << " - subtract_buffers_" << #datatype << std::endl; \
    simd->subtract_buffers_ ##datatype (src_buffer_a1.data(), src_buffer_b1.data(), dst_buffer_1.data(), s); \
    fpu->subtract_buffers_ ##datatype (src_buffer_a2.data(), src_buffer_b2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << " - multiply_buffers_" << #datatype << std::endl; \
    simd->multiply_buffers_ ##datatype (src_buffer_a1.data(), src_buffer_b1.data(), dst_buffer_1.data(), s); \
    fpu->multiply_buffers_ ##datatype (src_buffer_a2.data(), src_buffer_b2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << " - divide_buffers_" << #datatype << std::endl; \
    simd->set_buffer_ ##datatype (src_buffer_b1.data(), s, (datatype)2); \
    fpu->set_buffer_ ##datatype (src_buffer_b2.data(), s, (datatype)2); \
    simd->divide_buffers_ ##datatype (src_buffer_a1.data(), src_buffer_b1.data(), dst_buffer_1.data(), s); \
    fpu->divide_buffers_ ##datatype (src_buffer_a2.data(), src_buffer_b2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << std::endl; \
    }

#define run_all_tests_by_flag(flags) \
    { \
    const uint32 s = 8192; \
    math fpu(FORCE_FPU); \
    math simd(flags); \
    std::clog << simd.name() << ": " << std::endl; \
    run_typed_test_by_flag(int8); \
    run_typed_test_by_flag(uint8); \
    run_typed_test_by_flag(int16); \
    run_typed_test_by_flag(uint16); \
    run_typed_test_by_flag(int32); \
    run_typed_test_by_flag(uint32); \
    run_typed_test_by_flag(int64); \
    run_typed_test_by_flag(uint64); \
    run_typed_test_by_flag(float); \
    run_typed_test_by_flag(double); \
    }

#define run_all_tests \
    run_all_tests_by_flag(FORCE_MMX); \
    run_all_tests_by_flag(FORCE_SSE); \
    run_all_tests_by_flag(FORCE_SSE2); \

    //run_all_tests_by_flag(FORCE_SSE3)
    //run_all_tests_by_flag(FORCE_SSSE3)
    //run_all_tests_by_flag(FORCE_SSE41)
    //run_all_tests_by_flag(FORCE_SSE42)
    //run_all_tests_by_flag(FORCE_AVX)

} // end namespace

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

int main(int argc, char* argv[])
{
    unused(argc);
    unused(argv);

    run_all_tests

    return 0;
}
<commit_msg>- enabled all tests (even if some classes are not implemented)<commit_after>/*
 * waterspout
 *
 *   - simd abstraction library for audio/image manipulation -
 *
 * Copyright (c) 2013 Lucio Asnaghi
 *
 *
 * The MIT License (MIT)
 *
 * 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.
 */

#include <waterspout.h>

#include <ctime>
#include <stdexcept>
#include <iostream>
#include <iomanip>

using namespace waterspout;

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

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

/**
 * The timer class to measure elapsed time and benchmarking
 */

class timer
{
public:
    timer()
    {
        restart();
    }

    virtual ~timer()
    {
    }

    void restart()
    {
        stopped_ = false;
        clock_start_ = time_now();
        cpu_start_ = clock();
    }

    virtual void stop()
    {
        stopped_ = true;
        cpu_end_ = clock();
        clock_end_ = time_now();
    }

    double cpu_elapsed()
    {
        // return elapsed CPU time in ms
        if (! stopped_)
        {
            stop();
        }

        return ((double)(cpu_end_ - cpu_start_)) / CLOCKS_PER_SEC * 1000.0;
    }

    double clock_elapsed()
    {
        // return elapsed wall clock time in ms
        if (! stopped_)
        {
            stop();
        }

        return (clock_end_ - clock_start_) * 1000.0;
    }

    forcedinline double time_now()
    {
#if defined(WATERSPOUT_COMPILER_MSVC)
        LARGE_INTEGER t, f;
        QueryPerformanceCounter(&t);
        QueryPerformanceFrequency(&f);
        return double(t.QuadPart) / double(f.QuadPart);
#else
        struct timeval t;
        struct timezone tzp;
        gettimeofday(&t, &tzp);
        return t.tv_sec + t.tv_usec * 1e-6;
#endif
    }

protected:
    double clock_start_, clock_end_;
    clock_t cpu_start_, cpu_end_;
    bool stopped_;
};

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

namespace {

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

template<typename T>
void check_buffer_is_value(T* buffer, uint32 size, T value)
{
    for (uint32 i = 0; i < size; ++i)
    {
        if (buffer[i] != value)
        {
            std::clog << "Errors at index "
                      << i << " (" << buffer[i] << "!=" << value << ")" << std::endl;

            throw std::runtime_error("Buffer is not a specific value !");
        }
    }
}

template<typename T>
void check_buffer_is_zero(T* buffer, uint32 size)
{
    check_buffer_is_value(buffer, size, static_cast<T>(0));
}

template<typename T>
void check_buffers_are_equal(T* a, T* b, uint32 size)
{
    for (uint32 i = 0; i < size; ++i)
    {
        if (a[i] != b[i])
        {
            std::clog << "Errors at index "
                      << i << " (" << a[i] << "!=" << b[i] << ")" << std::endl;

            throw std::runtime_error("Buffers are not equal !");
        }
    }
}

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

#define run_typed_test_by_flag(datatype) \
    { \
    datatype## _buffer src_buffer_a1(s); \
    datatype## _buffer src_buffer_a2(s); \
    datatype## _buffer src_buffer_b1(s); \
    datatype## _buffer src_buffer_b2(s); \
    datatype## _buffer dst_buffer_1(s); \
    datatype## _buffer dst_buffer_2(s); \
    \
    std::clog << " - clear_buffer_" << #datatype << std::endl; \
    simd->clear_buffer_ ##datatype (src_buffer_a1.data(), s); \
    fpu->clear_buffer_ ##datatype (src_buffer_a2.data(), s); \
    check_buffers_are_equal(src_buffer_a1.data(), src_buffer_a2.data(), s); \
    \
    std::clog << " - set_buffer_" << #datatype << std::endl; \
    simd->set_buffer_ ##datatype (src_buffer_a1.data(), s, (datatype)1); \
    fpu->set_buffer_ ##datatype (src_buffer_a2.data(), s, (datatype)1); \
    simd->set_buffer_ ##datatype (src_buffer_b1.data(), s, (datatype)500); \
    fpu->set_buffer_ ##datatype (src_buffer_b2.data(), s, (datatype)500); \
    check_buffers_are_equal(src_buffer_a1.data(), src_buffer_a2.data(), s); \
    check_buffers_are_equal(src_buffer_b1.data(), src_buffer_b2.data(), s); \
    \
    std::clog << " - scale_buffer_" << #datatype << std::endl; \
    simd->scale_buffer_ ##datatype (src_buffer_a1.data(), s, 2.0f); \
    fpu->scale_buffer_ ##datatype (src_buffer_a2.data(), s, 2.0f); \
    check_buffers_are_equal(src_buffer_a1.data(), src_buffer_a2.data(), s); \
    \
    std::clog << " - copy_buffer_" << #datatype << std::endl; \
    simd->copy_buffer_ ##datatype (src_buffer_a1.data(), dst_buffer_1.data(), s); \
    fpu->copy_buffer_ ##datatype (src_buffer_a2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << " - add_buffers_" << #datatype << std::endl; \
    simd->add_buffers_ ##datatype (src_buffer_a1.data(), src_buffer_b1.data(), dst_buffer_1.data(), s); \
    fpu->add_buffers_ ##datatype (src_buffer_a2.data(), src_buffer_b2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << " - subtract_buffers_" << #datatype << std::endl; \
    simd->subtract_buffers_ ##datatype (src_buffer_a1.data(), src_buffer_b1.data(), dst_buffer_1.data(), s); \
    fpu->subtract_buffers_ ##datatype (src_buffer_a2.data(), src_buffer_b2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << " - multiply_buffers_" << #datatype << std::endl; \
    simd->multiply_buffers_ ##datatype (src_buffer_a1.data(), src_buffer_b1.data(), dst_buffer_1.data(), s); \
    fpu->multiply_buffers_ ##datatype (src_buffer_a2.data(), src_buffer_b2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << " - divide_buffers_" << #datatype << std::endl; \
    simd->set_buffer_ ##datatype (src_buffer_b1.data(), s, (datatype)2); \
    fpu->set_buffer_ ##datatype (src_buffer_b2.data(), s, (datatype)2); \
    simd->divide_buffers_ ##datatype (src_buffer_a1.data(), src_buffer_b1.data(), dst_buffer_1.data(), s); \
    fpu->divide_buffers_ ##datatype (src_buffer_a2.data(), src_buffer_b2.data(), dst_buffer_2.data(), s); \
    check_buffers_are_equal(dst_buffer_1.data(), dst_buffer_2.data(), s); \
    \
    std::clog << std::endl; \
    }

#define run_all_tests_by_flag(flags) \
    { \
    const uint32 s = 8192; \
    math fpu(FORCE_FPU); \
    math simd(flags); \
    std::clog << simd.name() << ": " << std::endl; \
    run_typed_test_by_flag(int8); \
    run_typed_test_by_flag(uint8); \
    run_typed_test_by_flag(int16); \
    run_typed_test_by_flag(uint16); \
    run_typed_test_by_flag(int32); \
    run_typed_test_by_flag(uint32); \
    run_typed_test_by_flag(int64); \
    run_typed_test_by_flag(uint64); \
    run_typed_test_by_flag(float); \
    run_typed_test_by_flag(double); \
    }

#define run_all_tests \
    run_all_tests_by_flag(FORCE_MMX); \
    run_all_tests_by_flag(FORCE_SSE); \
    run_all_tests_by_flag(FORCE_SSE2); \
    run_all_tests_by_flag(FORCE_SSE3); \
    run_all_tests_by_flag(FORCE_SSSE3); \
    run_all_tests_by_flag(FORCE_SSE41); \
    run_all_tests_by_flag(FORCE_SSE42); \
    run_all_tests_by_flag(FORCE_AVX);

} // end namespace

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

int main(int argc, char* argv[])
{
    unused(argc);
    unused(argv);

    run_all_tests

    return 0;
}
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file SimpleStack.cxx
 *
 * A complete OpenLCB stack for use in straightforward OpenLCB nodes.
 *
 * @author Balazs Racz
 * @date 18 Mar 2015
 */

#if defined(__linux__) || defined(__MACH__)
#include <termios.h> /* tc* functions */
#endif

#include "nmranet/SimpleStack.hxx"
#include "nmranet/SimpleNodeInfo.hxx"

namespace nmranet
{

SimpleCanStack::SimpleCanStack(const nmranet::NodeID node_id)
    : node_(&ifCan_, node_id)
{
    AddAliasAllocator(node_id, &ifCan_);
}

void SimpleCanStack::start_stack()
{
    // Opens the eeprom file and sends configuration update commands to all
    // listeners.
    configUpdateFlow_.init(CONFIG_FILENAME);

    // Bootstraps the alias allocation process.
    ifCan_.alias_allocator()->send(ifCan_.alias_allocator()->alloc());

    // Adds memory spaces.
    if (config_enable_all_memory_space() == CONSTANT_TRUE)
    {
        auto *space = new ReadOnlyMemoryBlock(nullptr, 0xFFFFFFFFUL);
        memoryConfigHandler_.registry()->insert(
            nullptr, MemoryConfigDefs::SPACE_ALL_MEMORY, space);
        additionalComponents_.emplace_back(space);
    }
    {
        auto *space = new ReadOnlyMemoryBlock(
            reinterpret_cast<const uint8_t *>(&SNIP_STATIC_DATA),
            sizeof(SNIP_STATIC_DATA));
        memoryConfigHandler_.registry()->insert(
            &node_, MemoryConfigDefs::SPACE_ACDI_SYS, space);
        additionalComponents_.emplace_back(space);
    }
    {
        auto *space = new FileMemorySpace(
            SNIP_DYNAMIC_FILENAME, sizeof(SimpleNodeDynamicValues));
        memoryConfigHandler_.registry()->insert(
            &node_, MemoryConfigDefs::SPACE_ACDI_USR, space);
        additionalComponents_.emplace_back(space);
    }
    {
        auto *space = new ReadOnlyMemoryBlock(
            reinterpret_cast<const uint8_t *>(&CDI_DATA), strlen(CDI_DATA) + 1);
        memoryConfigHandler_.registry()->insert(
            &node_, MemoryConfigDefs::SPACE_CDI, space);
        additionalComponents_.emplace_back(space);
    }
    if (CONFIG_FILENAME != nullptr)
    {
        auto *space = new FileMemorySpace(CONFIG_FILENAME, CONFIG_FILE_SIZE);
        memory_config_handler()->registry()->insert(
            &node_, nmranet::MemoryConfigDefs::SPACE_CONFIG, space);
        additionalComponents_.emplace_back(space);
    }
}

void SimpleCanStack::add_gridconnect_port(const char *path, Notifiable *on_exit)
{
    int fd = ::open(path, O_RDWR);
    HASSERT(fd >= 0);
    LOG(INFO, "Adding device %s as fd %d", path, fd);
    create_gc_port_for_can_hub(&canHub0_, fd, on_exit);
}

#if defined(__linux__) || defined(__MACH__)
void SimpleCanStack::add_gridconnect_tty(
    const char *device, Notifiable *on_exit)
{
    int fd = ::open(device, O_RDWR);
    HASSERT(fd >= 0);
    LOG(INFO, "Adding device %s as fd %d", device, fd);
    create_gc_port_for_can_hub(&canHub0_, fd, on_exit);

    HASSERT(!tcflush(fd, TCIOFLUSH));
    struct termios settings;
    HASSERT(!tcgetattr(fd, &settings));
    cfmakeraw(&settings);
    HASSERT(!tcsetattr(fd, TCSANOW, &settings));
}
#endif
extern Pool *const __attribute__((__weak__)) g_incoming_datagram_allocator =
    init_main_buffer_pool();

} // namespace nmranet
<commit_msg>Adds baud rate setting for the simplecanstack's tty device driver.<commit_after>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file SimpleStack.cxx
 *
 * A complete OpenLCB stack for use in straightforward OpenLCB nodes.
 *
 * @author Balazs Racz
 * @date 18 Mar 2015
 */

#if defined(__linux__) || defined(__MACH__)
#include <termios.h> /* tc* functions */
#endif

#include "nmranet/SimpleStack.hxx"
#include "nmranet/SimpleNodeInfo.hxx"

namespace nmranet
{

SimpleCanStack::SimpleCanStack(const nmranet::NodeID node_id)
    : node_(&ifCan_, node_id)
{
    AddAliasAllocator(node_id, &ifCan_);
}

void SimpleCanStack::start_stack()
{
    // Opens the eeprom file and sends configuration update commands to all
    // listeners.
    configUpdateFlow_.init(CONFIG_FILENAME);

    // Bootstraps the alias allocation process.
    ifCan_.alias_allocator()->send(ifCan_.alias_allocator()->alloc());

    // Adds memory spaces.
    if (config_enable_all_memory_space() == CONSTANT_TRUE)
    {
        auto *space = new ReadOnlyMemoryBlock(nullptr, 0xFFFFFFFFUL);
        memoryConfigHandler_.registry()->insert(
            nullptr, MemoryConfigDefs::SPACE_ALL_MEMORY, space);
        additionalComponents_.emplace_back(space);
    }
    {
        auto *space = new ReadOnlyMemoryBlock(
            reinterpret_cast<const uint8_t *>(&SNIP_STATIC_DATA),
            sizeof(SNIP_STATIC_DATA));
        memoryConfigHandler_.registry()->insert(
            &node_, MemoryConfigDefs::SPACE_ACDI_SYS, space);
        additionalComponents_.emplace_back(space);
    }
    {
        auto *space = new FileMemorySpace(
            SNIP_DYNAMIC_FILENAME, sizeof(SimpleNodeDynamicValues));
        memoryConfigHandler_.registry()->insert(
            &node_, MemoryConfigDefs::SPACE_ACDI_USR, space);
        additionalComponents_.emplace_back(space);
    }
    {
        auto *space = new ReadOnlyMemoryBlock(
            reinterpret_cast<const uint8_t *>(&CDI_DATA), strlen(CDI_DATA) + 1);
        memoryConfigHandler_.registry()->insert(
            &node_, MemoryConfigDefs::SPACE_CDI, space);
        additionalComponents_.emplace_back(space);
    }
    if (CONFIG_FILENAME != nullptr)
    {
        auto *space = new FileMemorySpace(CONFIG_FILENAME, CONFIG_FILE_SIZE);
        memory_config_handler()->registry()->insert(
            &node_, nmranet::MemoryConfigDefs::SPACE_CONFIG, space);
        additionalComponents_.emplace_back(space);
    }
}

void SimpleCanStack::add_gridconnect_port(const char *path, Notifiable *on_exit)
{
    int fd = ::open(path, O_RDWR);
    HASSERT(fd >= 0);
    LOG(INFO, "Adding device %s as fd %d", path, fd);
    create_gc_port_for_can_hub(&canHub0_, fd, on_exit);
}

#if defined(__linux__) || defined(__MACH__)
void SimpleCanStack::add_gridconnect_tty(
    const char *device, Notifiable *on_exit)
{
    int fd = ::open(device, O_RDWR);
    HASSERT(fd >= 0);
    LOG(INFO, "Adding device %s as fd %d", device, fd);
    create_gc_port_for_can_hub(&canHub0_, fd, on_exit);

    HASSERT(!tcflush(fd, TCIOFLUSH));
    struct termios settings;
    HASSERT(!tcgetattr(fd, &settings));
    cfmakeraw(&settings);
    cfsetspeed(&settings, B115200);
    HASSERT(!tcsetattr(fd, TCSANOW, &settings));
}
#endif
extern Pool *const __attribute__((__weak__)) g_incoming_datagram_allocator =
    init_main_buffer_pool();

} // namespace nmranet
<|endoftext|>


<commit_before>/*=============================================================================
   Copyright (c) 2016-2017 Joel de Guzman

   Distributed under the MIT License (https://opensource.org/licenses/MIT)
=============================================================================*/
#include <boost/detail/lightweight_test.hpp>
#include <photon/support/json.hpp>
#include <boost/fusion/include/equal_to.hpp>

namespace json = photon::json;
namespace x3 = boost::spirit::x3;
namespace fusion = boost::fusion;

template <typename T>
void test_parser(json::parser const& jp, char const* in, T n)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   T attr;
   bool r = x3::parse(f, l, jp, attr);
   BOOST_TEST(r);
   BOOST_TEST(attr == n);
};

void test_string1(json::parser const& jp, char const* in)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   json::string s;
   bool r = x3::parse(f, l, jp, s);
   BOOST_TEST(r);
   BOOST_TEST(s.begin() == in);
   BOOST_TEST(s.end() == l);
};

void test_string2(json::parser const& jp, char const* in, std::string s)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   std::string attr;
   bool r = x3::parse(f, l, jp, attr);
   BOOST_TEST(r);
   BOOST_TEST(attr == s);
};

template <typename C>
bool same(C const& a, C const& b)
{
   if (boost::size(a) != boost::size(b))
      return false;
   for (std::size_t i = 0; i != boost::size(a); ++i)
      if (a[i] != b[i])
         return false;
   return true;
}

template <typename Container>
void test_array(json::parser const& jp, char const* in, Container const& c)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   Container attr;
   bool r = x3::phrase_parse(f, l, jp, x3::space, attr);
   BOOST_TEST(r);
   BOOST_TEST(same(attr, c));
};

struct foo
{
   int i;
   double d;
   std::string s;
};

template <typename T>
void test_object(json::parser const& jp, char const* in, T const& obj)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   T attr;
   bool r = x3::phrase_parse(f, l, jp, x3::space, attr);
   BOOST_TEST(r);
   BOOST_TEST(attr == obj);
};

BOOST_FUSION_ADAPT_STRUCT(
   foo,
   (int, i)
   (double, d)
   (std::string, s)
)

using fusion::operator==;

void test_json()
{
   json::parser jp;

   // ints and bools
   {
      test_parser(jp, "1234", 1234);
      test_parser(jp, "1234.45", 1234.45);
      test_parser(jp, "true", true);
      test_parser(jp, "false", false);
   }

   // strings
   {
      test_string1(jp, "\"This is my string\"");
      test_string1(jp, "\"This is \\\"my\\\" string\"");

      test_string2(jp, "\"This is my string\"", "This is my string");
      test_string2(jp, "\"This is \\\"my\\\" string\"", "This is \"my\" string");
      test_string2(jp, "\"Sosa did fine.\\u263A\"", u8"Sosa did fine.\u263A");
      test_string2(jp, "\"Snowman: \\u2603\"", u8"Snowman: \u2603");
   }

   // int vector
   {
      std::vector<int> c = {1, 2, 3, 4};
      test_array(jp, "[1, 2, 3, 4]", c);

      // empty vector
      std::vector<int> c2;
      test_array(jp, "[]", c2);
   }

   // int array
   {
      std::array<int, 4> c = {{1, 2, 3, 4}};
      test_array(jp, "[1, 2, 3, 4]", c);

      int c2[4] = {1, 2, 3, 4};
      test_array(jp, "[1, 2, 3, 4]", c2);

      // empty array
      std::array<int, 0> c3;
      test_array(jp, "[]", c3);
   }

   // double vector
   {
      std::vector<double> c = {1.1, 2.2, 3.3, 4.4};
      test_array(jp, "[1.1, 2.2, 3.3, 4.4]", c);
   }

   // string vector
   {
      std::vector<std::string> c = {"a", "b", "c", "d"};
      test_array(jp, "[\"a\", \"b\", \"c\", \"d\"]", c);
   }

   // struct
   {
      foo obj = {1, 2.2, "hey!"};

      char const* in = R"(
         {
            "i" : 1,
            "d" : 2.2,
            "s" : "hey!"
         }
      )";

      test_object(jp, in, obj);
   }
}

int main(int argc, const char* argv[])
{
   test_json();
   return boost::report_errors();
}
<commit_msg>hierarchical json objects!<commit_after>/*=============================================================================
   Copyright (c) 2016-2017 Joel de Guzman

   Distributed under the MIT License (https://opensource.org/licenses/MIT)
=============================================================================*/
#include <boost/detail/lightweight_test.hpp>
#include <photon/support/json.hpp>
#include <boost/fusion/include/equal_to.hpp>

namespace json = photon::json;
namespace x3 = boost::spirit::x3;
namespace fusion = boost::fusion;

template <typename T>
void test_parser(json::parser const& jp, char const* in, T n)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   T attr;
   bool r = x3::parse(f, l, jp, attr);
   BOOST_TEST(r);
   BOOST_TEST(attr == n);
};

void test_string1(json::parser const& jp, char const* in)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   json::string s;
   bool r = x3::parse(f, l, jp, s);
   BOOST_TEST(r);
   BOOST_TEST(s.begin() == in);
   BOOST_TEST(s.end() == l);
};

void test_string2(json::parser const& jp, char const* in, std::string s)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   std::string attr;
   bool r = x3::parse(f, l, jp, attr);
   BOOST_TEST(r);
   BOOST_TEST(attr == s);
};

template <typename C>
bool same(C const& a, C const& b)
{
   if (boost::size(a) != boost::size(b))
      return false;
   for (std::size_t i = 0; i != boost::size(a); ++i)
      if (a[i] != b[i])
         return false;
   return true;
}

template <typename Container>
void test_array(json::parser const& jp, char const* in, Container const& c)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   Container attr;
   bool r = x3::phrase_parse(f, l, jp, x3::space, attr);
   BOOST_TEST(r);
   BOOST_TEST(same(attr, c));
};

struct foo
{
   int i;
   double d;
   std::string s;
};

struct bar
{
   int ii;
   double dd;
   foo ff;
};

template <typename T>
void test_object(json::parser const& jp, char const* in, T const& obj)
{
   char const* f = in;
   char const* l = f + std::strlen(f);

   T attr;
   bool r = x3::phrase_parse(f, l, jp, x3::space, attr);
   BOOST_TEST(r);
   BOOST_TEST(attr == obj);
};

BOOST_FUSION_ADAPT_STRUCT(
   foo,
   (int, i)
   (double, d)
   (std::string, s)
)

BOOST_FUSION_ADAPT_STRUCT(
   bar,
   (int, ii)
   (double, dd)
   (foo, ff)
)

using fusion::operator==;

void test_json()
{
   json::parser jp;

   // ints and bools
   {
      test_parser(jp, "1234", 1234);
      test_parser(jp, "1234.45", 1234.45);
      test_parser(jp, "true", true);
      test_parser(jp, "false", false);
   }

   // strings
   {
      test_string1(jp, "\"This is my string\"");
      test_string1(jp, "\"This is \\\"my\\\" string\"");

      test_string2(jp, "\"This is my string\"", "This is my string");
      test_string2(jp, "\"This is \\\"my\\\" string\"", "This is \"my\" string");
      test_string2(jp, "\"Sosa did fine.\\u263A\"", u8"Sosa did fine.\u263A");
      test_string2(jp, "\"Snowman: \\u2603\"", u8"Snowman: \u2603");
   }

   // int vector
   {
      std::vector<int> c = {1, 2, 3, 4};
      test_array(jp, "[1, 2, 3, 4]", c);

      // empty vector
      std::vector<int> c2;
      test_array(jp, "[]", c2);
   }

   // int array
   {
      std::array<int, 4> c = {{1, 2, 3, 4}};
      test_array(jp, "[1, 2, 3, 4]", c);

      int c2[4] = {1, 2, 3, 4};
      test_array(jp, "[1, 2, 3, 4]", c2);

      // empty array
      std::array<int, 0> c3;
      test_array(jp, "[]", c3);
   }

   // double vector
   {
      std::vector<double> c = {1.1, 2.2, 3.3, 4.4};
      test_array(jp, "[1.1, 2.2, 3.3, 4.4]", c);
   }

   // string vector
   {
      std::vector<std::string> c = {"a", "b", "c", "d"};
      test_array(jp, "[\"a\", \"b\", \"c\", \"d\"]", c);
   }

   // struct
   {
      foo obj = {1, 2.2, "hey!"};
      bar obj2 = {8, 9.9, obj};

      {
         char const* in = R"(
            {
               "i" : 1,
               "d" : 2.2,
               "s" : "hey!"
            }
         )";

         test_object(jp, in, obj);
      }

      {
         char const* in = R"(
            {
               "ii" : 8,
               "dd" : 9.9,
               "ff" :
               {
                  "i" : 1,
                  "d" : 2.2,
                  "s" : "hey!"
               }
            }
         )";

         test_object(jp, in, obj2);
      }
   }
}

int main(int argc, const char* argv[])
{
   test_json();
   return boost::report_errors();
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <string.h>

#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/byte_buffer_reader.h"
#include "grpc/support/slice.h"

#include "byte_buffer.h"

namespace grpc {
namespace node {

using v8::Context;
using v8::Function;
using v8::Local;
using v8::Object;
using v8::Number;
using v8::Value;

grpc_byte_buffer *BufferToByteBuffer(Local<Value> buffer) {
  Nan::HandleScope scope;
  int length = ::node::Buffer::Length(buffer);
  char *data = ::node::Buffer::Data(buffer);
  gpr_slice slice = gpr_slice_malloc(length);
  memcpy(GPR_SLICE_START_PTR(slice), data, length);
  grpc_byte_buffer *byte_buffer(grpc_raw_byte_buffer_create(&slice, 1));
  gpr_slice_unref(slice);
  return byte_buffer;
}

Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
  Nan::EscapableHandleScope scope;
  if (buffer == NULL) {
    return scope.Escape(Nan::Null());
  }
  size_t length = grpc_byte_buffer_length(buffer);
  char *result = reinterpret_cast<char *>(calloc(length, sizeof(char)));
  size_t offset = 0;
  grpc_byte_buffer_reader reader;
  grpc_byte_buffer_reader_init(&reader, buffer);
  gpr_slice next;
  while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
    memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
    offset += GPR_SLICE_LENGTH(next);
  }
  return scope.Escape(MakeFastBuffer(
      Nan::NewBuffer(result, length).ToLocalChecked()));
}

Local<Value> MakeFastBuffer(Local<Value> slowBuffer) {
  Nan::EscapableHandleScope scope;
  Local<Object> globalObj = Nan::GetCurrentContext()->Global();
  Local<Function> bufferConstructor = Local<Function>::Cast(
      globalObj->Get(Nan::New("Buffer").ToLocalChecked()));
  Local<Value> consArgs[3] = {
    slowBuffer,
    Nan::New<Number>(::node::Buffer::Length(slowBuffer)),
    Nan::New<Number>(0)
  };
  Local<Object> fastBuffer = bufferConstructor->NewInstance(3, consArgs);
  return scope.Escape(fastBuffer);
}
}  // namespace node
}  // namespace grpc
<commit_msg>Fixes memory leak when receiving data<commit_after>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <string.h>

#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/byte_buffer_reader.h"
#include "grpc/support/slice.h"

#include "byte_buffer.h"

namespace grpc {
namespace node {

using v8::Context;
using v8::Function;
using v8::Local;
using v8::Object;
using v8::Number;
using v8::Value;

grpc_byte_buffer *BufferToByteBuffer(Local<Value> buffer) {
  Nan::HandleScope scope;
  int length = ::node::Buffer::Length(buffer);
  char *data = ::node::Buffer::Data(buffer);
  gpr_slice slice = gpr_slice_malloc(length);
  memcpy(GPR_SLICE_START_PTR(slice), data, length);
  grpc_byte_buffer *byte_buffer(grpc_raw_byte_buffer_create(&slice, 1));
  gpr_slice_unref(slice);
  return byte_buffer;
}

Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
  Nan::EscapableHandleScope scope;
  if (buffer == NULL) {
    return scope.Escape(Nan::Null());
  }
  size_t length = grpc_byte_buffer_length(buffer);
  char *result = reinterpret_cast<char *>(calloc(length, sizeof(char)));
  size_t offset = 0;
  grpc_byte_buffer_reader reader;
  grpc_byte_buffer_reader_init(&reader, buffer);
  gpr_slice next;
  while (grpc_byte_buffer_reader_next(&reader, &next) != 0) {
    memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
    offset += GPR_SLICE_LENGTH(next);
    gpr_slice_unref(next);
  }
  return scope.Escape(MakeFastBuffer(
      Nan::NewBuffer(result, length).ToLocalChecked()));
}

Local<Value> MakeFastBuffer(Local<Value> slowBuffer) {
  Nan::EscapableHandleScope scope;
  Local<Object> globalObj = Nan::GetCurrentContext()->Global();
  Local<Function> bufferConstructor = Local<Function>::Cast(
      globalObj->Get(Nan::New("Buffer").ToLocalChecked()));
  Local<Value> consArgs[3] = {
    slowBuffer,
    Nan::New<Number>(::node::Buffer::Length(slowBuffer)),
    Nan::New<Number>(0)
  };
  Local<Object> fastBuffer = bufferConstructor->NewInstance(3, consArgs);
  return scope.Escape(fastBuffer);
}
}  // namespace node
}  // namespace grpc
<|endoftext|>


<commit_before>#include <miopen.h>
#include "test.hpp"
#include <vector>
#include <array>
#include <iterator>
#include <memory>
#include <miopen/tensor_extra.hpp>

struct handle_fixture
{
    miopenHandle_t handle;
#if MIOPEN_BACKEND_OPENCL
    cl_command_queue q;
#endif

    handle_fixture()
    {
        miopenCreate(&handle);
#if MIOPEN_BACKEND_OPENCL
        miopenGetStream(handle, &q);
#endif
    }

    ~handle_fixture()
    {
        miopenDestroy(handle);
    }
};

struct input_tensor_fixture
{
    miopenTensorDescriptor_t inputTensor;

    input_tensor_fixture()
    {
        STATUS(miopenCreateTensorDescriptor(&inputTensor));
        STATUS(miopenSet4dTensorDescriptor(
                inputTensor,
                miopenFloat,
                100,
                32,
                8,
                8));

    }

    ~input_tensor_fixture()
    {
        miopenDestroyTensorDescriptor(inputTensor);
    }

    void run()
    {
        int n, c, h, w;
        int nStride, cStride, hStride, wStride;
        miopenDataType_t dt;

        STATUS(miopenGet4dTensorDescriptor(
                inputTensor,
                &dt,
                &n,
                &c,
                &h,
                &w,
                &nStride,
                &cStride,
                &hStride,
                &wStride));

        EXPECT(dt == 1);
        EXPECT(n == 100);
        EXPECT(c == 32);
        EXPECT(h == 8);
        EXPECT(w == 8);
        EXPECT(nStride == c * cStride);
        EXPECT(cStride == h * hStride);
        EXPECT(hStride == w * wStride);
        EXPECT(wStride == 1);
    }
};

struct conv_filter_fixture : virtual handle_fixture
{
    miopenTensorDescriptor_t convFilter;
    miopenConvolutionDescriptor_t convDesc;

    static const miopenConvolutionMode_t mode = miopenConvolution;

    conv_filter_fixture()
    {
        STATUS(miopenCreateTensorDescriptor(&convFilter));
        // weights
        STATUS(miopenSet4dTensorDescriptor(
            convFilter,
            miopenFloat,
            64,  // outputs
            32,   // inputs
            5,   // kernel size
            5));

        STATUS(miopenCreateConvolutionDescriptor(&convDesc));
        // convolution with padding 2
        STATUS(miopenInitConvolutionDescriptor(convDesc,
                mode,
                0,
                0,
                1,
                1,
                1,
                1));

    }
    ~conv_filter_fixture()
    {
        miopenDestroyTensorDescriptor(convFilter);
        miopenDestroyConvolutionDescriptor(convDesc);
    }

    void run()
    {
        // TODO: Update API to not require mode by pointer
        miopenConvolutionMode_t lmode = mode;
        int pad_w, pad_h, u, v, upx, upy;
        STATUS(miopenGetConvolutionDescriptor(convDesc,
                &lmode,
                &pad_h, &pad_w, &u, &v,
                &upx, &upy));

        EXPECT(mode == 0);
        EXPECT(pad_h == 0);
        EXPECT(pad_w == 0);
        EXPECT(u == 1);
        EXPECT(v == 1);
        EXPECT(upx == 1);
        EXPECT(upy == 1);
    }
};

struct output_tensor_fixture : conv_filter_fixture, input_tensor_fixture
{
    miopenTensorDescriptor_t outputTensor;
    output_tensor_fixture()
    {
        int x, y, z, a;
        STATUS(miopenGetConvolutionForwardOutputDim(convDesc, inputTensor, convFilter, &x, &y, &z, &a));

        STATUS(miopenCreateTensorDescriptor(&outputTensor));

        STATUS(miopenSet4dTensorDescriptor(
            outputTensor,
            miopenFloat,
            x,
            y,
            z,
            a));
    }
    ~output_tensor_fixture()
    {
        miopenDestroyTensorDescriptor(outputTensor);
    }

    void run()
    {
        int x, y, z, a;
        STATUS(miopenGetConvolutionForwardOutputDim(convDesc, inputTensor, convFilter, &x, &y, &z, &a));

        EXPECT(x == 100);
        EXPECT(y == 64);
        EXPECT(z == 4);
        EXPECT(a == 4);
    }
};

template<bool Profile>
struct conv_forward : output_tensor_fixture
{
    void run()
    {
        STATUS(miopenEnableProfiling(handle, Profile));
        int alpha = 1, beta = 1;
        STATUS(miopenTransformTensor(handle,
                &alpha,
                inputTensor,
                NULL,
                &beta,
                convFilter,
                NULL));

        // int value = 10;
        // STATUS(miopenSetTensor(handle, inputTensor, NULL, &value));

        // STATUS(miopenScaleTensor(handle, inputTensor, NULL, &alpha));

        // Setup OpenCL buffers

		int n, h, c, w;
		STATUS(miopenGet4dTensorDescriptorLengths(inputTensor, &n, &c, &h, &w));
		size_t sz_in = n*c*h*w;

		STATUS(miopenGet4dTensorDescriptorLengths(convFilter, &n, &c, &h, &w));
		size_t sz_wei = n*c*h*w;

		STATUS(miopenGet4dTensorDescriptorLengths(outputTensor, &n, &c, &h, &w));
		size_t sz_out = n*c*h*w;

		size_t sz_fwd_workspace;
		STATUS(miopenConvolutionForwardGetWorkSpaceSize(handle, convFilter, inputTensor, outputTensor, convDesc, &sz_fwd_workspace));

        std::vector<float> in(sz_in);
        std::vector<float> wei(sz_wei);
        std::vector<float> out(sz_out);
        std::vector<float> fwd_workspace(sz_fwd_workspace/4);

        for(int i = 0; i < sz_in; i++) {
            in[i] = rand() * (1.0 / RAND_MAX);
        }
        for (int i = 0; i < sz_wei; i++) {
            wei[i] = static_cast<double>(rand() * (1.0 / RAND_MAX) - 0.5) * 0.001;
        }

#if MIOPEN_BACKEND_OPENCL

        cl_context ctx;
        clGetCommandQueueInfo(q, CL_QUEUE_CONTEXT, sizeof(cl_context), &ctx, NULL);

        cl_int status = CL_SUCCESS;
		cl_mem in_dev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz_in,NULL, &status);
		cl_mem wei_dev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz_wei,NULL, NULL);
		cl_mem out_dev = clCreateBuffer(ctx, CL_MEM_READ_WRITE, 4*sz_out,NULL, NULL);
		cl_mem fwd_workspace_dev = clCreateBuffer(ctx, CL_MEM_READ_WRITE, sz_fwd_workspace, NULL, NULL);

		status = clEnqueueWriteBuffer(q, in_dev, CL_TRUE, 0, 4*sz_in, in.data(), 0, NULL, NULL);
		status |= clEnqueueWriteBuffer(q, wei_dev, CL_TRUE, 0, 4*sz_wei, wei.data(), 0, NULL, NULL);
		status |= clEnqueueWriteBuffer(q, out_dev, CL_TRUE, 0, 4*sz_out, out.data(), 0, NULL, NULL);
		status |= clEnqueueWriteBuffer(q, fwd_workspace_dev, CL_TRUE, 0, sz_fwd_workspace, fwd_workspace.data(), 0, NULL, NULL);
		EXPECT(status == CL_SUCCESS);

#elif MIOPEN_BACKEND_HIP

        void * in_dev;
        void * wei_dev;
        void * out_dev;
		void * fwd_workspace_dev;

        EXPECT(hipMalloc(&in_dev, 4*sz_in) == hipSuccess);
        EXPECT(hipMalloc(&wei_dev, 4*sz_wei) == hipSuccess);
        EXPECT(hipMalloc(&out_dev, 4*sz_out) == hipSuccess);
        EXPECT(hipMalloc(&fwd_workspace_dev, sz_fwd_workspace) == hipSuccess);

        EXPECT(hipMemcpy(in_dev, in.data(), 4*sz_in, hipMemcpyHostToDevice) == hipSuccess);
        EXPECT(hipMemcpy(wei_dev, wei.data(), 4*sz_wei, hipMemcpyHostToDevice) == hipSuccess);
        EXPECT(hipMemcpy(out_dev, out.data(), 4*sz_out, hipMemcpyHostToDevice) == hipSuccess);
        EXPECT(hipMemcpy(fwd_workspace_dev, fwd_workspace.data(), sz_fwd_workspace, hipMemcpyHostToDevice) == hipSuccess);

#endif

        int ret_algo_count;
        miopenConvAlgoPerf_t perf;

        STATUS(miopenFindConvolutionForwardAlgorithm(handle,
            inputTensor,
            in_dev,
            convFilter,
            wei_dev,
            convDesc,
            outputTensor,
            out_dev,
            1,
            &ret_algo_count,
            &perf,
            fwd_workspace_dev,
            sz_fwd_workspace,
			0)); // MD: Not performing exhaustiveSearch by default for now

        STATUS(miopenConvolutionForward(handle,
            &alpha,
            inputTensor,
            in_dev,
            convFilter,
            wei_dev,
            convDesc,
            miopenConvolutionFwdAlgoDirect,
            &beta,
            outputTensor,
			out_dev,
            fwd_workspace_dev,
            sz_fwd_workspace));

        float time;
        STATUS(miopenGetKernelTime(handle, &time));
        if (Profile)
        {
            CHECK(time > 0.0);
        }
        else
        {
            CHECK(time == 0.0);
        }

        // Potential memory leak free memory at end of function
#if MIOPEN_BACKEND_OPENCL
		clReleaseMemObject(in_dev);
		clReleaseMemObject(wei_dev);
		clReleaseMemObject(out_dev);
		clReleaseMemObject(fwd_workspace_dev);

#elif MIOPEN_BACKEND_HIP
        hipFree(in_dev);
        hipFree(wei_dev);
        hipFree(out_dev);
		hipFree(fwd_workspace_dev);
#endif
    }
};

int main() {
    run_test<input_tensor_fixture>();
    run_test<conv_filter_fixture>();
    run_test<output_tensor_fixture>();
    run_test<conv_forward<true>>();
    run_test<conv_forward<false>>();
}

<commit_msg>fixed forward-workspace args<commit_after>#include <miopen.h>
#include "test.hpp"
#include <vector>
#include <array>
#include <iterator>
#include <memory>
#include <miopen/tensor_extra.hpp>

struct handle_fixture
{
    miopenHandle_t handle;
#if MIOPEN_BACKEND_OPENCL
    cl_command_queue q;
#endif

    handle_fixture()
    {
        miopenCreate(&handle);
#if MIOPEN_BACKEND_OPENCL
        miopenGetStream(handle, &q);
#endif
    }

    ~handle_fixture()
    {
        miopenDestroy(handle);
    }
};

struct input_tensor_fixture
{
    miopenTensorDescriptor_t inputTensor;

    input_tensor_fixture()
    {
        STATUS(miopenCreateTensorDescriptor(&inputTensor));
        STATUS(miopenSet4dTensorDescriptor(
                inputTensor,
                miopenFloat,
                100,
                32,
                8,
                8));

    }

    ~input_tensor_fixture()
    {
        miopenDestroyTensorDescriptor(inputTensor);
    }

    void run()
    {
        int n, c, h, w;
        int nStride, cStride, hStride, wStride;
        miopenDataType_t dt;

        STATUS(miopenGet4dTensorDescriptor(
                inputTensor,
                &dt,
                &n,
                &c,
                &h,
                &w,
                &nStride,
                &cStride,
                &hStride,
                &wStride));

        EXPECT(dt == 1);
        EXPECT(n == 100);
        EXPECT(c == 32);
        EXPECT(h == 8);
        EXPECT(w == 8);
        EXPECT(nStride == c * cStride);
        EXPECT(cStride == h * hStride);
        EXPECT(hStride == w * wStride);
        EXPECT(wStride == 1);
    }
};

struct conv_filter_fixture : virtual handle_fixture
{
    miopenTensorDescriptor_t convFilter;
    miopenConvolutionDescriptor_t convDesc;

    static const miopenConvolutionMode_t mode = miopenConvolution;

    conv_filter_fixture()
    {
        STATUS(miopenCreateTensorDescriptor(&convFilter));
        // weights
        STATUS(miopenSet4dTensorDescriptor(
            convFilter,
            miopenFloat,
            64,  // outputs
            32,   // inputs
            5,   // kernel size
            5));

        STATUS(miopenCreateConvolutionDescriptor(&convDesc));
        // convolution with padding 2
        STATUS(miopenInitConvolutionDescriptor(convDesc,
                mode,
                0,
                0,
                1,
                1,
                1,
                1));

    }
    ~conv_filter_fixture()
    {
        miopenDestroyTensorDescriptor(convFilter);
        miopenDestroyConvolutionDescriptor(convDesc);
    }

    void run()
    {
        // TODO: Update API to not require mode by pointer
        miopenConvolutionMode_t lmode = mode;
        int pad_w, pad_h, u, v, upx, upy;
        STATUS(miopenGetConvolutionDescriptor(convDesc,
                &lmode,
                &pad_h, &pad_w, &u, &v,
                &upx, &upy));

        EXPECT(mode == 0);
        EXPECT(pad_h == 0);
        EXPECT(pad_w == 0);
        EXPECT(u == 1);
        EXPECT(v == 1);
        EXPECT(upx == 1);
        EXPECT(upy == 1);
    }
};

struct output_tensor_fixture : conv_filter_fixture, input_tensor_fixture
{
    miopenTensorDescriptor_t outputTensor;
    output_tensor_fixture()
    {
        int x, y, z, a;
        STATUS(miopenGetConvolutionForwardOutputDim(convDesc, inputTensor, convFilter, &x, &y, &z, &a));

        STATUS(miopenCreateTensorDescriptor(&outputTensor));

        STATUS(miopenSet4dTensorDescriptor(
            outputTensor,
            miopenFloat,
            x,
            y,
            z,
            a));
    }
    ~output_tensor_fixture()
    {
        miopenDestroyTensorDescriptor(outputTensor);
    }

    void run()
    {
        int x, y, z, a;
        STATUS(miopenGetConvolutionForwardOutputDim(convDesc, inputTensor, convFilter, &x, &y, &z, &a));

        EXPECT(x == 100);
        EXPECT(y == 64);
        EXPECT(z == 4);
        EXPECT(a == 4);
    }
};

template<bool Profile>
struct conv_forward : output_tensor_fixture
{
    void run()
    {
        STATUS(miopenEnableProfiling(handle, Profile));
        int alpha = 1, beta = 1;
        STATUS(miopenTransformTensor(handle,
                &alpha,
                inputTensor,
                NULL,
                &beta,
                convFilter,
                NULL));

        // int value = 10;
        // STATUS(miopenSetTensor(handle, inputTensor, NULL, &value));

        // STATUS(miopenScaleTensor(handle, inputTensor, NULL, &alpha));

        // Setup OpenCL buffers

		int n, h, c, w;
		STATUS(miopenGet4dTensorDescriptorLengths(inputTensor, &n, &c, &h, &w));
		size_t sz_in = n*c*h*w;

		STATUS(miopenGet4dTensorDescriptorLengths(convFilter, &n, &c, &h, &w));
		size_t sz_wei = n*c*h*w;

		STATUS(miopenGet4dTensorDescriptorLengths(outputTensor, &n, &c, &h, &w));
		size_t sz_out = n*c*h*w;

		size_t sz_fwd_workspace;
		STATUS(miopenConvolutionForwardGetWorkSpaceSize(handle, convFilter, inputTensor, convDesc, outputTensor, &sz_fwd_workspace));

        std::vector<float> in(sz_in);
        std::vector<float> wei(sz_wei);
        std::vector<float> out(sz_out);
        std::vector<float> fwd_workspace(sz_fwd_workspace/4);

        for(int i = 0; i < sz_in; i++) {
            in[i] = rand() * (1.0 / RAND_MAX);
        }
        for (int i = 0; i < sz_wei; i++) {
            wei[i] = static_cast<double>(rand() * (1.0 / RAND_MAX) - 0.5) * 0.001;
        }

#if MIOPEN_BACKEND_OPENCL

        cl_context ctx;
        clGetCommandQueueInfo(q, CL_QUEUE_CONTEXT, sizeof(cl_context), &ctx, NULL);

        cl_int status = CL_SUCCESS;
		cl_mem in_dev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz_in,NULL, &status);
		cl_mem wei_dev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz_wei,NULL, NULL);
		cl_mem out_dev = clCreateBuffer(ctx, CL_MEM_READ_WRITE, 4*sz_out,NULL, NULL);
		cl_mem fwd_workspace_dev = clCreateBuffer(ctx, CL_MEM_READ_WRITE, sz_fwd_workspace, NULL, NULL);

		status = clEnqueueWriteBuffer(q, in_dev, CL_TRUE, 0, 4*sz_in, in.data(), 0, NULL, NULL);
		status |= clEnqueueWriteBuffer(q, wei_dev, CL_TRUE, 0, 4*sz_wei, wei.data(), 0, NULL, NULL);
		status |= clEnqueueWriteBuffer(q, out_dev, CL_TRUE, 0, 4*sz_out, out.data(), 0, NULL, NULL);
		status |= clEnqueueWriteBuffer(q, fwd_workspace_dev, CL_TRUE, 0, sz_fwd_workspace, fwd_workspace.data(), 0, NULL, NULL);
		EXPECT(status == CL_SUCCESS);

#elif MIOPEN_BACKEND_HIP

        void * in_dev;
        void * wei_dev;
        void * out_dev;
		void * fwd_workspace_dev;

        EXPECT(hipMalloc(&in_dev, 4*sz_in) == hipSuccess);
        EXPECT(hipMalloc(&wei_dev, 4*sz_wei) == hipSuccess);
        EXPECT(hipMalloc(&out_dev, 4*sz_out) == hipSuccess);
        EXPECT(hipMalloc(&fwd_workspace_dev, sz_fwd_workspace) == hipSuccess);

        EXPECT(hipMemcpy(in_dev, in.data(), 4*sz_in, hipMemcpyHostToDevice) == hipSuccess);
        EXPECT(hipMemcpy(wei_dev, wei.data(), 4*sz_wei, hipMemcpyHostToDevice) == hipSuccess);
        EXPECT(hipMemcpy(out_dev, out.data(), 4*sz_out, hipMemcpyHostToDevice) == hipSuccess);
        EXPECT(hipMemcpy(fwd_workspace_dev, fwd_workspace.data(), sz_fwd_workspace, hipMemcpyHostToDevice) == hipSuccess);

#endif

        int ret_algo_count;
        miopenConvAlgoPerf_t perf;

        STATUS(miopenFindConvolutionForwardAlgorithm(handle,
            inputTensor,
            in_dev,
            convFilter,
            wei_dev,
            convDesc,
            outputTensor,
            out_dev,
            1,
            &ret_algo_count,
            &perf,
            fwd_workspace_dev,
            sz_fwd_workspace,
			0)); // MD: Not performing exhaustiveSearch by default for now

        STATUS(miopenConvolutionForward(handle,
            &alpha,
            inputTensor,
            in_dev,
            convFilter,
            wei_dev,
            convDesc,
            miopenConvolutionFwdAlgoDirect,
            &beta,
            outputTensor,
			out_dev,
            fwd_workspace_dev,
            sz_fwd_workspace));

        float time;
        STATUS(miopenGetKernelTime(handle, &time));
        if (Profile)
        {
            CHECK(time > 0.0);
        }
        else
        {
            CHECK(time == 0.0);
        }

        // Potential memory leak free memory at end of function
#if MIOPEN_BACKEND_OPENCL
		clReleaseMemObject(in_dev);
		clReleaseMemObject(wei_dev);
		clReleaseMemObject(out_dev);
		clReleaseMemObject(fwd_workspace_dev);

#elif MIOPEN_BACKEND_HIP
        hipFree(in_dev);
        hipFree(wei_dev);
        hipFree(out_dev);
		hipFree(fwd_workspace_dev);
#endif
    }
};

int main() {
    run_test<input_tensor_fixture>();
    run_test<conv_filter_fixture>();
    run_test<output_tensor_fixture>();
    run_test<conv_forward<true>>();
    run_test<conv_forward<false>>();
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 * Copyright 2016 Realm Inc.
 *
 * 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
 *
 * 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.
 *
 **************************************************************************/

#ifndef REALM_UTIL_BIND_PTR_HPP
#define REALM_UTIL_BIND_PTR_HPP

#include <algorithm>
#include <atomic>
#include <ostream>
#include <utility>

#include <realm/util/features.h>
#include <realm/util/assert.hpp>

namespace realm {
namespace util {

class bind_ptr_base {
public:
    struct adopt_tag {
    };
};

/// A generic intrusive smart pointer that binds itself explicitely to
/// the target object.
///
/// This class is agnostic towards what 'binding' means for the target
/// object, but a common use is 'reference counting'. See RefCountBase
/// for an example of that.
///
/// This smart pointer implementation assumes that the target object
/// destructor never throws.
template <class T>
class bind_ptr : public bind_ptr_base {
public:
    constexpr bind_ptr() noexcept
        : m_ptr(nullptr)
    {
    }
    ~bind_ptr() noexcept
    {
        unbind();
    }

    explicit bind_ptr(T* p) noexcept
    {
        bind(p);
    }
    template <class U>
    explicit bind_ptr(U* p) noexcept
    {
        bind(p);
    }

    bind_ptr(T* p, adopt_tag) noexcept
    {
        m_ptr = p;
    }
    template <class U>
    bind_ptr(U* p, adopt_tag) noexcept
    {
        m_ptr = p;
    }

    // Copy construct
    bind_ptr(const bind_ptr& p) noexcept
    {
        bind(p.m_ptr);
    }
    template <class U>
    bind_ptr(const bind_ptr<U>& p) noexcept
    {
        bind(p.m_ptr);
    }

    // Copy assign
    bind_ptr& operator=(const bind_ptr& p) noexcept
    {
        bind_ptr(p).swap(*this);
        return *this;
    }
    template <class U>
    bind_ptr& operator=(const bind_ptr<U>& p) noexcept
    {
        bind_ptr(p).swap(*this);
        return *this;
    }

    // Move construct
    bind_ptr(bind_ptr&& p) noexcept
        : m_ptr(p.release())
    {
    }
    template <class U>
    bind_ptr(bind_ptr<U>&& p) noexcept
        : m_ptr(p.release())
    {
    }

    // Move from std::unique_ptr
    bind_ptr(std::unique_ptr<T>&& p) noexcept
    {
        bind(p.release());
    }

    // Move assign
    bind_ptr& operator=(bind_ptr&& p) noexcept
    {
        bind_ptr(std::move(p)).swap(*this);
        return *this;
    }
    template <class U>
    bind_ptr& operator=(bind_ptr<U>&& p) noexcept
    {
        bind_ptr(std::move(p)).swap(*this);
        return *this;
    }

    //@{
    // Comparison
    template <class U>
    bool operator==(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator==(U*) const noexcept;

    template <class U>
    bool operator!=(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator!=(U*) const noexcept;

    template <class U>
    bool operator<(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator<(U*) const noexcept;

    template <class U>
    bool operator>(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator>(U*) const noexcept;

    template <class U>
    bool operator<=(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator<=(U*) const noexcept;

    template <class U>
    bool operator>=(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator>=(U*) const noexcept;
    //@}

    // Dereference
    T& operator*() const noexcept
    {
        return *m_ptr;
    }
    T* operator->() const noexcept
    {
        return m_ptr;
    }

    explicit operator bool() const noexcept
    {
        return m_ptr != 0;
    }

    T* get() const noexcept
    {
        return m_ptr;
    }
    void reset() noexcept
    {
        bind_ptr().swap(*this);
    }
    void reset(T* p) noexcept
    {
        bind_ptr(p).swap(*this);
    }
    template <class U>
    void reset(U* p) noexcept
    {
        bind_ptr(p).swap(*this);
    }

    void reset(T* p, adopt_tag) noexcept
    {
        bind_ptr(p, adopt_tag{}).swap(*this);
    }

    template <class U>
    void reset(U* p, adopt_tag) noexcept
    {
        bind_ptr(p, adopt_tag{}).swap(*this);
    }

    T* release() noexcept
    {
        T* const p = m_ptr;
        m_ptr = nullptr;
        return p;
    }

    void swap(bind_ptr& p) noexcept
    {
        std::swap(m_ptr, p.m_ptr);
    }
    friend void swap(bind_ptr& a, bind_ptr& b) noexcept
    {
        a.swap(b);
    }

protected:
    struct casting_move_tag {
    };
    template <class U>
    bind_ptr(bind_ptr<U>* p, casting_move_tag) noexcept
        : m_ptr(static_cast<T*>(p->release()))
    {
    }

private:
    T* m_ptr;

    void bind(T* p) noexcept
    {
        if (p)
            p->bind_ptr();
        m_ptr = p;
    }
    void unbind() noexcept
    {
        if (m_ptr)
            m_ptr->unbind_ptr();
    }

    template <class>
    friend class bind_ptr;
};

template <class T, typename... Args>
bind_ptr<T> make_bind(Args&&... __args)
{
    return bind_ptr<T>(new T(std::forward<Args>(__args)...));
}

template <class C, class T, class U>
inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const bind_ptr<U>& p)
{
    out << static_cast<const void*>(p.get());
    return out;
}

//@{
// Comparison
template <class T, class U>
bool operator==(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator!=(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator<(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator>(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator<=(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator>=(T*, const bind_ptr<U>&) noexcept;
//@}

/// Polymorphic convenience base class for reference counting objects.
///
/// Together with bind_ptr, this class delivers simple instrusive
/// reference counting.
///
/// \sa bind_ptr
class RefCountBase {
public:
    RefCountBase() noexcept
        : m_ref_count(0)
    {
    }
    virtual ~RefCountBase() noexcept
    {
        REALM_ASSERT(m_ref_count == 0);
    }

    RefCountBase(const RefCountBase&)
        : m_ref_count(0)
    {
    }
    void operator=(const RefCountBase&) {}

protected:
    void bind_ptr() const noexcept
    {
        ++m_ref_count;
    }
    void unbind_ptr() const noexcept
    {
        if (--m_ref_count == 0)
            delete this;
    }

private:
    mutable unsigned long m_ref_count;

    template <class>
    friend class bind_ptr;
};

/// Same as RefCountBase, but this one makes the copying of, and the
/// destruction of counted references thread-safe.
///
/// \sa RefCountBase
/// \sa bind_ptr
class AtomicRefCountBase {
public:
    AtomicRefCountBase() noexcept
        : m_ref_count(0)
    {
    }
    virtual ~AtomicRefCountBase() noexcept
    {
        REALM_ASSERT(m_ref_count == 0);
    }

    AtomicRefCountBase(const AtomicRefCountBase&)
        : m_ref_count(0)
    {
    }
    void operator=(const AtomicRefCountBase&) {}

protected:
    // FIXME: Operators ++ and -- as used below use
    // std::memory_order_seq_cst. This can be optimized.
    void bind_ptr() const noexcept
    {
        ++m_ref_count;
    }
    void unbind_ptr() const noexcept
    {
        if (--m_ref_count == 0) {
            delete this;
        }
    }

private:
    mutable std::atomic<unsigned long> m_ref_count;

    template <class>
    friend class bind_ptr;
};

// Implementation:

template <class T>
template <class U>
bool bind_ptr<T>::operator==(const bind_ptr<U>& p) const noexcept
{
    return m_ptr == p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator==(U* p) const noexcept
{
    return m_ptr == p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator!=(const bind_ptr<U>& p) const noexcept
{
    return m_ptr != p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator!=(U* p) const noexcept
{
    return m_ptr != p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator<(const bind_ptr<U>& p) const noexcept
{
    return m_ptr < p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator<(U* p) const noexcept
{
    return m_ptr < p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator>(const bind_ptr<U>& p) const noexcept
{
    return m_ptr > p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator>(U* p) const noexcept
{
    return m_ptr > p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator<=(const bind_ptr<U>& p) const noexcept
{
    return m_ptr <= p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator<=(U* p) const noexcept
{
    return m_ptr <= p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator>=(const bind_ptr<U>& p) const noexcept
{
    return m_ptr >= p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator>=(U* p) const noexcept
{
    return m_ptr >= p;
}

template <class T, class U>
bool operator==(T* a, const bind_ptr<U>& b) noexcept
{
    return b == a;
}

template <class T, class U>
bool operator!=(T* a, const bind_ptr<U>& b) noexcept
{
    return b != a;
}

template <class T, class U>
bool operator<(T* a, const bind_ptr<U>& b) noexcept
{
    return b > a;
}

template <class T, class U>
bool operator>(T* a, const bind_ptr<U>& b) noexcept
{
    return b < a;
}

template <class T, class U>
bool operator<=(T* a, const bind_ptr<U>& b) noexcept
{
    return b >= a;
}

template <class T, class U>
bool operator>=(T* a, const bind_ptr<U>& b) noexcept
{
    return b <= a;
}

} // namespace util
} // namespace realm

#endif // REALM_UTIL_BIND_PTR_HPP
<commit_msg>Add an explicit deduction guide for bind_ptr<commit_after>/*************************************************************************
 *
 * Copyright 2016 Realm Inc.
 *
 * 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
 *
 * 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.
 *
 **************************************************************************/

#ifndef REALM_UTIL_BIND_PTR_HPP
#define REALM_UTIL_BIND_PTR_HPP

#include <algorithm>
#include <atomic>
#include <ostream>
#include <utility>

#include <realm/util/features.h>
#include <realm/util/assert.hpp>

namespace realm {
namespace util {

class bind_ptr_base {
public:
    struct adopt_tag {
    };
};

/// A generic intrusive smart pointer that binds itself explicitely to
/// the target object.
///
/// This class is agnostic towards what 'binding' means for the target
/// object, but a common use is 'reference counting'. See RefCountBase
/// for an example of that.
///
/// This smart pointer implementation assumes that the target object
/// destructor never throws.
template <class T>
class bind_ptr : public bind_ptr_base {
public:
    constexpr bind_ptr() noexcept
        : m_ptr(nullptr)
    {
    }
    ~bind_ptr() noexcept
    {
        unbind();
    }

    explicit bind_ptr(T* p) noexcept
    {
        bind(p);
    }
    template <class U>
    explicit bind_ptr(U* p) noexcept
    {
        bind(p);
    }

    bind_ptr(T* p, adopt_tag) noexcept
    {
        m_ptr = p;
    }
    template <class U>
    bind_ptr(U* p, adopt_tag) noexcept
    {
        m_ptr = p;
    }

    // Copy construct
    bind_ptr(const bind_ptr& p) noexcept
    {
        bind(p.m_ptr);
    }
    template <class U>
    bind_ptr(const bind_ptr<U>& p) noexcept
    {
        bind(p.m_ptr);
    }

    // Copy assign
    bind_ptr& operator=(const bind_ptr& p) noexcept
    {
        bind_ptr(p).swap(*this);
        return *this;
    }
    template <class U>
    bind_ptr& operator=(const bind_ptr<U>& p) noexcept
    {
        bind_ptr(p).swap(*this);
        return *this;
    }

    // Move construct
    bind_ptr(bind_ptr&& p) noexcept
        : m_ptr(p.release())
    {
    }
    template <class U>
    bind_ptr(bind_ptr<U>&& p) noexcept
        : m_ptr(p.release())
    {
    }

    // Move from std::unique_ptr
    bind_ptr(std::unique_ptr<T>&& p) noexcept
    {
        bind(p.release());
    }

    // Move assign
    bind_ptr& operator=(bind_ptr&& p) noexcept
    {
        bind_ptr(std::move(p)).swap(*this);
        return *this;
    }
    template <class U>
    bind_ptr& operator=(bind_ptr<U>&& p) noexcept
    {
        bind_ptr(std::move(p)).swap(*this);
        return *this;
    }

    //@{
    // Comparison
    template <class U>
    bool operator==(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator==(U*) const noexcept;

    template <class U>
    bool operator!=(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator!=(U*) const noexcept;

    template <class U>
    bool operator<(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator<(U*) const noexcept;

    template <class U>
    bool operator>(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator>(U*) const noexcept;

    template <class U>
    bool operator<=(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator<=(U*) const noexcept;

    template <class U>
    bool operator>=(const bind_ptr<U>&) const noexcept;

    template <class U>
    bool operator>=(U*) const noexcept;
    //@}

    // Dereference
    T& operator*() const noexcept
    {
        return *m_ptr;
    }
    T* operator->() const noexcept
    {
        return m_ptr;
    }

    explicit operator bool() const noexcept
    {
        return m_ptr != 0;
    }

    T* get() const noexcept
    {
        return m_ptr;
    }
    void reset() noexcept
    {
        bind_ptr().swap(*this);
    }
    void reset(T* p) noexcept
    {
        bind_ptr(p).swap(*this);
    }
    template <class U>
    void reset(U* p) noexcept
    {
        bind_ptr(p).swap(*this);
    }

    void reset(T* p, adopt_tag) noexcept
    {
        bind_ptr(p, adopt_tag{}).swap(*this);
    }

    template <class U>
    void reset(U* p, adopt_tag) noexcept
    {
        bind_ptr(p, adopt_tag{}).swap(*this);
    }

    T* release() noexcept
    {
        T* const p = m_ptr;
        m_ptr = nullptr;
        return p;
    }

    void swap(bind_ptr& p) noexcept
    {
        std::swap(m_ptr, p.m_ptr);
    }
    friend void swap(bind_ptr& a, bind_ptr& b) noexcept
    {
        a.swap(b);
    }

protected:
    struct casting_move_tag {
    };
    template <class U>
    bind_ptr(bind_ptr<U>* p, casting_move_tag) noexcept
        : m_ptr(static_cast<T*>(p->release()))
    {
    }

private:
    T* m_ptr;

    void bind(T* p) noexcept
    {
        if (p)
            p->bind_ptr();
        m_ptr = p;
    }
    void unbind() noexcept
    {
        if (m_ptr)
            m_ptr->unbind_ptr();
    }

    template <class>
    friend class bind_ptr;
};

// Deduction guides
template <class T>
bind_ptr(T*) -> bind_ptr<T>;
template <class T>
bind_ptr(T*, bind_ptr_base::adopt_tag) -> bind_ptr<T>;

template <class T, typename... Args>
bind_ptr<T> make_bind(Args&&... __args)
{
    return bind_ptr<T>(new T(std::forward<Args>(__args)...));
}

template <class C, class T, class U>
inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const bind_ptr<U>& p)
{
    out << static_cast<const void*>(p.get());
    return out;
}

//@{
// Comparison
template <class T, class U>
bool operator==(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator!=(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator<(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator>(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator<=(T*, const bind_ptr<U>&) noexcept;
template <class T, class U>
bool operator>=(T*, const bind_ptr<U>&) noexcept;
//@}

/// Polymorphic convenience base class for reference counting objects.
///
/// Together with bind_ptr, this class delivers simple instrusive
/// reference counting.
///
/// \sa bind_ptr
class RefCountBase {
public:
    RefCountBase() noexcept
        : m_ref_count(0)
    {
    }
    virtual ~RefCountBase() noexcept
    {
        REALM_ASSERT(m_ref_count == 0);
    }

    RefCountBase(const RefCountBase&)
        : m_ref_count(0)
    {
    }
    void operator=(const RefCountBase&) {}

protected:
    void bind_ptr() const noexcept
    {
        ++m_ref_count;
    }
    void unbind_ptr() const noexcept
    {
        if (--m_ref_count == 0)
            delete this;
    }

private:
    mutable unsigned long m_ref_count;

    template <class>
    friend class bind_ptr;
};

/// Same as RefCountBase, but this one makes the copying of, and the
/// destruction of counted references thread-safe.
///
/// \sa RefCountBase
/// \sa bind_ptr
class AtomicRefCountBase {
public:
    AtomicRefCountBase() noexcept
        : m_ref_count(0)
    {
    }
    virtual ~AtomicRefCountBase() noexcept
    {
        REALM_ASSERT(m_ref_count == 0);
    }

    AtomicRefCountBase(const AtomicRefCountBase&)
        : m_ref_count(0)
    {
    }
    void operator=(const AtomicRefCountBase&) {}

protected:
    // FIXME: Operators ++ and -- as used below use
    // std::memory_order_seq_cst. This can be optimized.
    void bind_ptr() const noexcept
    {
        ++m_ref_count;
    }
    void unbind_ptr() const noexcept
    {
        if (--m_ref_count == 0) {
            delete this;
        }
    }

private:
    mutable std::atomic<unsigned long> m_ref_count;

    template <class>
    friend class bind_ptr;
};

// Implementation:

template <class T>
template <class U>
bool bind_ptr<T>::operator==(const bind_ptr<U>& p) const noexcept
{
    return m_ptr == p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator==(U* p) const noexcept
{
    return m_ptr == p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator!=(const bind_ptr<U>& p) const noexcept
{
    return m_ptr != p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator!=(U* p) const noexcept
{
    return m_ptr != p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator<(const bind_ptr<U>& p) const noexcept
{
    return m_ptr < p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator<(U* p) const noexcept
{
    return m_ptr < p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator>(const bind_ptr<U>& p) const noexcept
{
    return m_ptr > p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator>(U* p) const noexcept
{
    return m_ptr > p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator<=(const bind_ptr<U>& p) const noexcept
{
    return m_ptr <= p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator<=(U* p) const noexcept
{
    return m_ptr <= p;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator>=(const bind_ptr<U>& p) const noexcept
{
    return m_ptr >= p.m_ptr;
}

template <class T>
template <class U>
bool bind_ptr<T>::operator>=(U* p) const noexcept
{
    return m_ptr >= p;
}

template <class T, class U>
bool operator==(T* a, const bind_ptr<U>& b) noexcept
{
    return b == a;
}

template <class T, class U>
bool operator!=(T* a, const bind_ptr<U>& b) noexcept
{
    return b != a;
}

template <class T, class U>
bool operator<(T* a, const bind_ptr<U>& b) noexcept
{
    return b > a;
}

template <class T, class U>
bool operator>(T* a, const bind_ptr<U>& b) noexcept
{
    return b < a;
}

template <class T, class U>
bool operator<=(T* a, const bind_ptr<U>& b) noexcept
{
    return b >= a;
}

template <class T, class U>
bool operator>=(T* a, const bind_ptr<U>& b) noexcept
{
    return b <= a;
}

} // namespace util
} // namespace realm

#endif // REALM_UTIL_BIND_PTR_HPP
<|endoftext|>