<commit_before>#pragma once

/*
MIT License

Copyright (c) 2017 ZetaChain_Native

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 "platform.hpp" // Platform Specific Stuff NOTE: Must Always be the first include in a file
#include <iostream> // std::cout
#include <string> // std::string
#include <algorithm> // std::find_if
#include <vector> // std::vector
#include <map> // std::map
#include <stdexcept> // throw std::runtime_error()
#include "thirdparty/json.hpp"
#include "conversions.hpp"
#include "operators.hpp"
#include "constants.hpp" // MAX_BLOCK_SIZE
#include "opencl/init.hpp"
#include "opencl/openclhandle.hpp"
#include "opencl/opencllockingdata.hpp"
#include "opencl/programarguments.hpp"
#include "opencl/kernelarguments.hpp"
#include "opencl/commandqueuearguments.hpp"
#include "opencl/ndrangekernelarguments.hpp"
#include "opencl/opencllockingdata.hpp"
#include "opencl/readbufferarguments.hpp"

extern bool __noOpenCL;

extern "C" void lockBlockChainASM(unsigned long timeout);

namespace ZetaChain_Native {

	template <class BlockType>
	class Blockchain {

	public:
		Blockchain(){

		}

		Blockchain(std::map<std::string, BlockType>, std::vector<Blockchain<BlockType>> orphanedChains) : public Blockchain() {

			this->blocks = hashedBlocks;
			this->orphanedChains = orphanedChains;
		}

		virtual ~Blockchain() {
			// for(int i = 0; i < this->blocks->size() - 1; i++) {
			// 	delete this->blocks[i];
			// }
			// delete this->blocks;

			// for(int i = 0; i < this->orphanedChains->size(); i++) [
			// 	delete this->orphanedChains[i];
			// ]
			// delete this->orphanedChains;
		}

		template <class BlockType>

		bool add(BlockType block) {
			if(block->getData() == nullptr)
				throw std::runtime_error("Can not add a null block to a blockchain");

			block->setHeight(this->count + 1);
			block->setIndex(this->count);

			if(lastBlock == nullptr)
				block->setPreviousHash("");
			else
				block->setPreviousHash(lastBlock->getHash());

			block->mine();
			block->lock();

			std::string hash = block->getHash();
			if(!containsBlockByHash(hash)) {
				this->blocks.insert( {hash, *block} );
				this->count++;
				lastBlock = block;
				return true;
			}
			std::cout << "[WARNING] Block with Hash: " << hash << " was already present in the blockchain Skipping" << std::endl;
			return false;
		}

		bool containsBlockByHash(std::string hash){
			if(this->blocks.find(hash) == this->blocks.end())
				return false;

			return true;
		}

		BlockType getBlockByHash(std::string hash){
			if(!this->containsBlockByHash(hash))
				return nullptr;

			return this->blocks[hash];
		}

		bool containsBlockByHeight(unsigned long height) {
			return height <= count + 1;
		}

		BlockType getBlockByHeight(unsigned long height) {
			if(!this->containsBlockByHeight(height))
				return nullptr;

			std::string hash = this->lastBlock->getHash();
			BlockType blk = *this->lastBlock;

			while(hash != ""){
				blk = getBlockByHash(hash);
				if(blk.getHeight() == height)
					return blk;
				hash = blk.getPreviousHash();
			}

			return nullptr;
		}

		std::vector<unsigned char> toBytes() {
			std::vector<unsigned char> bytes = std::vector<unsigned char>(sizeof(Blockchain<BlockType>));
			if(this->lastBlock != nullptr){
				// for(int i = 0 i < sizeof(BlockData) - 1; i++){
				// 	bytes.push_back(static_cast<unsigned char>(*(this->lastBlock + i)));
				// }
				bytes += this->lastBlock->toBytes();
			}
			for(std::map<std::string, BlockType>::iterator it = this->blocks.begin(); it != this->blocks.end(); it++) {
				bytes += it->second->toBytes();
			}
			if (this->orphanedChains.size() > 0) {
				for (int i = 0; i < this->orphanedChains.size() - 1; i++) {
					bytes += orphanedChains[i]->toBytes();
				}
			}
			return bytes;
		}

		bool verify() {
			for(std::map<std::string, BlockType>::iterator itr = blocks.begin(); itr != blocks.end(); itr++) {
				if(!itr->second.verify())
				return false;
			}
			return true;
		}

		bool lock(unsigned long timeout = 1000) {
			if(this->timeLocked != 0)
			return true;

			if(!__noOpenCL) {
				OpenCL::OpenCLLockingData* lockingData = OpenCL::OpenCLLockingData::getInstance();
				if(!lockingData->handle){
					lockingData->handle = OpenCL::init();
					if(!lockingData->handle){
						throw std::runtime_error("Failed to Initialise OpenCL Handle please update your drivers or restart the application with the --noOpenCL option");
					}
				}
				else {
					cl_program program = lockingData->handle->createProgram(lockingData->handle->loadKernel("kernels/lockblockchain.cl"));
					lockingData->currentProgram = new OpenCL::OpenCLProgram(program, "kernels/lockblockchain.cl", &lockingData->handle);
					if(!lockingData->currentProgram) {
						throw std::runtime_error("Failed to Create Program with Kernel Code kernels/lockblockchain.cl");
					}
					OpenCL::ProgramArguments pArgs = {
						program,
						lockingData->handle->getDevices().size(),
						lockingData->handle->getDevices().data(),
						nullptr,
						nullptr,
						nullptr
					};
					lockingData->handle->checkError(lockingData->handle->buildProgram(pArgs));
					cl_int error = CL_SUCCESS;
					OpenCL::KernelArguments kArgs = {
						lockingData->currentProgram->getProgram(),
						"lockblock.cl",
						&error
					};
					cl_kernel kernel = lockingData->handle->createKernel(kArgs);
					lockingData->currentKernel = new OpenCL::OpenCLKernel(kernel, "kernels/lockblockchain.cl", &lockingData->handle);
					lockingData->handle->checkError(error);
					unsigned long kernelData = timeout + 1; // Adding 1 because of OpenCL control thread
					const size_t KERNEL_DATA_SIZE = sizeof(kernelData);
					OpenCL::BufferArguments aBufferArgs = {
						CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
						KERNEL_DATA_SIZE,
						reinterpret_cast<void*>(&kernelData),
						&error
					};
					cl_mem aBuffer = lockingData->handle->createBuffer(aBufferArgs);
					lockingData->currentABuffer = new OpenCL::OpenCLBuffer<unsigned long>(aBuffer, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, kernelData, &lockingData->handle);
					int result = -1;
					OpenCL::BufferArguments bBufferArgs = {
						CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
						sizeof(int),
						reinterpret_cast<void*>(&result),
						&error
					};
					cl_mem bBuffer = lockingData->handle->createBuffer(bBufferArgs);
					lockingData->currentBBuffer = new OpenCL::OpenCLBuffer<int>(bBuffer, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, kernelData, &lockingData->handle);
					OpenCL::CommandQueueArguments commandArgs = {
						lockingData->handle->getDevices()[0],
						NULL,
						&error
					};
					cl_command_queue commandQueue = lockingData->handle->createCommandQueue(commandArgs);
					lockingData->currentCommandQueue = new OpenCL::OpenCLCommandQueue(commandQueue, lockingData->handle->getDevices()[0], NULL, &lockingData->handle);
					OpenCL::KernelArgArguments arg_iterations = {
						kernel,
						0,
						sizeof(cl_mem),
						&aBuffer
					};
					lockingData->handle->setKernelArgument(arg_iterations);
					OpenCL::KernelArgArguments arg_result = {
						kernel,
						1,
						sizeof(cl_mem),
						&bBuffer
					};
					lockingData->handle->setKernelArgument(arg_result);
					const size_t globalWorkSize[] = { KERNEL_DATA_SIZE, 0, 0 };
					OpenCL::NDRangeKernelArguments ndArgs = {
						commandQueue,
						kernel,
						1,
						nullptr,
						0,
						nullptr,
						NULL
					};
					lockingData->handle->checkError(lockingData->handle->enqueueNDRangeKernel(ndArgs));
					OpenCL::ReadBufferArguments readArgs = {
						commandQueue,
						bBuffer,
						CL_TRUE,
						0,
						sizeof(int),
						reinterpret_cast<void*>(&result),
						0,
						nullptr,
						nullptr
					};
					lockingData->handle->checkError(lockingData->handle->enqueueReadBuffer(readArgs));
					lockingData->handle->releaseCommandQueue(commandQueue);
					lockingData->handle->releaseMemObject(bBuffer);
					lockingData->handle->releaseMemObject(aBuffer);
					lockingData->handle->releaseKernel(kernel);
					lockingData->handle->releaseProgram(program);

					delete lockingData->currentCommandQueue;
					delete lockingData->currentBBuffer;
					delete lockingData->currentABuffer;
					delete lockingData->currentKernel;
					delete lockingData->currentProgram;
					delete lockingData->handle;
				}
			}
			else {
				lockBlockChainASM(timeout);
			}

			time_t now;
			time(&now);
			struct tm* timeinfo;
			timeinfo = localtime(&now);
			this->timeLocked = now - (timeout / 1000);
			time_t _time = this->timeLocked;
			this->hash = computeHash();
			std::cout << "Block Data has Sucessfully been locked" << std::endl;
			return this->timeLocked != 0;;
		}

		std::string toString() {
			nlohmann::json j;
			nlohmann::json lBlock = this->lastBlock->toString();
			nlohmann::json blocksArr = nlohmann::json::array();
			nlohmann::json orphanedChainsArr = nlohmann::json::array();

			std::vector<std::string> blockValues = std::vector<std::string>(this->blocks.size());

			for(std::map<std::string, BlockType>::iterator itr = this->blocks.begin(); itr != this->blocks.end(); itr++) {
				blockValues.push_back(itr->second.toString());
			}

			for(int i = 0; i < blockValues.size() - 1; i++) {
				nlohmann::json obj = blockValues[i];
				blocksArr.push_back(obj);
			}

			for(int i = 0; i < orphanedChains.size() - 1; i++) {
				nlohmann::json obj = orphanedChains[i]->toString();
				orphanedChainsArr.push_back(obj);
			}

			j["lastBlock", lBlock.dump()];
			j["count", this->count];
			j["orphanCount", this->orphanCount];
			j["blocks", blocksArr.dump()];
			j["orphanedChains", orphanedChainsArr.dump()];
			return j;
		}

		std::map<std::string, BlockType> getBlocks() {
			return this->blocks;
		}

		std::vector<Blockchain<BlockType>*> getOrphanedChains() {
			return this->orphanedChains;
		}

		BlockType* getLastBlock() {
			return this->lastBlock;
		}

		unsigned long getCount() {
			return this->count;
		}

		unsigned long getOrphanCount() {
			return this->orphanCount;
		}

		void setBlocks(std::map<std::string, BlockType> blocks) {
			if(this->blocks.size() != 0)
				throw std::runtime_error("Can not set blocks for a non empty blockchain");
			this->blocks = blocks;
		}

		void setOrphanedChains(std::vector<Blockchain<BlockType>*> orphanedChains) {
			if(this->orphanedChains.size() != 0)
				throw std::runtime_error("Can not set orphaned chains for a non empty blockchain");
			this->orphanedChains = orphanedChains;
		}

		void setLastBlock(BlockType* lastBlock) {
			if(this->lastBlock != nullptr)
				throw std::runtime_error("Can not modify last block as it is not null");
			this->lastBlock = lastBlock;
		}

		void setCount(unsigned long count) {
			if(this->count != 0)
				throw std::runtime_error("Can not set block count for a non empty blockchain");
			this->count = count;
		}

		void setOrphanCount(unsigned long orphanCount) {
			if(this->orphanCount != 0)
				throw std::runtime_error("Can not set orphan count for a non empty blockchain");
			this->count = orphanCount;
		}

	protected:

	private:
		BlockType* lastBlock = new BlockType();
		unsigned long count = 0;
		unsigned long orphanCount = 0;
		std::map<std::string, BlockType> blocks = std::map<std::string, BlockType>();
		std::vector<Blockchain<BlockType>*> orphanedChains = std::vector<Blockchain<BlockType>*>();
	};
}<commit_msg>Fix Typo<commit_after>#pragma once

/*
MIT License

Copyright (c) 2017 ZetaChain_Native

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 "platform.hpp" // Platform Specific Stuff NOTE: Must Always be the first include in a file
#include <iostream> // std::cout
#include <string> // std::string
#include <algorithm> // std::find_if
#include <vector> // std::vector
#include <map> // std::map
#include <stdexcept> // throw std::runtime_error()
#include "thirdparty/json.hpp"
#include "conversions.hpp"
#include "operators.hpp"
#include "constants.hpp" // MAX_BLOCK_SIZE
#include "opencl/init.hpp"
#include "opencl/openclhandle.hpp"
#include "opencl/opencllockingdata.hpp"
#include "opencl/programarguments.hpp"
#include "opencl/kernelarguments.hpp"
#include "opencl/commandqueuearguments.hpp"
#include "opencl/ndrangekernelarguments.hpp"
#include "opencl/opencllockingdata.hpp"
#include "opencl/readbufferarguments.hpp"

extern bool __noOpenCL;

extern "C" void lockBlockChainASM(unsigned long timeout);

namespace ZetaChain_Native {

	template <class BlockType>
	class Blockchain {

	public:
		Blockchain(){

		}

		Blockchain(std::map<std::string, BlockType>, std::vector<Blockchain<BlockType>> orphanedChains) : public Blockchain() {

			this->blocks = hashedBlocks;
			this->orphanedChains = orphanedChains;
		}

		virtual ~Blockchain() {
			// for(int i = 0; i < this->blocks->size() - 1; i++) {
			// 	delete this->blocks[i];
			// }
			// delete this->blocks;

			// for(int i = 0; i < this->orphanedChains->size(); i++) [
			// 	delete this->orphanedChains[i];
			// ]
			// delete this->orphanedChains;
		}

		template <class BlockType>

		bool add(BlockType block) {
			if(block->getData() == nullptr)
				throw std::runtime_error("Can not add a null block to a blockchain");

			block->setHeight(this->count + 1);
			block->setIndex(this->count);

			if(lastBlock == nullptr)
				block->setPreviousHash("");
			else
				block->setPreviousHash(lastBlock->getHash());

			block->mine();
			block->lock();

			std::string hash = block->getHash();
			if(!containsBlockByHash(hash)) {
				this->blocks.insert( {hash, *block} );
				this->count++;
				lastBlock = block;
				return true;
			}
			std::cout << "[WARNING] Block with Hash: " << hash << " was already present in the blockchain Skipping" << std::endl;
			return false;
		}

		bool containsBlockByHash(std::string hash){
			if(this->blocks.find(hash) == this->blocks.end())
				return false;

			return true;
		}

		BlockType getBlockByHash(std::string hash){
			if(!this->containsBlockByHash(hash))
				return nullptr;

			return this->blocks[hash];
		}

		bool containsBlockByHeight(unsigned long height) {
			return height <= count + 1;
		}

		BlockType getBlockByHeight(unsigned long height) {
			if(!this->containsBlockByHeight(height))
				return nullptr;

			std::string hash = this->lastBlock->getHash();
			BlockType blk = *this->lastBlock;

			while(hash != ""){
				blk = getBlockByHash(hash);
				if(blk.getHeight() == height)
					return blk;
				hash = blk.getPreviousHash();
			}

			return nullptr;
		}

		std::vector<unsigned char> toBytes() {
			std::vector<unsigned char> bytes = std::vector<unsigned char>(sizeof(Blockchain<BlockType>));
			if(this->lastBlock != nullptr){
				// for(int i = 0 i < sizeof(BlockData) - 1; i++){
				// 	bytes.push_back(static_cast<unsigned char>(*(this->lastBlock + i)));
				// }
				bytes += this->lastBlock->toBytes();
			}
			for(std::map<std::string, BlockType>::iterator it = this->blocks.begin(); it != this->blocks.end(); it++) {
				bytes += it->second->toBytes();
			}
			if (this->orphanedChains.size() > 0) {
				for (int i = 0; i < this->orphanedChains.size() - 1; i++) {
					bytes += orphanedChains[i]->toBytes();
				}
			}
			return bytes;
		}

		bool verify() {
			for(std::map<std::string, BlockType>::iterator itr = blocks.begin(); itr != blocks.end(); itr++) {
				if(!itr->second.verify())
				return false;
			}
			return true;
		}

		bool lock(unsigned long timeout = 1000) {
			if(this->timeLocked != 0)
			return true;

			if(!__noOpenCL) {
				OpenCL::OpenCLLockingData* lockingData = OpenCL::OpenCLLockingData::getInstance();
				if(!lockingData->handle){
					lockingData->handle = OpenCL::init();
					if(!lockingData->handle){
						throw std::runtime_error("Failed to Initialise OpenCL Handle please update your drivers or restart the application with the --noOpenCL option");
					}
				}
				else {
					cl_program program = lockingData->handle->createProgram(lockingData->handle->loadKernel("kernels/lockblockchain.cl"));
					lockingData->currentProgram = new OpenCL::OpenCLProgram(program, "kernels/lockblockchain.cl", &lockingData->handle);
					if(!lockingData->currentProgram) {
						throw std::runtime_error("Failed to Create Program with Kernel Code kernels/lockblockchain.cl");
					}
					OpenCL::ProgramArguments pArgs = {
						program,
						lockingData->handle->getDevices().size(),
						lockingData->handle->getDevices().data(),
						nullptr,
						nullptr,
						nullptr
					};
					lockingData->handle->checkError(lockingData->handle->buildProgram(pArgs));
					cl_int error = CL_SUCCESS;
					OpenCL::KernelArguments kArgs = {
						lockingData->currentProgram->getProgram(),
						"lockblock.cl",
						&error
					};
					cl_kernel kernel = lockingData->handle->createKernel(kArgs);
					lockingData->currentKernel = new OpenCL::OpenCLKernel(kernel, "kernels/lockblockchain.cl", &lockingData->handle);
					lockingData->handle->checkError(error);
					unsigned long kernelData = timeout + 1; // Adding 1 because of OpenCL control thread
					const size_t KERNEL_DATA_SIZE = sizeof(kernelData);
					OpenCL::BufferArguments aBufferArgs = {
						CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
						KERNEL_DATA_SIZE,
						reinterpret_cast<void*>(&kernelData),
						&error
					};
					cl_mem aBuffer = lockingData->handle->createBuffer(aBufferArgs);
					lockingData->currentABuffer = new OpenCL::OpenCLBuffer<unsigned long>(aBuffer, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, kernelData, &lockingData->handle);
					int result = -1;
					OpenCL::BufferArguments bBufferArgs = {
						CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
						sizeof(int),
						reinterpret_cast<void*>(&result),
						&error
					};
					cl_mem bBuffer = lockingData->handle->createBuffer(bBufferArgs);
					lockingData->currentBBuffer = new OpenCL::OpenCLBuffer<int>(bBuffer, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, kernelData, &lockingData->handle);
					OpenCL::CommandQueueArguments commandArgs = {
						lockingData->handle->getDevices()[0],
						NULL,
						&error
					};
					cl_command_queue commandQueue = lockingData->handle->createCommandQueue(commandArgs);
					lockingData->currentCommandQueue = new OpenCL::OpenCLCommandQueue(commandQueue, lockingData->handle->getDevices()[0], NULL, &lockingData->handle);
					OpenCL::KernelArgArguments arg_iterations = {
						kernel,
						0,
						sizeof(cl_mem),
						&aBuffer
					};
					lockingData->handle->setKernelArgument(arg_iterations);
					OpenCL::KernelArgArguments arg_result = {
						kernel,
						1,
						sizeof(cl_mem),
						&bBuffer
					};
					lockingData->handle->setKernelArgument(arg_result);
					const size_t globalWorkSize[] = { KERNEL_DATA_SIZE, 0, 0 };
					OpenCL::NDRangeKernelArguments ndArgs = {
						commandQueue,
						kernel,
						1,
						nullptr,
						0,
						nullptr,
						NULL
					};
					lockingData->handle->checkError(lockingData->handle->enqueueNDRangeKernel(ndArgs));
					OpenCL::ReadBufferArguments readArgs = {
						commandQueue,
						bBuffer,
						CL_TRUE,
						0,
						sizeof(int),
						reinterpret_cast<void*>(&result),
						0,
						nullptr,
						nullptr
					};
					lockingData->handle->checkError(lockingData->handle->enqueueReadBuffer(readArgs));
					lockingData->handle->releaseCommandQueue(commandQueue);
					lockingData->handle->releaseMemObject(bBuffer);
					lockingData->handle->releaseMemObject(aBuffer);
					lockingData->handle->releaseKernel(kernel);
					lockingData->handle->releaseProgram(program);

					delete lockingData->currentCommandQueue;
					delete lockingData->currentBBuffer;
					delete lockingData->currentABuffer;
					delete lockingData->currentKernel;
					delete lockingData->currentProgram;
					delete lockingData->handle;
				}
			}
			else {
				lockBlockChainASM(timeout);
			}

			time_t now;
			time(&now);
			struct tm* timeinfo;
			timeinfo = localtime(&now);
			this->timeLocked = now - (timeout / 1000);
			time_t _time = this->timeLocked;
			this->hash = computeHash();
			std::cout << "Blockchain has Sucessfully been locked" << std::endl;
			return this->timeLocked != 0;;
		}

		std::string toString() {
			nlohmann::json j;
			nlohmann::json lBlock = this->lastBlock->toString();
			nlohmann::json blocksArr = nlohmann::json::array();
			nlohmann::json orphanedChainsArr = nlohmann::json::array();

			std::vector<std::string> blockValues = std::vector<std::string>(this->blocks.size());

			for(std::map<std::string, BlockType>::iterator itr = this->blocks.begin(); itr != this->blocks.end(); itr++) {
				blockValues.push_back(itr->second.toString());
			}

			for(int i = 0; i < blockValues.size() - 1; i++) {
				nlohmann::json obj = blockValues[i];
				blocksArr.push_back(obj);
			}

			for(int i = 0; i < orphanedChains.size() - 1; i++) {
				nlohmann::json obj = orphanedChains[i]->toString();
				orphanedChainsArr.push_back(obj);
			}

			j["lastBlock", lBlock.dump()];
			j["count", this->count];
			j["orphanCount", this->orphanCount];
			j["blocks", blocksArr.dump()];
			j["orphanedChains", orphanedChainsArr.dump()];
			return j;
		}

		std::map<std::string, BlockType> getBlocks() {
			return this->blocks;
		}

		std::vector<Blockchain<BlockType>*> getOrphanedChains() {
			return this->orphanedChains;
		}

		BlockType* getLastBlock() {
			return this->lastBlock;
		}

		unsigned long getCount() {
			return this->count;
		}

		unsigned long getOrphanCount() {
			return this->orphanCount;
		}

		void setBlocks(std::map<std::string, BlockType> blocks) {
			if(this->blocks.size() != 0)
				throw std::runtime_error("Can not set blocks for a non empty blockchain");
			this->blocks = blocks;
		}

		void setOrphanedChains(std::vector<Blockchain<BlockType>*> orphanedChains) {
			if(this->orphanedChains.size() != 0)
				throw std::runtime_error("Can not set orphaned chains for a non empty blockchain");
			this->orphanedChains = orphanedChains;
		}

		void setLastBlock(BlockType* lastBlock) {
			if(this->lastBlock != nullptr)
				throw std::runtime_error("Can not modify last block as it is not null");
			this->lastBlock = lastBlock;
		}

		void setCount(unsigned long count) {
			if(this->count != 0)
				throw std::runtime_error("Can not set block count for a non empty blockchain");
			this->count = count;
		}

		void setOrphanCount(unsigned long orphanCount) {
			if(this->orphanCount != 0)
				throw std::runtime_error("Can not set orphan count for a non empty blockchain");
			this->count = orphanCount;
		}

	protected:

	private:
		BlockType* lastBlock = new BlockType();
		unsigned long count = 0;
		unsigned long orphanCount = 0;
		std::map<std::string, BlockType> blocks = std::map<std::string, BlockType>();
		std::vector<Blockchain<BlockType>*> orphanedChains = std::vector<Blockchain<BlockType>*>();
	};
}<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "box2d.hpp"

TEST(box2d_test, test_construction)
{
  // Тест на создание объекта по умолчанию.
  Box2D box1;
  EXPECT_EQ(box1.point1(), Point2D(0.0f, 0.0f));
  EXPECT_EQ(box1.point2(), Point2D(1.0f, 1.0f));

  // Тест на создание объекта с параметрами.
  Box2D box2 = { Point2D(1.0f, 2.0f), Point2D(5.0f, 8.0f) };
  EXPECT_EQ(box2.point1(), Point2D(1.0f, 2.0f));
  EXPECT_EQ(box2.point2(), Point2D(5.0f, 8.0f));

  // Тест на создание копии объекта.
  Box2D box3 = box2;
  EXPECT_EQ(box3, box2);
}

TEST(box2d_test, test_check)
{
  // Тест на проверку пересечения прямоугольников
  Box2D box1 = { Point2D(0.0f, 0.0f), Point2D(1.0f, 1.0f) };
  Box2D box2 = { Point2D(0.0f, 2.0f), Point2D(1.0f, 3.0f) };
  Box2D box3 = { Point2D(2.0f, 0.0f), Point2D(3.0f, 1.0f) };
  Box2D box4 = { Point2D(2.0f, 2.0f), Point2D(3.0f, 3.0f) };
  Box2D box5 = { Point2D(0.5f, 0.5f), Point2D(2.5f, 2.5f) };
  Box2D box6 = { Point2D(1.0f, 1.0f), Point2D(2.0f, 2.0f) };
  Box2D box7 = { Point2D(2.0f, 1.0f), Point2D(3.0f, 2.0f) };
  Box2D box8 = { Point2D(1.0f, 2.0f), Point2D(2.0f, 3.0f) };
  Box2D box9 = { Point2D(0.0f, 1.0f), Point2D(1.0f, 2.0f) };
  Box2D box10 = { Point2D(1.0f, 0.0f), Point2D(2.0f, 1.0f) };
  Box2D box11 = { Point2D(0.0f, 0.0f), Point2D(1.0f, 1.0f) };
  EXPECT_EQ(checkBoxes(box1,box2),false);
  EXPECT_EQ(checkBoxes(box2,box1),false);
  EXPECT_EQ(checkBoxes(box2,box3),false);
  EXPECT_EQ(checkBoxes(box3,box2),false);
  EXPECT_EQ(checkBoxes(box5,box3),true);
  EXPECT_EQ(checkBoxes(box3,box5),true);
  EXPECT_EQ(checkBoxes(box5,box4),true);
  EXPECT_EQ(checkBoxes(box4,box5),true);
  EXPECT_EQ(checkBoxes(box6,box5),true);
  EXPECT_EQ(checkBoxes(box5,box6),true);
  EXPECT_EQ(checkBoxes(box7,box5),true);
  EXPECT_EQ(checkBoxes(box5,box7),true);
  EXPECT_EQ(checkBoxes(box8,box5),true);
  EXPECT_EQ(checkBoxes(box5,box8),true);
  EXPECT_EQ(checkBoxes(box9,box5),true);
  EXPECT_EQ(checkBoxes(box5,box9),true);
  EXPECT_EQ(checkBoxes(box10,box5),true);
  EXPECT_EQ(checkBoxes(box5,box10),true);
  EXPECT_EQ(checkBoxes(box6,box3),false);
  EXPECT_EQ(checkBoxes(box3,box6),false);
  EXPECT_EQ(checkBoxes(box7,box6),false);
  EXPECT_EQ(checkBoxes(box6,box7),false);
  EXPECT_EQ(checkBoxes(box8,box6),false);
  EXPECT_EQ(checkBoxes(box6,box8),false);
  EXPECT_EQ(checkBoxes(box2,box6),false);
  EXPECT_EQ(checkBoxes(box6,box2),false);
  EXPECT_EQ(checkBoxes(box1,box11),true);
  EXPECT_EQ(checkBoxes(box11,box1),true);
}
<commit_msg>reformat code; add additional tests<commit_after>#include "gtest/gtest.h"
#include "box2d.hpp"

TEST(box2d_test, test_construction)
{
  // Тест на создание объекта по умолчанию.
  Box2D box1;
  EXPECT_EQ(box1.point1(), Point2D(0.0f, 0.0f));
  EXPECT_EQ(box1.point2(), Point2D(1.0f, 1.0f));

  // Тест на создание объекта с параметрами.
  Box2D box2 = { Point2D(1.0f, 2.0f), Point2D(5.0f, 8.0f) };
  EXPECT_EQ(box2.point1(), Point2D(1.0f, 2.0f));
  EXPECT_EQ(box2.point2(), Point2D(5.0f, 8.0f));

  // Тест на создание копии объекта.
  Box2D box3 = box2;
  EXPECT_EQ(box3, box2);
}

TEST(box2d_test, test_check)
{
  // Тест на проверку пересечения прямоугольников
  Box2D box1 = { Point2D(0.0f, 0.0f), Point2D(1.0f, 1.0f) };
  Box2D box2 = { Point2D(0.0f, 2.0f), Point2D(1.0f, 3.0f) };
  Box2D box3 = { Point2D(2.0f, 0.0f), Point2D(3.0f, 1.0f) };
  Box2D box4 = { Point2D(2.0f, 2.0f), Point2D(3.0f, 3.0f) };
  Box2D box5 = { Point2D(0.5f, 0.5f), Point2D(2.5f, 2.5f) };
  Box2D box6 = { Point2D(1.0f, 1.0f), Point2D(2.0f, 2.0f) };
  Box2D box7 = { Point2D(2.0f, 1.0f), Point2D(3.0f, 2.0f) };
  Box2D box8 = { Point2D(1.0f, 2.0f), Point2D(2.0f, 3.0f) };
  Box2D box9 = { Point2D(0.0f, 1.0f), Point2D(1.0f, 2.0f) };
  Box2D box10 = { Point2D(1.0f, 0.0f), Point2D(2.0f, 1.0f) };
  Box2D box11 = { Point2D(0.0f, 0.0f), Point2D(1.0f, 1.0f) };
  EXPECT_EQ(Box2D::checkBoxes(box1,box2),false);
  EXPECT_EQ(Box2D::checkBoxes(box2,box1),false);
  EXPECT_EQ(Box2D::checkBoxes(box2,box3),false);
  EXPECT_EQ(Box2D::checkBoxes(box3,box2),false);
  EXPECT_EQ(Box2D::checkBoxes(box5,box3),true);
  EXPECT_EQ(Box2D::checkBoxes(box3,box5),true);
  EXPECT_EQ(Box2D::checkBoxes(box5,box4),true);
  EXPECT_EQ(Box2D::checkBoxes(box4,box5),true);
  EXPECT_EQ(Box2D::checkBoxes(box6,box5),true);
  EXPECT_EQ(Box2D::checkBoxes(box5,box6),true);
  EXPECT_EQ(Box2D::checkBoxes(box7,box5),true);
  EXPECT_EQ(Box2D::checkBoxes(box5,box7),true);
  EXPECT_EQ(Box2D::checkBoxes(box8,box5),true);
  EXPECT_EQ(Box2D::checkBoxes(box5,box8),true);
  EXPECT_EQ(Box2D::checkBoxes(box9,box5),true);
  EXPECT_EQ(Box2D::checkBoxes(box5,box9),true);
  EXPECT_EQ(Box2D::checkBoxes(box10,box5),true);
  EXPECT_EQ(Box2D::checkBoxes(box5,box10),true);
  EXPECT_EQ(Box2D::checkBoxes(box6,box3),false);
  EXPECT_EQ(Box2D::checkBoxes(box3,box6),false);
  EXPECT_EQ(Box2D::checkBoxes(box7,box6),false);
  EXPECT_EQ(Box2D::checkBoxes(box6,box7),false);
  EXPECT_EQ(Box2D::checkBoxes(box8,box6),false);
  EXPECT_EQ(Box2D::checkBoxes(box6,box8),false);
  EXPECT_EQ(Box2D::checkBoxes(box2,box6),false);
  EXPECT_EQ(Box2D::checkBoxes(box6,box2),false);
  EXPECT_EQ(Box2D::checkBoxes(box1,box11),true);
  EXPECT_EQ(Box2D::checkBoxes(box11,box1),true);
}

TEST(box2d_test, test_point_check_inside)
{
  Point2D p1 = { 0.0f, 0.0f };

  Point2D p2 = { 0.0f, 0.0f };

  Box2D box1 = { Point2D(-1.0f, -1.0f),
                 Point2D(1.0f, 1.0f) };

  Box2D box2 = { Point2D(1.0f, 1.0f),
                 Point2D(-1.0f, -1.0f) };

  EXPECT_EQ(Box2D::checkInside(box1, p1), true);
  EXPECT_EQ(Box2D::checkInside(box2, p2), true);
}

TEST(box2d_test, test_point_check_outside)
{
  Point2D p1 = { 2.0f, 1.0f };

  Point2D p2 = { -10.0f, -3.0f };

  Box2D box1 = { Point2D(-1.0f, -1.0f),
                 Point2D(1.0f, 1.0f) };

  Box2D box2 = { Point2D(1.0f, 1.0f),
                 Point2D(-1.0f, -1.0f) };

  EXPECT_EQ(Box2D::checkInside(box1, p1), false);
  EXPECT_EQ(Box2D::checkInside(box2, p2), false);
}
<|endoftext|>


<commit_before>#include "State.h"

State::State(double _theta, double _theta_dot, ROBOT_STATE _robot_state):
  theta(_theta),
  theta_dot(_theta_dot),
  robot_state(_robot_state)
{}

double State::getReward(){
        g * std::cos(theta) + 0.5 * theta_dot * theta_dot;
    }
<commit_msg>added return to "getReward()"<commit_after>#include "State.h"

State::State(double _theta, double _theta_dot, ROBOT_STATE _robot_state):
  theta(_theta),
  theta_dot(_theta_dot),
  robot_state(_robot_state)
{}

double State::getReward(){
  return g * std::cos(theta) + 0.5 * theta_dot * theta_dot;
}
<|endoftext|>


<commit_before>/*
    Copyright 2015 Vision Lab, Univeristy of Antwerp, Belgium

    Written by Ben Jeurissen, 28/08/15.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "command.h"
#include "progressbar.h"
#include "image.h"
#include "algo/threaded_copy.h"
#include "dwi/gradient.h"
#include "dwi/tensor.h"
#include <Eigen/Eigenvalues>

using namespace MR;
using namespace App;
using namespace std;

typedef float value_type;
const char* modulate_choices[] = { "none", "fa", "eigval", NULL };

void usage ()
{
  ARGUMENTS
  + Argument ("dwi", "the input dwi image.").type_image_in ();

  OPTIONS
  + Option ("adc",
            "compute the mean apparent diffusion coefficient (ADC) of the diffusion tensor.")
  + Argument ("image").type_image_out()

  + Option ("fa",
            "compute the fractional anisotropy of the diffusion tensor.")
  + Argument ("image").type_image_out()

  + Option ("value",
            "compute the selected eigenvalue(s) of the diffusion tensor.")
  + Argument ("image").type_image_out()

  + Option ("vector",
            "compute the selected eigenvector(s) of the diffusion tensor.")
  + Argument ("image").type_image_out()

  + Option ("num",
            "specify the desired eigenvalue/eigenvector(s). Note that several eigenvalues "
            "can be specified as a number sequence. For example, '1,3' specifies the "
            "major (1) and minor (3) eigenvalues/eigenvectors (default = 1).")
  + Argument ("image")

  + Option ("modulate",
            "specify how to modulate the magnitude of the eigenvectors. Valid choices "
            "are: none, FA, eigval (default = FA).")
  + Argument ("spec").type_choice (modulate_choices)

  + Option ("mask",
            "only perform computation within the specified binary brain mask image.")
  + Argument ("image").type_image_in();

  AUTHOR = "Ben Jeurissen (ben.jeurissen@uantwerpen.be) & J-Donald Tournier (jdtournier@gmail.com)";

  DESCRIPTION
  + "Generate maps of tensor-derived parameters.";

  REFERENCES
  + "Basser, P. J.; Mattiello, J. & Lebihan, D. "
    "MR diffusion tensor spectroscopy and imaging. "
    "Biophysical Journal, 1994, 66, 259-267";
}

template <class MASKType, class ADCType, class FAType, class VALUEType, class VECTORType>
class Processor
{
  public:
    Processor (MASKType* mask_image, ADCType* adc_image, FAType* fa_image, VALUEType* value_image, VECTORType* vector_image, std::vector<int> vals, int modulate) :
      mask_image (mask_image),
      adc_image (adc_image),
      fa_image (fa_image),
      value_image (value_image),
      vector_image (vector_image),
      vals (vals),
      modulate (modulate) { }

    template <class DTType>
      void operator() (DTType& dt_image)
      {
        /* check mask */
        if (mask_image) {
          assign_pos_of (dt_image, 0, 3).to (*mask_image);
          if (!mask_image->value())
            return;
        }

        /* input dt */
        Eigen::Matrix<double, 6, 1> dt;
        for (auto l = Loop (3) (dt_image); l; ++l)
          dt[dt_image.index(3)] = dt_image.value();

        /* output adc */
        if (adc_image) {
          assign_pos_of (dt_image, 0, 3).to (*adc_image);
          adc_image->value() = DWI::tensor2ADC(dt);
        }

        double fa;
        if (fa_image || (vector_image && (modulate == 1)))
          fa = DWI::tensor2FA(dt);

        /* output fa */
        if (fa_image) {
          assign_pos_of (dt_image, 0, 3).to (*fa_image);
          fa_image->value() = fa;
        }

        Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> es;
	if (value_image || vector_image) {
          Eigen::Matrix3d M;
          M (0,0) = dt[0];
          M (1,1) = dt[1];
          M (2,2) = dt[2];
          M (0,1) = M (1,0) = dt[3];
          M (0,2) = M (2,0) = dt[4];
          M (1,2) = M (2,1) = dt[5];
          es = Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d>(M, vector_image ? Eigen::ComputeEigenvectors : Eigen::EigenvaluesOnly);
        }

        Eigen::Vector3d eigval;
        if (value_image || (vector_image && (modulate == 2)))
          eigval = es.eigenvalues();

        /* output value */
        if (value_image) {
          assign_pos_of (dt_image, 0, 3).to (*value_image);
          auto l = Loop(3)(*value_image);
          for (int i = 0; i < vals.size(); i++) {
            value_image->value() = eigval(3-vals[i]); l++;
          }
        }

        /* output vector */
        if (vector_image) {
          Eigen::Matrix3d eigvec = es.eigenvectors();
          assign_pos_of (dt_image, 0, 3).to (*vector_image);
          auto l = Loop(3)(*vector_image);
          for (int i = 0; i < vals.size(); i++) {
            double fact = 1.0;
            if (modulate == 1)
              fact = fa;
            else if (modulate == 2)
              fact = eigval(3-vals[i]);
            vector_image->value() = eigvec(0,3-vals[i])*fact; l++;
            vector_image->value() = eigvec(1,3-vals[i])*fact; l++;
            vector_image->value() = eigvec(2,3-vals[i])*fact; l++;
          }
        }
      }

  private:
    copy_ptr<MASKType> mask_image;
    copy_ptr<ADCType> adc_image;
    copy_ptr<FAType> fa_image;
    copy_ptr<VALUEType> value_image;
    copy_ptr<VECTORType> vector_image;
    std::vector<int> vals;
    int modulate;
};

template <class MASKType, class ADCType, class FAType, class VALUEType, class VECTORType>
inline Processor<MASKType, ADCType, FAType, VALUEType, VECTORType> processor (MASKType* mask_image, ADCType* adc_image, FAType* fa_image, VALUEType* value_image, VECTORType* vector_image, std::vector<int> vals, int modulate) {
  return { mask_image, adc_image, fa_image, value_image, vector_image, vals, modulate };
}

void run ()
{
  auto dt = Header::open (argument[0]).get_image<value_type>();
  auto header = dt.header();
  header.datatype() = DataType::Float32;

  Image<bool>* mask = nullptr;
  auto opt = get_options ("mask");
  if (opt.size()) {
    mask = new Image<bool> (Image<bool>::open (opt[0][0]));
    check_dimensions (dt, *mask, 0, 3);
  }

  Image<value_type>* adc = nullptr;
  opt = get_options ("adc");
  if (opt.size()) {
    header.set_ndim (3);
    adc = new Image<value_type> (Image<value_type>::create (opt[0][0], header));
  }

  Image<value_type>* fa = nullptr;
  opt = get_options ("fa");
  if (opt.size()) {
    header.set_ndim (3);
    fa = new Image<value_type> (Image<value_type>::create (opt[0][0], header));
  }

  std::vector<int> vals = {1};
  opt = get_options ("num");
  if (opt.size()) {
    vals = opt[0][0];
  if (vals.empty())
    throw Exception ("invalid eigenvalue/eigenvector number specifier");
  for (size_t i = 0; i < vals.size(); ++i)
    if (vals[i] < 1 || vals[i] > 3)
      throw Exception ("eigenvalue/eigenvector number is out of bounds");
  }

  int modulate = 1;
  opt = get_options ("modulate");
  if (opt.size())
    modulate = opt[0][0];

  Image<value_type>* value = nullptr;
  opt = get_options ("value");
  if (opt.size()) {
    header.set_ndim (4);
    header.size (3) = vals.size();
    value = new Image<value_type> (Image<value_type>::create (opt[0][0], header));
  }

  Image<value_type>* vector = nullptr;
  opt = get_options ("vector");
  if (opt.size()) {
    header.set_ndim (4);
    header.size (3) = vals.size()*3;
    vector = new Image<value_type> (Image<value_type>::create (opt[0][0], header));
  }

  ThreadedLoop("computing metrics...", dt, 0, 3).run (processor (mask, adc, fa, value, vector, vals, modulate), dt);
}
<commit_msg>fixed uninitialised value compiler warning in tensor2metric<commit_after>/*
    Copyright 2015 Vision Lab, Univeristy of Antwerp, Belgium

    Written by Ben Jeurissen, 28/08/15.

    This file is part of MRtrix.

    MRtrix is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MRtrix is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "command.h"
#include "progressbar.h"
#include "image.h"
#include "algo/threaded_copy.h"
#include "dwi/gradient.h"
#include "dwi/tensor.h"
#include <Eigen/Eigenvalues>

using namespace MR;
using namespace App;
using namespace std;

typedef float value_type;
const char* modulate_choices[] = { "none", "fa", "eigval", NULL };

void usage ()
{
  ARGUMENTS
  + Argument ("dwi", "the input dwi image.").type_image_in ();

  OPTIONS
  + Option ("adc",
            "compute the mean apparent diffusion coefficient (ADC) of the diffusion tensor.")
  + Argument ("image").type_image_out()

  + Option ("fa",
            "compute the fractional anisotropy of the diffusion tensor.")
  + Argument ("image").type_image_out()

  + Option ("value",
            "compute the selected eigenvalue(s) of the diffusion tensor.")
  + Argument ("image").type_image_out()

  + Option ("vector",
            "compute the selected eigenvector(s) of the diffusion tensor.")
  + Argument ("image").type_image_out()

  + Option ("num",
            "specify the desired eigenvalue/eigenvector(s). Note that several eigenvalues "
            "can be specified as a number sequence. For example, '1,3' specifies the "
            "major (1) and minor (3) eigenvalues/eigenvectors (default = 1).")
  + Argument ("image")

  + Option ("modulate",
            "specify how to modulate the magnitude of the eigenvectors. Valid choices "
            "are: none, FA, eigval (default = FA).")
  + Argument ("spec").type_choice (modulate_choices)

  + Option ("mask",
            "only perform computation within the specified binary brain mask image.")
  + Argument ("image").type_image_in();

  AUTHOR = "Ben Jeurissen (ben.jeurissen@uantwerpen.be) & J-Donald Tournier (jdtournier@gmail.com)";

  DESCRIPTION
  + "Generate maps of tensor-derived parameters.";

  REFERENCES
  + "Basser, P. J.; Mattiello, J. & Lebihan, D. "
    "MR diffusion tensor spectroscopy and imaging. "
    "Biophysical Journal, 1994, 66, 259-267";
}

template <class MASKType, class ADCType, class FAType, class VALUEType, class VECTORType>
class Processor
{
  public:
    Processor (MASKType* mask_image, ADCType* adc_image, FAType* fa_image, VALUEType* value_image, VECTORType* vector_image, std::vector<int> vals, int modulate) :
      mask_image (mask_image),
      adc_image (adc_image),
      fa_image (fa_image),
      value_image (value_image),
      vector_image (vector_image),
      vals (vals),
      modulate (modulate) { }

    template <class DTType>
      void operator() (DTType& dt_image)
      {
        /* check mask */
        if (mask_image) {
          assign_pos_of (dt_image, 0, 3).to (*mask_image);
          if (!mask_image->value())
            return;
        }

        /* input dt */
        Eigen::Matrix<double, 6, 1> dt;
        for (auto l = Loop (3) (dt_image); l; ++l)
          dt[dt_image.index(3)] = dt_image.value();

        /* output adc */
        if (adc_image) {
          assign_pos_of (dt_image, 0, 3).to (*adc_image);
          adc_image->value() = DWI::tensor2ADC(dt);
        }

        double fa = 0.0;
        if (fa_image || (vector_image && (modulate == 1)))
          fa = DWI::tensor2FA(dt);

        /* output fa */
        if (fa_image) {
          assign_pos_of (dt_image, 0, 3).to (*fa_image);
          fa_image->value() = fa;
        }

        Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> es;
	if (value_image || vector_image) {
          Eigen::Matrix3d M;
          M (0,0) = dt[0];
          M (1,1) = dt[1];
          M (2,2) = dt[2];
          M (0,1) = M (1,0) = dt[3];
          M (0,2) = M (2,0) = dt[4];
          M (1,2) = M (2,1) = dt[5];
          es = Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d>(M, vector_image ? Eigen::ComputeEigenvectors : Eigen::EigenvaluesOnly);
        }

        Eigen::Vector3d eigval;
        if (value_image || (vector_image && (modulate == 2)))
          eigval = es.eigenvalues();

        /* output value */
        if (value_image) {
          assign_pos_of (dt_image, 0, 3).to (*value_image);
          auto l = Loop(3)(*value_image);
          for (int i = 0; i < vals.size(); i++) {
            value_image->value() = eigval(3-vals[i]); l++;
          }
        }

        /* output vector */
        if (vector_image) {
          Eigen::Matrix3d eigvec = es.eigenvectors();
          assign_pos_of (dt_image, 0, 3).to (*vector_image);
          auto l = Loop(3)(*vector_image);
          for (int i = 0; i < vals.size(); i++) {
            double fact = 1.0;
            if (modulate == 1)
              fact = fa;
            else if (modulate == 2)
              fact = eigval(3-vals[i]);
            vector_image->value() = eigvec(0,3-vals[i])*fact; l++;
            vector_image->value() = eigvec(1,3-vals[i])*fact; l++;
            vector_image->value() = eigvec(2,3-vals[i])*fact; l++;
          }
        }
      }

  private:
    copy_ptr<MASKType> mask_image;
    copy_ptr<ADCType> adc_image;
    copy_ptr<FAType> fa_image;
    copy_ptr<VALUEType> value_image;
    copy_ptr<VECTORType> vector_image;
    std::vector<int> vals;
    int modulate;
};

template <class MASKType, class ADCType, class FAType, class VALUEType, class VECTORType>
inline Processor<MASKType, ADCType, FAType, VALUEType, VECTORType> processor (MASKType* mask_image, ADCType* adc_image, FAType* fa_image, VALUEType* value_image, VECTORType* vector_image, std::vector<int> vals, int modulate) {
  return { mask_image, adc_image, fa_image, value_image, vector_image, vals, modulate };
}

void run ()
{
  auto dt = Header::open (argument[0]).get_image<value_type>();
  auto header = dt.header();
  header.datatype() = DataType::Float32;

  Image<bool>* mask = nullptr;
  auto opt = get_options ("mask");
  if (opt.size()) {
    mask = new Image<bool> (Image<bool>::open (opt[0][0]));
    check_dimensions (dt, *mask, 0, 3);
  }

  Image<value_type>* adc = nullptr;
  opt = get_options ("adc");
  if (opt.size()) {
    header.set_ndim (3);
    adc = new Image<value_type> (Image<value_type>::create (opt[0][0], header));
  }

  Image<value_type>* fa = nullptr;
  opt = get_options ("fa");
  if (opt.size()) {
    header.set_ndim (3);
    fa = new Image<value_type> (Image<value_type>::create (opt[0][0], header));
  }

  std::vector<int> vals = {1};
  opt = get_options ("num");
  if (opt.size()) {
    vals = opt[0][0];
  if (vals.empty())
    throw Exception ("invalid eigenvalue/eigenvector number specifier");
  for (size_t i = 0; i < vals.size(); ++i)
    if (vals[i] < 1 || vals[i] > 3)
      throw Exception ("eigenvalue/eigenvector number is out of bounds");
  }

  int modulate = 1;
  opt = get_options ("modulate");
  if (opt.size())
    modulate = opt[0][0];

  Image<value_type>* value = nullptr;
  opt = get_options ("value");
  if (opt.size()) {
    header.set_ndim (4);
    header.size (3) = vals.size();
    value = new Image<value_type> (Image<value_type>::create (opt[0][0], header));
  }

  Image<value_type>* vector = nullptr;
  opt = get_options ("vector");
  if (opt.size()) {
    header.set_ndim (4);
    header.size (3) = vals.size()*3;
    vector = new Image<value_type> (Image<value_type>::create (opt[0][0], header));
  }

  ThreadedLoop("computing metrics...", dt, 0, 3).run (processor (mask, adc, fa, value, vector, vals, modulate), dt);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: idloptions.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 02:15:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#include    <stdio.h>

#include    "idloptions.hxx"

using namespace rtl;

sal_Bool IdlOptions::initOptions(int ac, char* av[], sal_Bool bCmdFile)
    throw( IllegalArgument )
{
    sal_Bool    ret = sal_True;
    sal_uInt16  i=0;

    if (!bCmdFile)
    {
        bCmdFile = sal_True;

        m_program = av[0];

        if (ac < 2)
        {
            fprintf(stderr, "%s", prepareHelp().getStr());
            ret = sal_False;
        }

        i = 1;
    } else
    {
        i = 0;
    }

    char    *s=NULL;
    for (i; i < ac; i++)
    {
        if (av[i][0] == '-')
        {
            switch (av[i][1])
            {
                case 'O':
                    if (av[i][2] == '\0')
                    {
                        if (i < ac - 1 && av[i+1][0] != '-')
                        {
                            i++;
                            s = av[i];
                        } else
                        {
                            OString tmp("'-O', please check");
                            if (i <= ac - 1)
                            {
                                tmp += " your input '" + OString(av[i+1]) + "'";
                            }

                            throw IllegalArgument(tmp);
                        }
                    } else
                    {
                        s = av[i] + 2;
                    }

                    m_options["-O"] = OString(s);
                    break;
                case 'B':
                    if (av[i][2] == '\0')
                    {
                        if (i < ac - 1 && av[i+1][0] != '-')
                        {
                            i++;
                            s = av[i];
                        } else
                        {
                            OString tmp("'-B', please check");
                            if (i <= ac - 1)
                            {
                                tmp += " your input '" + OString(av[i+1]) + "'";
                            }

                            throw IllegalArgument(tmp);
                        }
                    } else
                    {
                        s = av[i] + 2;
                    }

                    m_options["-B"] = OString(s);
                    break;
                case 'T':
                    if (av[i][2] == '\0')
                    {
                        if (i < ac - 1 && av[i+1][0] != '-')
                        {
                            i++;
                            s = av[i];
                        } else
                        {
                            OString tmp("'-T', please check");
                            if (i <= ac - 1)
                            {
                                tmp += " your input '" + OString(av[i+1]) + "'";
                            }

                            throw IllegalArgument(tmp);
                        }
                    } else
                    {
                        s = av[i] + 2;
                    }

                    if (m_options.count("-T") > 0)
                    {
                        OString tmp(m_options["-T"]);
                        tmp = tmp + ";" + s;
                        m_options["-T"] = tmp;
                    } else
                    {
                        m_options["-T"] = OString(s);
                    }
                    break;
                case 'G':
                    if (av[i][2] == 'c')
                    {
                        if (av[i][3] != '\0')
                        {
                            OString tmp("'-Gc', please check");
                            if (i <= ac - 1)
                            {
                                tmp += " your input '" + OString(av[i]) + "'";
                            }

                            throw IllegalArgument(tmp);
                        }

                        m_options["-Gc"] = OString("");
                        break;
                    } else
                    if (av[i][2] != '\0')
                    {
                        OString tmp("'-G', please check");
                        if (i <= ac - 1)
                        {
                            tmp += " your input '" + OString(av[i]) + "'";
                        }

                        throw IllegalArgument(tmp);
                    }

                    m_options["-G"] = OString("");
                    break;
                default:
                    throw IllegalArgument("the option is unknown" + OString(av[i]));
                    break;
            }
        } else
        {
            if (av[i][0] == '@')
            {
                FILE* cmdFile = fopen(av[i]+1, "r");
                  if( cmdFile == NULL )
                  {
                    fprintf(stderr, "%s", prepareHelp().getStr());
                    ret = sal_False;
                } else
                {
                    int rargc=0;
                    char* rargv[512];
                    char  buffer[512];

                    while ( fscanf(cmdFile, "%s", buffer) != EOF )
                    {
                        rargv[rargc]= strdup(buffer);
                        rargc++;
                    }
                    fclose(cmdFile);

                    ret = initOptions(rargc, rargv, bCmdFile);

                    for (long i=0; i < rargc; i++)
                    {
                        free(rargv[i]);
                    }
                }
            } else
            {
                m_inputFiles.push_back(av[i]);
            }
        }
    }

    return ret;
}

OString IdlOptions::prepareHelp()
{
    OString help("\nusing: ");
    help += m_program + " [-options] file_1 ... file_n\nOptions:\n";
    help += "    -O<path>   = path describes the root directory for the generated output.\n";
    help += "                 The output directory tree is generated under this directory.\n";
    help += "    -T<name>   = name specifies a type or a list of types. The output for this\n";
    help += "      [t1;...]   type is generated. If no '-T' option is specified,\n";
    help += "                 then output for all types is generated.\n";
    help += "                 Example: 'com.sun.star.uno.XInterface' is a valid type.\n";
    help += "    -B<name>   = name specifies the base node. All types are searched under this\n";
    help += "                 node. Default is the root '/' of the registry files.\n";
    help += "    -G         = generate only target files which does not exists.\n";
    help += "    -Gc        = generate only target files which content will be changed.\n";
    help += "IMPORTANT:       You lose enum values and struct, exception inheritance!\n";
    help += "                 Parameter name Object is translated to _Object!\n";
    help += "                 The type type is translated to CORBA::TypeCode!\n";
    help += "                 Sequences are expanded to a typedef name Sequence_..._\"name\"!\n";
    help += prepareVersion();

    return help;
}

OString IdlOptions::prepareVersion()
{
    OString version("\nSun Microsystems (R) ");
    version += m_program + " Version 2.0\n\n";

    return version;
}

<commit_msg>INTEGRATION: CWS pchfix02 (1.2.40); FILE MERGED 2006/09/01 17:19:24 kaib 1.2.40.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: idloptions.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 03:38:41 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_codemaker.hxx"
#include    <stdio.h>

#include    "idloptions.hxx"

using namespace rtl;

sal_Bool IdlOptions::initOptions(int ac, char* av[], sal_Bool bCmdFile)
    throw( IllegalArgument )
{
    sal_Bool    ret = sal_True;
    sal_uInt16  i=0;

    if (!bCmdFile)
    {
        bCmdFile = sal_True;

        m_program = av[0];

        if (ac < 2)
        {
            fprintf(stderr, "%s", prepareHelp().getStr());
            ret = sal_False;
        }

        i = 1;
    } else
    {
        i = 0;
    }

    char    *s=NULL;
    for (i; i < ac; i++)
    {
        if (av[i][0] == '-')
        {
            switch (av[i][1])
            {
                case 'O':
                    if (av[i][2] == '\0')
                    {
                        if (i < ac - 1 && av[i+1][0] != '-')
                        {
                            i++;
                            s = av[i];
                        } else
                        {
                            OString tmp("'-O', please check");
                            if (i <= ac - 1)
                            {
                                tmp += " your input '" + OString(av[i+1]) + "'";
                            }

                            throw IllegalArgument(tmp);
                        }
                    } else
                    {
                        s = av[i] + 2;
                    }

                    m_options["-O"] = OString(s);
                    break;
                case 'B':
                    if (av[i][2] == '\0')
                    {
                        if (i < ac - 1 && av[i+1][0] != '-')
                        {
                            i++;
                            s = av[i];
                        } else
                        {
                            OString tmp("'-B', please check");
                            if (i <= ac - 1)
                            {
                                tmp += " your input '" + OString(av[i+1]) + "'";
                            }

                            throw IllegalArgument(tmp);
                        }
                    } else
                    {
                        s = av[i] + 2;
                    }

                    m_options["-B"] = OString(s);
                    break;
                case 'T':
                    if (av[i][2] == '\0')
                    {
                        if (i < ac - 1 && av[i+1][0] != '-')
                        {
                            i++;
                            s = av[i];
                        } else
                        {
                            OString tmp("'-T', please check");
                            if (i <= ac - 1)
                            {
                                tmp += " your input '" + OString(av[i+1]) + "'";
                            }

                            throw IllegalArgument(tmp);
                        }
                    } else
                    {
                        s = av[i] + 2;
                    }

                    if (m_options.count("-T") > 0)
                    {
                        OString tmp(m_options["-T"]);
                        tmp = tmp + ";" + s;
                        m_options["-T"] = tmp;
                    } else
                    {
                        m_options["-T"] = OString(s);
                    }
                    break;
                case 'G':
                    if (av[i][2] == 'c')
                    {
                        if (av[i][3] != '\0')
                        {
                            OString tmp("'-Gc', please check");
                            if (i <= ac - 1)
                            {
                                tmp += " your input '" + OString(av[i]) + "'";
                            }

                            throw IllegalArgument(tmp);
                        }

                        m_options["-Gc"] = OString("");
                        break;
                    } else
                    if (av[i][2] != '\0')
                    {
                        OString tmp("'-G', please check");
                        if (i <= ac - 1)
                        {
                            tmp += " your input '" + OString(av[i]) + "'";
                        }

                        throw IllegalArgument(tmp);
                    }

                    m_options["-G"] = OString("");
                    break;
                default:
                    throw IllegalArgument("the option is unknown" + OString(av[i]));
                    break;
            }
        } else
        {
            if (av[i][0] == '@')
            {
                FILE* cmdFile = fopen(av[i]+1, "r");
                  if( cmdFile == NULL )
                  {
                    fprintf(stderr, "%s", prepareHelp().getStr());
                    ret = sal_False;
                } else
                {
                    int rargc=0;
                    char* rargv[512];
                    char  buffer[512];

                    while ( fscanf(cmdFile, "%s", buffer) != EOF )
                    {
                        rargv[rargc]= strdup(buffer);
                        rargc++;
                    }
                    fclose(cmdFile);

                    ret = initOptions(rargc, rargv, bCmdFile);

                    for (long i=0; i < rargc; i++)
                    {
                        free(rargv[i]);
                    }
                }
            } else
            {
                m_inputFiles.push_back(av[i]);
            }
        }
    }

    return ret;
}

OString IdlOptions::prepareHelp()
{
    OString help("\nusing: ");
    help += m_program + " [-options] file_1 ... file_n\nOptions:\n";
    help += "    -O<path>   = path describes the root directory for the generated output.\n";
    help += "                 The output directory tree is generated under this directory.\n";
    help += "    -T<name>   = name specifies a type or a list of types. The output for this\n";
    help += "      [t1;...]   type is generated. If no '-T' option is specified,\n";
    help += "                 then output for all types is generated.\n";
    help += "                 Example: 'com.sun.star.uno.XInterface' is a valid type.\n";
    help += "    -B<name>   = name specifies the base node. All types are searched under this\n";
    help += "                 node. Default is the root '/' of the registry files.\n";
    help += "    -G         = generate only target files which does not exists.\n";
    help += "    -Gc        = generate only target files which content will be changed.\n";
    help += "IMPORTANT:       You lose enum values and struct, exception inheritance!\n";
    help += "                 Parameter name Object is translated to _Object!\n";
    help += "                 The type type is translated to CORBA::TypeCode!\n";
    help += "                 Sequences are expanded to a typedef name Sequence_..._\"name\"!\n";
    help += prepareVersion();

    return help;
}

OString IdlOptions::prepareVersion()
{
    OString version("\nSun Microsystems (R) ");
    version += m_program + " Version 2.0\n\n";

    return version;
}

<|endoftext|>


<commit_before>#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif

#include <cmath>
#include <limits>
#include <numeric>
#include <fstream>
#include <iostream>
#include <algorithm>

#include "Tools/Code/Polar/decoder_polar_functions.h"
#include "Tools/Exception/exception.hpp"

#include "Frozenbits_generator_GA.hpp"

using namespace aff3ct;
using namespace aff3ct::tools;

std::vector<bool> init_fb(const int K, const int N)
{
	std::vector<bool> fake_frozen_bits(N);
	std::fill(fake_frozen_bits.begin(),     fake_frozen_bits.begin() + K, 0);
	std::fill(fake_frozen_bits.begin() + K, fake_frozen_bits.end(),       1);
	return fake_frozen_bits;
}

Frozenbits_generator_GA
::Frozenbits_generator_GA(const int K, const int N, const Polar_code& code)
: Frozenbits_generator(K, N),
  code(code),
  z(code.get_codeword_size()),
  fake_frozen_bits(init_fb(K, code.get_codeword_size())),
  decoder_sc(K, code.get_codeword_size(), code, fake_frozen_bits)
{
	recursive_override_frozen_bits(decoder_sc.polar_tree.get_root());

	for (size_t l = 0; l < decoder_sc.lambdas.size(); l++)
	{
		if (Polar_lambdas_bis<int64_t,double>::functions.find(code.get_kernel_matrices()[l]) ==
		    Polar_lambdas_bis<int64_t,double>::functions.end())
			throw runtime_error(__FILE__, __LINE__, __func__, "Unsupported polar kernel.");
		decoder_sc.lambdas[l] =
		    Polar_lambdas_bis<int64_t,double,square_plus_DE,plus_DE>::functions[code.get_kernel_matrices()[l]];
	}
}

void Frozenbits_generator_GA
::evaluate()
{
	this->check_noise();

	for (auto i = 0; i < this->N; i++)
		z[i] = 2.0 / std::pow((double)this->n->get_noise(), 2.0);

	this->decoder_sc._load(z.data());
	this->decoder_sc.recursive_decode(this->decoder_sc.polar_tree.get_root());
	this->recursive_store_DE(this->decoder_sc.polar_tree.get_root(), z.data());

	std::iota(this->best_channels.begin(), this->best_channels.end(), 0);
	std::sort(this->best_channels.begin(), this->best_channels.end(), [this](int i1, int i2) { return z[i1] > z[i2]; });
}

double Frozenbits_generator_GA
::phi(double t)
{
	if (t < phi_pivot)
		return std::exp(0.0564 * t * t - 0.48560 * t);
	else // if(t >= phi_pivot)
		return std::exp(alpha * std::pow(t, gamma) + beta);
}

double Frozenbits_generator_GA
::phi_inv(double t)
{
	if (t > phi_inv_pivot)
		return 4.304964539 * (1 - sqrt(1 + 0.9567131408 * std::log(t)));
	else
		return std::pow(a * std::log(t) + b, c);
}

void Frozenbits_generator_GA
::check_noise()
{
	Frozenbits_generator::check_noise();

	this->n->is_of_type_throw(tools::Noise_type::SIGMA);
}

void Frozenbits_generator_GA
::recursive_override_frozen_bits(const Generic_node<module::Contents_MK_SC<int64_t, double>>* node_curr)
{
	if (!node_curr->is_leaf()) // stop condition
		for (auto c : node_curr->get_children())
			this->recursive_override_frozen_bits(c); // recursive call
	else
		node_curr->get_contents()->is_frozen_bit = true;
}

void Frozenbits_generator_GA
::recursive_store_DE(const Generic_node<module::Contents_MK_SC<int64_t, double>>* node_curr, double *z) const
{
	if (!node_curr->is_leaf()) // stop condition
		for (auto c : node_curr->get_children())
			this->recursive_store_DE(c, z); // recursive call
	else
		z[node_curr->get_lane_id()] = node_curr->get_contents()->l[0];
}

double Frozenbits_generator_GA
::square_plus_DE(const double& zl, const double& zr)
{
	auto z = phi_inv(1.0 - ((1.0 - phi(zl)) * (1.0 - phi(zr))));
	return (z == HUGE_VAL) ? zl + M_LN2 / (alpha * gamma) : z;
	// return z;
}

double Frozenbits_generator_GA
::plus_DE(const double& zl, const double& zr)
{
	return zl + zr;
}<commit_msg>Simplify the GA code.<commit_after>#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif

#include <cmath>
#include <limits>
#include <numeric>
#include <fstream>
#include <iostream>
#include <algorithm>

#include "Tools/Code/Polar/decoder_polar_functions.h"
#include "Tools/Exception/exception.hpp"

#include "Frozenbits_generator_GA.hpp"

using namespace aff3ct;
using namespace aff3ct::tools;

std::vector<bool> init_fb(const int K, const int N)
{
	std::vector<bool> fake_frozen_bits(N);
	std::fill(fake_frozen_bits.begin(),     fake_frozen_bits.begin() + K, 0);
	std::fill(fake_frozen_bits.begin() + K, fake_frozen_bits.end(),       1);
	return fake_frozen_bits;
}

Frozenbits_generator_GA
::Frozenbits_generator_GA(const int K, const int N, const Polar_code& code)
: Frozenbits_generator(K, N),
  code(code),
  z(code.get_codeword_size()),
  fake_frozen_bits(init_fb(K, code.get_codeword_size())),
  decoder_sc(K, code.get_codeword_size(), code, fake_frozen_bits)
{
	recursive_override_frozen_bits(decoder_sc.polar_tree.get_root());

	for (size_t l = 0; l < decoder_sc.lambdas.size(); l++)
	{
		if (Polar_lambdas_bis<int64_t,double>::functions.find(code.get_kernel_matrices()[l]) ==
		    Polar_lambdas_bis<int64_t,double>::functions.end())
			throw runtime_error(__FILE__, __LINE__, __func__, "Unsupported polar kernel.");
		decoder_sc.lambdas[l] =
		    Polar_lambdas_bis<int64_t,double,square_plus_DE,plus_DE>::functions[code.get_kernel_matrices()[l]];
	}
}

void Frozenbits_generator_GA
::evaluate()
{
	this->check_noise();

	std::fill(z.begin(), z.end(), 2.0 / std::pow((double)this->n->get_noise(), 2.0));

	this->decoder_sc._load(z.data());
	this->decoder_sc.recursive_decode(this->decoder_sc.polar_tree.get_root());
	this->recursive_store_DE(this->decoder_sc.polar_tree.get_root(), z.data());

	std::iota(this->best_channels.begin(), this->best_channels.end(), 0);
	std::sort(this->best_channels.begin(), this->best_channels.end(), [this](int i1, int i2) { return z[i1] > z[i2]; });
}

double Frozenbits_generator_GA
::phi(double t)
{
	if (t < phi_pivot)
		return std::exp(0.0564 * t * t - 0.48560 * t);
	else // if(t >= phi_pivot)
		return std::exp(alpha * std::pow(t, gamma) + beta);
}

double Frozenbits_generator_GA
::phi_inv(double t)
{
	if (t > phi_inv_pivot)
		return 4.304964539 * (1 - sqrt(1 + 0.9567131408 * std::log(t)));
	else
		return std::pow(a * std::log(t) + b, c);
}

void Frozenbits_generator_GA
::check_noise()
{
	Frozenbits_generator::check_noise();

	this->n->is_of_type_throw(tools::Noise_type::SIGMA);
}

void Frozenbits_generator_GA
::recursive_override_frozen_bits(const Generic_node<module::Contents_MK_SC<int64_t, double>>* node_curr)
{
	if (!node_curr->is_leaf()) // stop condition
		for (auto c : node_curr->get_children())
			this->recursive_override_frozen_bits(c); // recursive call
	else
		node_curr->get_contents()->is_frozen_bit = true;
}

void Frozenbits_generator_GA
::recursive_store_DE(const Generic_node<module::Contents_MK_SC<int64_t, double>>* node_curr, double *z) const
{
	if (!node_curr->is_leaf()) // stop condition
		for (auto c : node_curr->get_children())
			this->recursive_store_DE(c, z); // recursive call
	else
		z[node_curr->get_lane_id()] = node_curr->get_contents()->l[0];
}

double Frozenbits_generator_GA
::square_plus_DE(const double& zl, const double& zr)
{
	auto z = phi_inv(1.0 - ((1.0 - phi(zl)) * (1.0 - phi(zr))));
	return (z == HUGE_VAL) ? zl + M_LN2 / (alpha * gamma) : z;
	// return z;
}

double Frozenbits_generator_GA
::plus_DE(const double& zl, const double& zr)
{
	return zl + zr;
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     All rights reserved.
 *
 *  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.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong
 *
 */

#pragma once

#include <string>
#include <iostream>
#include <unistd.h>
#include <unordered_map>
#include <fstream>
#include <errno.h>
#include <sstream>

#include "config.hpp"
#include "rdma.hpp"
#include "mem.hpp"
#include "query.hpp"

using namespace std;

#define WK_CLINE 64

// The communication over RDMA-based ring buffer
class RDMA_Adaptor {
private:
    Mem *mem;
    int sid;
    int num_servers;
    int num_threads;

    /// The ring-buffer space contains #threads logical-queues.
    /// Each logical-queue contains #servers physical queues (ring-buffer).
    /// The X physical-queue (ring-buffer) of thread(tid) is written by the responding threads
    /// (proxies and engine with the same "tid") on the X server.
    /// Access mode of physical queue is N writers (from the same server) and 1 reader.

    // track tail of ring buffer for writer
    struct rbf_rmeta_t {
        uint64_t tail;
        pthread_spinlock_t lock;
    } __attribute__ ((aligned (WK_CLINE)));

    // track head of ring buffer for reader
    struct rbf_lmeta_t {
        uint64_t head;
        pthread_spinlock_t lock;
    } __attribute__ ((aligned (WK_CLINE)));

    rbf_rmeta_t *rmetas = NULL;
    rbf_lmeta_t *lmetas = NULL;

    // each thread uses a round-robin strategy to check its physical-queues
    struct scheduler_t {
        uint64_t rr_cnt; // round-robin
    } __attribute__ ((aligned (WK_CLINE)));

    scheduler_t *schedulers;

    // Align given value down to given alignment
    uint64_t inline floor(uint64_t val, uint64_t alignment) {
        ASSERT(alignment != 0);
        return val - val % alignment;
    }

    // Align given value up to given alignment
    uint64_t inline ceil(uint64_t val, uint64_t alignment) {
        ASSERT(alignment != 0);
        if (val % alignment == 0)
            return val;
        return val - val % alignment + alignment;
    }

    // Check if there is data from threads in dst_sid to tid
    bool check(int tid, int dst_sid) {
        rbf_lmeta_t *lmeta = &lmetas[tid * num_servers + dst_sid];
        char *rbf = mem->ring(tid, dst_sid); // ring buffer for tid to recv data from threads in dst_sid
        uint64_t rbf_sz = mem->ring_size();
        volatile uint64_t data_sz = *(volatile uint64_t *)(rbf + lmeta->head % rbf_sz);  // header

        return (data_sz != 0);
    }

    // Fetch data from threads in dst_sid to tid
    std::string fetch(int tid, int dst_sid) {
        // step 1: get lmeta of dst rbf
        rbf_lmeta_t *lmeta = &lmetas[tid * num_servers + dst_sid];
        // step 2: calculate mem location and data size
        char * rbf = mem->ring(tid, dst_sid);
        uint64_t rbf_sz = mem->ring_size();
        // struct of data: [size | data | size]
        volatile uint64_t data_sz = *(volatile uint64_t *)(rbf + lmeta->head % rbf_sz);  // header
        *(uint64_t *)(rbf + lmeta->head % rbf_sz) = 0;  // clean header

        uint64_t to_footer = sizeof(uint64_t) + ceil(data_sz, sizeof(uint64_t));
        volatile uint64_t * footer = (volatile uint64_t *)(rbf + (lmeta->head + to_footer) % rbf_sz); // footer
        // step 3: spin-wait rdma-write done
        while (*footer != data_sz) {
            _mm_pause();
            /* If RDMA-WRITE is done, footer == header == size
             * Otherwise, footer == 0
             */
            ASSERT(*footer == 0 || *footer == data_sz);
        }
        *footer = 0;  // clean footer

        // step 4: actually read data
        std::string result;
        result.reserve(data_sz);
        uint64_t start = (lmeta->head + sizeof(uint64_t)) % rbf_sz; // start of data
        uint64_t end = (lmeta->head + sizeof(uint64_t) + data_sz) % rbf_sz;  // end of data
        if (start < end) {
            result.append(rbf + start, data_sz);
            memset(rbf + start, 0, ceil(data_sz, sizeof(uint64_t)));  // clean data
        } else { // overwrite from the start
            result.append(rbf + start, data_sz - end);
            result.append(rbf, end);
            memset(rbf + start, 0, data_sz - end);                    // clean data
            memset(rbf, 0, ceil(end, sizeof(uint64_t)));              // clean data
        }
        // step 5: move forward rbf head
        lmeta->head += 2 * sizeof(uint64_t) + ceil(data_sz, sizeof(uint64_t));

        // step 6: update heads of ring buffer to writer to help it detect overflow
        char *head = mem->local_ring_head(tid, dst_sid);
        const uint64_t threshold = rbf_sz / 8;
        if (lmeta->head - * (uint64_t *)head > threshold) {
            *(uint64_t *)head = lmeta->head;
            if (sid != dst_sid) {   // update to remote server
                RDMA &rdma = RDMA::get_rdma();
                uint64_t remote_head = mem->remote_ring_head_offset(tid, sid);
                rdma.dev->RdmaWrite(tid, dst_sid, head, mem->remote_ring_head_size(), remote_head);
            } else {
                *(uint64_t *)mem->remote_ring_head(tid, sid) = lmeta->head;
            }
        }
        return result;
    } // end of fetch

    /* Check whether overflow occurs if given msg is sent
     * @tid tid of writer
     * @dst_sid, @dst_tid sid and tid of reader
     * @msg_sz size of msg to send
    */
    inline bool rbf_full(int tid, int dst_sid, int dst_tid, uint64_t msg_sz) {
        uint64_t rbf_sz = mem->ring_size();
        uint64_t tail = rmetas[dst_sid * num_threads + dst_tid].tail;
        uint64_t head = *(uint64_t *)mem->remote_ring_head(dst_tid, dst_sid);

        return (rbf_sz < (tail - head + msg_sz));
    }

public:
    bool init = false;

    RDMA_Adaptor(int sid, Mem *mem, int num_servers, int num_threads)
        : sid(sid), mem(mem), num_servers(num_servers), num_threads(num_threads) {
        // no RDMA device
        if (!RDMA::get_rdma().has_rdma()) return;

        // init the metadata of remote and local ring-buffers
        int nrbfs = num_servers * num_threads;

        rmetas = (rbf_rmeta_t *)malloc(sizeof(rbf_rmeta_t) * nrbfs);
        memset(rmetas, 0, sizeof(rbf_rmeta_t) * nrbfs);
        for (int i = 0; i < nrbfs; i++) {
            rmetas[i].tail = 0;
            pthread_spin_init(&rmetas[i].lock, 0);
        }

        lmetas = (rbf_lmeta_t *)malloc(sizeof(rbf_lmeta_t) * nrbfs);
        memset(lmetas, 0, sizeof(rbf_lmeta_t) * nrbfs);
        for (int i = 0; i < nrbfs; i++) {
            lmetas[i].head = 0;
            pthread_spin_init(&lmetas[i].lock, 0);
        }

        schedulers = (scheduler_t *)malloc(sizeof(scheduler_t) * num_threads);
        memset(schedulers, 0, sizeof(scheduler_t) * num_threads);

        init = true;
    }

    ~RDMA_Adaptor() { }  //TODO

    // Send given string to (dst_sid, dst_tid) by thread(tid)
    // Return false if failed . Otherwise, return true.
    bool send(int tid, int dst_sid, int dst_tid, const string &str) {
        ASSERT(init);

        rbf_rmeta_t *rmeta = &rmetas[dst_sid * num_threads + dst_tid];
        uint64_t rbf_sz = mem->ring_size();

        const char *data = str.c_str();
        uint64_t data_sz = str.length();

        // struct of data: [size | data | size] (use size of data as header and footer)
        uint64_t msg_sz = sizeof(uint64_t) + ceil(data_sz, sizeof(uint64_t)) + sizeof(uint64_t);

        ASSERT(msg_sz < rbf_sz);

        pthread_spin_lock(&rmeta->lock);
        if (rbf_full(tid, dst_sid, dst_tid, msg_sz)) { // detect overflow
            pthread_spin_unlock(&rmeta->lock);
            return false;
        }

        if (sid == dst_sid) { // local physical-queue
            uint64_t off = rmeta->tail;
            rmeta->tail += msg_sz;
            pthread_spin_unlock(&rmeta->lock);

            // write msg to the local physical-queue
            char *ptr = mem->ring(dst_tid, sid);

            *((uint64_t *)(ptr + off % rbf_sz)) = data_sz;       // header
            off += sizeof(uint64_t);

            if (off / rbf_sz == (off + data_sz - 1) / rbf_sz ) {    // data
                memcpy(ptr + (off % rbf_sz), data, data_sz);
            } else {
                uint64_t _sz = rbf_sz - (off % rbf_sz);
                memcpy(ptr + (off % rbf_sz), data, _sz);
                memcpy(ptr, data + _sz, data_sz - _sz);
            }
            off += ceil(data_sz, sizeof(uint64_t));

            *((uint64_t *)(ptr + off % rbf_sz)) = data_sz;       // footer
        } else { // remote physical-queue
            uint64_t off = rmeta->tail;
            rmeta->tail += msg_sz;
            pthread_spin_unlock(&rmeta->lock);

            // prepare RDMA buffer for RDMA-WRITE
            char *rdma_buf = mem->buffer(tid);
            uint64_t buf_sz = mem->buffer_size();
            ASSERT(msg_sz < buf_sz); // enough space to buffer the msg

            *((uint64_t *)rdma_buf) = data_sz;  // header
            rdma_buf += sizeof(uint64_t);

            memcpy(rdma_buf, data, data_sz);    // data
            rdma_buf += ceil(data_sz, sizeof(uint64_t));
            *((uint64_t*)rdma_buf) = data_sz;   // footer

            // write msg to the remote physical-queue
            RDMA &rdma = RDMA::get_rdma();
            uint64_t rdma_off = mem->ring_offset(dst_tid, sid);
            if (off / rbf_sz == (off + msg_sz - 1) / rbf_sz ) {
                rdma.dev->RdmaWrite(tid, dst_sid, mem->buffer(tid), msg_sz, rdma_off + (off % rbf_sz));
            } else {
                uint64_t _sz = rbf_sz - (off % rbf_sz);
                rdma.dev->RdmaWrite(tid, dst_sid, mem->buffer(tid), _sz, rdma_off + (off % rbf_sz));
                rdma.dev->RdmaWrite(tid, dst_sid, mem->buffer(tid) + _sz, msg_sz - _sz, rdma_off);
            }
        }

        return true;
    } // end of send

    std::string recv(int tid) {
        ASSERT(init);

        while (true) {
            // each thread has a logical-queue (#servers physical-queues)
            int dst_sid = (schedulers[tid].rr_cnt++) % num_servers; // round-robin
            if (check(tid, dst_sid))
                return fetch(tid, dst_sid);
        }
    }

    // Try to recv data of given thread
    bool tryrecv(int tid, std::string &str) {
        ASSERT(init);

        // check all physical-queues of tid once
        for (int dst_sid = 0; dst_sid < num_servers; dst_sid++) {
            if (check(tid, dst_sid)) {
                str = fetch(tid, dst_sid);
                return true;
            }
        }
        return false;
    }
};
<commit_msg>refine rdma_adaptor<commit_after>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     All rights reserved.
 *
 *  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.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong
 *
 */

#pragma once

#include <string>
#include <iostream>
#include <unistd.h>
#include <unordered_map>
#include <fstream>
#include <errno.h>
#include <sstream>

#include "config.hpp"
#include "rdma.hpp"

using namespace std;

#define WK_CLINE 64

// The communication over RDMA-based ring buffer
class RDMA_Adaptor {
private:
    Mem *mem;
    int sid;
    int num_servers;
    int num_threads;

    /// The ring-buffer space contains #threads logical-queues.
    /// Each logical-queue contains #servers physical queues (ring-buffer).
    /// The X physical-queue (ring-buffer) of thread(tid) is written by the responding threads
    /// (proxies and engine with the same "tid") on the X server.
    /// Access mode of physical queue is N writers (from the same server) and 1 reader.

    // track tail of ring buffer for writer
    struct rbf_rmeta_t {
        uint64_t tail;
        pthread_spinlock_t lock;
    } __attribute__ ((aligned (WK_CLINE)));

    // track head of ring buffer for reader
    struct rbf_lmeta_t {
        uint64_t head;
        pthread_spinlock_t lock;
    } __attribute__ ((aligned (WK_CLINE)));

    rbf_rmeta_t *rmetas = NULL;
    rbf_lmeta_t *lmetas = NULL;

    // each thread uses a round-robin strategy to check its physical-queues
    struct scheduler_t {
        uint64_t rr_cnt; // round-robin
    } __attribute__ ((aligned (WK_CLINE)));

    scheduler_t *schedulers;

    // Align given value down to given alignment
    uint64_t inline floor(uint64_t val, uint64_t alignment) {
        ASSERT(alignment != 0);
        return val - val % alignment;
    }

    // Align given value up to given alignment
    uint64_t inline ceil(uint64_t val, uint64_t alignment) {
        ASSERT(alignment != 0);
        if (val % alignment == 0)
            return val;
        return val - val % alignment + alignment;
    }

    // Check if there is data from threads in dst_sid to tid
    bool check(int tid, int dst_sid) {
        rbf_lmeta_t *lmeta = &lmetas[tid * num_servers + dst_sid];
        char *rbf = mem->ring(tid, dst_sid); // ring buffer for tid to recv data from threads in dst_sid
        uint64_t rbf_sz = mem->ring_size();
        volatile uint64_t data_sz = *(volatile uint64_t *)(rbf + lmeta->head % rbf_sz);  // header

        return (data_sz != 0);
    }

    // Fetch data from threads in dst_sid to tid
    std::string fetch(int tid, int dst_sid) {
        // step 1: get lmeta of dst rbf
        rbf_lmeta_t *lmeta = &lmetas[tid * num_servers + dst_sid];
        // step 2: calculate mem location and data size
        char * rbf = mem->ring(tid, dst_sid);
        uint64_t rbf_sz = mem->ring_size();
        // struct of data: [size | data | size]
        volatile uint64_t data_sz = *(volatile uint64_t *)(rbf + lmeta->head % rbf_sz);  // header
        *(uint64_t *)(rbf + lmeta->head % rbf_sz) = 0;  // clean header

        uint64_t to_footer = sizeof(uint64_t) + ceil(data_sz, sizeof(uint64_t));
        volatile uint64_t * footer = (volatile uint64_t *)(rbf + (lmeta->head + to_footer) % rbf_sz); // footer
        // step 3: spin-wait rdma-write done
        while (*footer != data_sz) {
            _mm_pause();
            /* If RDMA-WRITE is done, footer == header == size
             * Otherwise, footer == 0
             */
            ASSERT(*footer == 0 || *footer == data_sz);
        }
        *footer = 0;  // clean footer

        // step 4: actually read data
        std::string result;
        result.reserve(data_sz);
        uint64_t start = (lmeta->head + sizeof(uint64_t)) % rbf_sz; // start of data
        uint64_t end = (lmeta->head + sizeof(uint64_t) + data_sz) % rbf_sz;  // end of data
        if (start < end) {
            result.append(rbf + start, data_sz);
            memset(rbf + start, 0, ceil(data_sz, sizeof(uint64_t)));  // clean data
        } else { // overwrite from the start
            result.append(rbf + start, data_sz - end);
            result.append(rbf, end);
            memset(rbf + start, 0, data_sz - end);                    // clean data
            memset(rbf, 0, ceil(end, sizeof(uint64_t)));              // clean data
        }
        // step 5: move forward rbf head
        lmeta->head += 2 * sizeof(uint64_t) + ceil(data_sz, sizeof(uint64_t));

        // step 6: update heads of ring buffer to writer to help it detect overflow
        char *head = mem->local_ring_head(tid, dst_sid);
        const uint64_t threshold = rbf_sz / 8;
        if (lmeta->head - * (uint64_t *)head > threshold) {
            *(uint64_t *)head = lmeta->head;
            if (sid != dst_sid) {  // update to remote server
                RDMA &rdma = RDMA::get_rdma();
                uint64_t remote_head = mem->remote_ring_head_offset(tid, sid);
                rdma.dev->RdmaWrite(tid, dst_sid, head, mem->remote_ring_head_size(), remote_head);
            } else {
                *(uint64_t *)mem->remote_ring_head(tid, sid) = lmeta->head;
            }
        }
        return result;
    } // end of fetch

    /* Check whether overflow occurs if given msg is sent
     * @tid tid of writer
     * @dst_sid, @dst_tid sid and tid of reader
     * @msg_sz size of msg to send
    */
    inline bool rbf_full(int tid, int dst_sid, int dst_tid, uint64_t msg_sz) {
        uint64_t rbf_sz = mem->ring_size();
        uint64_t tail = rmetas[dst_sid * num_threads + dst_tid].tail;
        uint64_t head = *(uint64_t *)mem->remote_ring_head(dst_tid, dst_sid);

        return (rbf_sz < (tail - head + msg_sz));
    }

public:
    bool init = false;

    RDMA_Adaptor(int sid, Mem *mem, int num_servers, int num_threads)
        : sid(sid), mem(mem), num_servers(num_servers), num_threads(num_threads) {
        // no RDMA device
        if (!RDMA::get_rdma().has_rdma()) return;

        // init the metadata of remote and local ring-buffers
        int nrbfs = num_servers * num_threads;

        rmetas = (rbf_rmeta_t *)malloc(sizeof(rbf_rmeta_t) * nrbfs);
        memset(rmetas, 0, sizeof(rbf_rmeta_t) * nrbfs);
        for (int i = 0; i < nrbfs; i++) {
            rmetas[i].tail = 0;
            pthread_spin_init(&rmetas[i].lock, 0);
        }

        lmetas = (rbf_lmeta_t *)malloc(sizeof(rbf_lmeta_t) * nrbfs);
        memset(lmetas, 0, sizeof(rbf_lmeta_t) * nrbfs);
        for (int i = 0; i < nrbfs; i++) {
            lmetas[i].head = 0;
            pthread_spin_init(&lmetas[i].lock, 0);
        }

        schedulers = (scheduler_t *)malloc(sizeof(scheduler_t) * num_threads);
        memset(schedulers, 0, sizeof(scheduler_t) * num_threads);

        init = true;
    }

    ~RDMA_Adaptor() { }  //TODO

    // Send given string to (dst_sid, dst_tid) by thread(tid)
    // Return false if failed . Otherwise, return true.
    bool send(int tid, int dst_sid, int dst_tid, const string &str) {
        ASSERT(init);

        rbf_rmeta_t *rmeta = &rmetas[dst_sid * num_threads + dst_tid];
        uint64_t rbf_sz = mem->ring_size();

        const char *data = str.c_str();
        uint64_t data_sz = str.length();

        // struct of data: [size | data | size] (use size of data as header and footer)
        uint64_t msg_sz = sizeof(uint64_t) + ceil(data_sz, sizeof(uint64_t)) + sizeof(uint64_t);

        ASSERT(msg_sz < rbf_sz);

        pthread_spin_lock(&rmeta->lock);
        if (rbf_full(tid, dst_sid, dst_tid, msg_sz)) { // detect overflow
            pthread_spin_unlock(&rmeta->lock);
            return false;
        }

        if (sid == dst_sid) { // local physical-queue
            uint64_t off = rmeta->tail;
            rmeta->tail += msg_sz;
            pthread_spin_unlock(&rmeta->lock);

            // write msg to the local physical-queue
            char *ptr = mem->ring(dst_tid, sid);

            *((uint64_t *)(ptr + off % rbf_sz)) = data_sz;       // header
            off += sizeof(uint64_t);

            if (off / rbf_sz == (off + data_sz - 1) / rbf_sz ) { // data
                memcpy(ptr + (off % rbf_sz), data, data_sz);
            } else {
                uint64_t _sz = rbf_sz - (off % rbf_sz);
                memcpy(ptr + (off % rbf_sz), data, _sz);
                memcpy(ptr, data + _sz, data_sz - _sz);
            }
            off += ceil(data_sz, sizeof(uint64_t));

            *((uint64_t *)(ptr + off % rbf_sz)) = data_sz;       // footer
        } else { // remote physical-queue
            uint64_t off = rmeta->tail;
            rmeta->tail += msg_sz;
            pthread_spin_unlock(&rmeta->lock);

            // prepare RDMA buffer for RDMA-WRITE
            char *rdma_buf = mem->buffer(tid);
            uint64_t buf_sz = mem->buffer_size();
            ASSERT(msg_sz < buf_sz); // enough space to buffer the msg

            *((uint64_t *)rdma_buf) = data_sz;  // header
            rdma_buf += sizeof(uint64_t);

            memcpy(rdma_buf, data, data_sz);    // data
            rdma_buf += ceil(data_sz, sizeof(uint64_t));
            *((uint64_t*)rdma_buf) = data_sz;   // footer

            // write msg to the remote physical-queue
            RDMA &rdma = RDMA::get_rdma();
            uint64_t rdma_off = mem->ring_offset(dst_tid, sid);
            if (off / rbf_sz == (off + msg_sz - 1) / rbf_sz ) {
                rdma.dev->RdmaWrite(tid, dst_sid, mem->buffer(tid), msg_sz, rdma_off + (off % rbf_sz));
            } else {
                uint64_t _sz = rbf_sz - (off % rbf_sz);
                rdma.dev->RdmaWrite(tid, dst_sid, mem->buffer(tid), _sz, rdma_off + (off % rbf_sz));
                rdma.dev->RdmaWrite(tid, dst_sid, mem->buffer(tid) + _sz, msg_sz - _sz, rdma_off);
            }
        }

        return true;
    } // end of send

    std::string recv(int tid) {
        ASSERT(init);

        while (true) {
            // each thread has a logical-queue (#servers physical-queues)
            int dst_sid = (schedulers[tid].rr_cnt++) % num_servers; // round-robin
            if (check(tid, dst_sid))
                return fetch(tid, dst_sid);
        }
    }

    // Try to recv data of given thread
    bool tryrecv(int tid, std::string &str) {
        ASSERT(init);

        // check all physical-queues of tid once
        for (int dst_sid = 0; dst_sid < num_servers; dst_sid++) {
            if (check(tid, dst_sid)) {
                str = fetch(tid, dst_sid);
                return true;
            }
        }
        return false;
    }
};
<|endoftext|>