<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Nathan Osman
 *
 * 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 <QMapIterator>
#include <QMutableMapIterator>
#include <QNetworkInterface>

#include "socketlistener.h"

SocketListener::SocketListener()
{
    connect(&monitor, &InterfaceMonitor::interfaceAdded, this, &SocketListener::addInterface);
    connect(&monitor, &InterfaceMonitor::interfaceRemoved, this, &SocketListener::removeInterface);
    connect(&timer, &QTimer::timeout, this, &SocketListener::sendPing);
    connect(Settings::instance(), &Settings::settingChanged, this, &SocketListener::settingChanged);

    reload();
}

SocketListener::~SocketListener()
{
    QMapIterator<QString, QUdpSocket *> i(sockets);

    while(i.hasNext()) {
        shutdown(i.next().value(), true);
    }
}

void SocketListener::start()
{
    monitor.start();
    timer.start();
}

void SocketListener::addInterface(const QString &name)
{
    QUdpSocket * socket = new QUdpSocket;

    connect(socket, &QUdpSocket::readyRead, this, &SocketListener::processDatagrams);

    if(initialize(socket, name)) {
        sockets.insert(name, socket);
        return;
    }

    socket->deleteLater();
}

void SocketListener::removeInterface(const QString &name)
{
    shutdown(sockets.take(name), true);
}

void SocketListener::sendPing()
{
    QMapIterator<QString, QUdpSocket *> i(sockets);

    while(i.hasNext()) {
        i.next().value()->writeDatagram(Device::current(), multicastAddress, multicastPort);
    }
}

void SocketListener::processDatagrams()
{
    QUdpSocket * socket = qobject_cast<QUdpSocket *>(sender());

    while(socket->hasPendingDatagrams()) {
        QByteArray data;
        data.resize(socket->pendingDatagramSize());
        socket->readDatagram(data.data(), data.size());

        Device device;
        if(Device::deserialize(data, device)) {
            emit pingReceived(device);
        }
    }
}

void SocketListener::settingChanged(Settings::Key key)
{
    if(key == Settings::PingInterval || key == Settings::MulticastAddress ||
            key == Settings::MulticastPort) {
        {
            QMapIterator<QString, QUdpSocket *> i(sockets);

            while(i.hasNext()) {
                shutdown(i.next().value(), false);
            }
        }

        timer.stop();
        reload();
        timer.start();

        {
            QMutableMapIterator<QString, QUdpSocket *> i(sockets);

            while(i.hasNext()) {
                i.next();
                if(!initialize(i.value(), i.key())) {
                    shutdown(i.value(), true);
                    i.remove();
                }
            }
        }
    }
}

void SocketListener::reload()
{
    timer.setInterval(Settings::get<int>(Settings::PingInterval));

    multicastAddress = QHostAddress(Settings::get<QString>(Settings::MulticastAddress));
    multicastPort = Settings::get<quint16>(Settings::MulticastPort);
}

bool SocketListener::initialize(QUdpSocket *socket, const QString &name)
{
    QNetworkInterface interface = QNetworkInterface::interfaceFromName(name);

    socket->setMulticastInterface(interface);

    return socket->bind(QHostAddress::AnyIPv6, multicastPort, QUdpSocket::ShareAddress) &&
            socket->joinMulticastGroup(multicastAddress, interface);
}

void SocketListener::shutdown(QUdpSocket *socket, bool destroy)
{
    socket->leaveMulticastGroup(multicastAddress, socket->multicastInterface());
    socket->close();

    if(destroy) {
        socket->deleteLater();
    }
}
<commit_msg>Fixed call to setMulticastInterface and added some debug statements.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Nathan Osman
 *
 * 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 <QDebug>
#include <QMapIterator>
#include <QMutableMapIterator>
#include <QNetworkInterface>

#include "socketlistener.h"

SocketListener::SocketListener()
{
    connect(&monitor, &InterfaceMonitor::interfaceAdded, this, &SocketListener::addInterface);
    connect(&monitor, &InterfaceMonitor::interfaceRemoved, this, &SocketListener::removeInterface);
    connect(&timer, &QTimer::timeout, this, &SocketListener::sendPing);
    connect(Settings::instance(), &Settings::settingChanged, this, &SocketListener::settingChanged);

    reload();
}

SocketListener::~SocketListener()
{
    QMapIterator<QString, QUdpSocket *> i(sockets);

    while(i.hasNext()) {
        shutdown(i.next().value(), true);
    }
}

void SocketListener::start()
{
    monitor.start();
    timer.start();
}

void SocketListener::addInterface(const QString &name)
{
    QUdpSocket * socket = new QUdpSocket;

    connect(socket, &QUdpSocket::readyRead, this, &SocketListener::processDatagrams);

    if(initialize(socket, name)) {
        qDebug() << "Initialized new interface" << name;
        sockets.insert(name, socket);
        return;
    }

    socket->deleteLater();
}

void SocketListener::removeInterface(const QString &name)
{
    qDebug() << "Removing interface" << name;
    shutdown(sockets.take(name), true);
}

void SocketListener::sendPing()
{
    QMapIterator<QString, QUdpSocket *> i(sockets);

    while(i.hasNext()) {
        i.next().value()->writeDatagram(Device::current(), multicastAddress, multicastPort);
    }
}

void SocketListener::processDatagrams()
{
    QUdpSocket * socket = qobject_cast<QUdpSocket *>(sender());

    while(socket->hasPendingDatagrams()) {
        QByteArray data;
        data.resize(socket->pendingDatagramSize());
        socket->readDatagram(data.data(), data.size());

        Device device;
        if(Device::deserialize(data, device)) {
            emit pingReceived(device);
        }
    }
}

void SocketListener::settingChanged(Settings::Key key)
{
    if(key == Settings::PingInterval || key == Settings::MulticastAddress ||
            key == Settings::MulticastPort) {
        {
            QMapIterator<QString, QUdpSocket *> i(sockets);

            while(i.hasNext()) {
                shutdown(i.next().value(), false);
            }
        }

        timer.stop();
        reload();
        timer.start();

        {
            QMutableMapIterator<QString, QUdpSocket *> i(sockets);

            while(i.hasNext()) {
                i.next();
                if(!initialize(i.value(), i.key())) {
                    shutdown(i.value(), true);
                    i.remove();
                }
            }
        }
    }
}

void SocketListener::reload()
{
    timer.setInterval(Settings::get<int>(Settings::PingInterval));

    multicastAddress = QHostAddress(Settings::get<QString>(Settings::MulticastAddress));
    multicastPort = Settings::get<quint16>(Settings::MulticastPort);
}

bool SocketListener::initialize(QUdpSocket *socket, const QString &name)
{
    QNetworkInterface interface = QNetworkInterface::interfaceFromName(name);

    if(!socket->bind(QHostAddress::AnyIPv6, multicastPort, QUdpSocket::ShareAddress)) {
        qDebug() << "Unable to bind" << name;
        return false;
    }

    socket->setMulticastInterface(interface);

    if(!socket->joinMulticastGroup(multicastAddress, interface)) {
        qDebug() << "Unable to join" << multicastAddress.toString() << "on" << name;
        return false;
    }

    return true;
}

void SocketListener::shutdown(QUdpSocket *socket, bool destroy)
{
    socket->leaveMulticastGroup(multicastAddress, socket->multicastInterface());
    socket->close();

    if(destroy) {
        socket->deleteLater();
    }
}
<|endoftext|>


<commit_before>#include "route_segment.h"

bool RouteNode::meets_constraints(std::set<u64> &visited){
	if (!this->memo_constraints.is_initialized()){
		if (this->constraints->require_large_pad && this->station->max_landing_pad_size < 1)
			this->memo_constraints = false;
		else if (this->constraints->avoid_loops && visited.find(this->station->id) != visited.end())
			this->memo_constraints = false;
		else if (!this->previous_segment)
			this->memo_constraints = true;
		else{
			visited.insert(this->station->id);
			this->memo_constraints = this->previous_segment->meets_constraints(visited);
		}
	}
	return this->memo_constraints.value();
}

double RouteNode::get_efficiency_fitness(){
	if (!this->memo_efficiency_fitness.is_initialized()){
		if (this->constraints->require_large_pad && this->station->max_landing_pad_size < 1)
			this->memo_efficiency_fitness = 0;
		else{
			std::set<u64> visited;
			if (!this->meets_constraints(visited))
				this->memo_efficiency_fitness = 0;
			else
				this->memo_efficiency_fitness = this->get_efficiency();
		}
	}
	return this->memo_efficiency_fitness.value();
}

u64 RouteNode::get_profit_fitness() {
	if (!this->memo_profit_fitness.is_initialized()){
		if (this->constraints->require_large_pad && this->station->max_landing_pad_size < 1)
			this->memo_profit_fitness = 0;
		else{
			std::set<u64> visited;
			visited.insert(this->station->id);
			if (!this->meets_constraints(visited))
				this->memo_profit_fitness = 0;
			else
				this->memo_profit_fitness = this->get_profit();
		}
	}
	return this->memo_profit_fitness.value();
}

double RouteNode::ls_to_cost(double ls){
	return ls > 0 ? sqrt(ls) * 1.8973665961010275991993361266596 : 0;
}

double RouteNode::get_cost(bool ignore_src, bool ignore_dst) const{
	if (!this->previous_segment)
		return 0;
	double ret = this->approximate_distance / 7.5 * 30;
	double ls = 0;
	auto station_src = previous_segment->station;
	if (station_src->system->id == this->station->system->id){
		if (!station_src->distance_to_star.is_initialized() && !this->station->distance_to_star.is_initialized())
			ls = 2500;
		else{
			ls = station_src->distance_to_star.value_or(5000) - this->station->distance_to_star.value_or(5000);
			if (ls < 0)
				ls = -ls;
		}
	}else{
		if (!ignore_src)
			ls += station_src->distance_to_star.value_or(5000);
		if (!ignore_dst)
			ls += this->station->distance_to_star.value_or(5000);
	}
	ret += this->ls_to_cost(ls);
	return ret;
}

unsigned RouteNode::get_max_quantity(){
	if (!this->previous_segment)
		throw std::exception("Incorrect implementation");
	if (!this->memo_quantity.is_initialized()){
		auto sell_price = this->previous_segment->station->find_sell_price(this->commodity);
		auto ret = std::min(unsigned(this-> available_funds / sell_price), this->constraints->max_capacity);
		this->memo_expenditure = ret * sell_price;
		this->memo_quantity = ret;
	}
	return this->memo_quantity.value();
}

void RouteNode::get_funds(){
	assert(this->previous_segment);
	this->available_funds = this->previous_segment->available_funds + (u64)this->previous_segment->get_segment_profit();
}

u64 RouteNode::get_segment_profit(){
	if (!this->previous_segment || !this->commodity)
		return 0;
	return this->get_max_quantity() * this->profit_per_unit;
}

RouteNodeInterop *RouteNode::to_interop(){
	auto ret = new RouteNodeInterop;
	memset(ret, 0, sizeof(*ret));
	ret->station_id = this->station->id;
	ret->system_id = this->station->system->id;
	if (this->previous_segment){
		ret->previous = this->previous_segment->to_interop();
		if (this->commodity){
			ret->commodity_id = this->commodity->id;
			ret->quantity = this->get_max_quantity();
			ret->expenditure = this->get_segment_expenditure();
		}else
			ret->commodity_id = std::numeric_limits<decltype(ret->commodity_id)>::max();
		ret->profit_per_unit = this->profit_per_unit;
		ret->efficiency = this->get_efficiency();
		ret->accumulated_profit = this->get_profit();
		ret->cost = this->get_cost();
	}
	return ret;
}
<commit_msg>Fixed bug again in duplicate code.<commit_after>#include "route_segment.h"

bool RouteNode::meets_constraints(std::set<u64> &visited){
	if (!this->memo_constraints.is_initialized()){
		if (this->constraints->require_large_pad && this->station->max_landing_pad_size < 1)
			this->memo_constraints = false;
		else if (this->constraints->avoid_loops && visited.find(this->station->id) != visited.end())
			this->memo_constraints = false;
		else if (!this->previous_segment)
			this->memo_constraints = true;
		else{
			visited.insert(this->station->id);
			this->memo_constraints = this->previous_segment->meets_constraints(visited);
		}
	}
	return this->memo_constraints.value();
}

double RouteNode::get_efficiency_fitness(){
	if (!this->memo_efficiency_fitness.is_initialized()){
		if (this->constraints->require_large_pad && this->station->max_landing_pad_size < 1)
			this->memo_efficiency_fitness = 0;
		else{
			std::set<u64> visited;
			if (!this->meets_constraints(visited))
				this->memo_efficiency_fitness = 0;
			else
				this->memo_efficiency_fitness = this->get_efficiency();
		}
	}
	return this->memo_efficiency_fitness.value();
}

u64 RouteNode::get_profit_fitness() {
	if (!this->memo_profit_fitness.is_initialized()){
		if (this->constraints->require_large_pad && this->station->max_landing_pad_size < 1)
			this->memo_profit_fitness = 0;
		else{
			std::set<u64> visited;
			if (!this->meets_constraints(visited))
				this->memo_profit_fitness = 0;
			else
				this->memo_profit_fitness = this->get_profit();
		}
	}
	return this->memo_profit_fitness.value();
}

double RouteNode::ls_to_cost(double ls){
	return ls > 0 ? sqrt(ls) * 1.8973665961010275991993361266596 : 0;
}

double RouteNode::get_cost(bool ignore_src, bool ignore_dst) const{
	if (!this->previous_segment)
		return 0;
	double ret = this->approximate_distance / 7.5 * 30;
	double ls = 0;
	auto station_src = previous_segment->station;
	if (station_src->system->id == this->station->system->id){
		if (!station_src->distance_to_star.is_initialized() && !this->station->distance_to_star.is_initialized())
			ls = 2500;
		else{
			ls = station_src->distance_to_star.value_or(5000) - this->station->distance_to_star.value_or(5000);
			if (ls < 0)
				ls = -ls;
		}
	}else{
		if (!ignore_src)
			ls += station_src->distance_to_star.value_or(5000);
		if (!ignore_dst)
			ls += this->station->distance_to_star.value_or(5000);
	}
	ret += this->ls_to_cost(ls);
	return ret;
}

unsigned RouteNode::get_max_quantity(){
	if (!this->previous_segment)
		throw std::exception("Incorrect implementation");
	if (!this->memo_quantity.is_initialized()){
		auto sell_price = this->previous_segment->station->find_sell_price(this->commodity);
		auto ret = std::min(unsigned(this-> available_funds / sell_price), this->constraints->max_capacity);
		this->memo_expenditure = ret * sell_price;
		this->memo_quantity = ret;
	}
	return this->memo_quantity.value();
}

void RouteNode::get_funds(){
	assert(this->previous_segment);
	this->available_funds = this->previous_segment->available_funds + (u64)this->previous_segment->get_segment_profit();
}

u64 RouteNode::get_segment_profit(){
	if (!this->previous_segment || !this->commodity)
		return 0;
	return this->get_max_quantity() * this->profit_per_unit;
}

RouteNodeInterop *RouteNode::to_interop(){
	auto ret = new RouteNodeInterop;
	memset(ret, 0, sizeof(*ret));
	ret->station_id = this->station->id;
	ret->system_id = this->station->system->id;
	if (this->previous_segment){
		ret->previous = this->previous_segment->to_interop();
		if (this->commodity){
			ret->commodity_id = this->commodity->id;
			ret->quantity = this->get_max_quantity();
			ret->expenditure = this->get_segment_expenditure();
		}else
			ret->commodity_id = std::numeric_limits<decltype(ret->commodity_id)>::max();
		ret->profit_per_unit = this->profit_per_unit;
		ret->efficiency = this->get_efficiency();
		ret->accumulated_profit = this->get_profit();
		ret->cost = this->get_cost();
	}
	return ret;
}
<|endoftext|>


<commit_before><commit_msg>wait for torrent to be seeding before trying to connect to it, in test_ssl<commit_after><|endoftext|>


<commit_before>/*******************************************************************************
 * tests/data/channel_multiplexer_test.cpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 * Copyright (C) 2015 Tobias Sturm  <tobias.sturm@student.kit.edu>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <c7a/data/channel_multiplexer.hpp>
#include <c7a/data/channel.hpp>
#include <c7a/data/manager.hpp>
#include <c7a/net/group.hpp>
#include <c7a/net/dispatcher_thread.hpp>
#include <c7a/common/cyclic_barrier.hpp>

#include <gtest/gtest.h>
#include <string>

using namespace c7a;
using namespace c7a::common;
using namespace c7a::net;
using Manager = c7a::data::Manager;
using Group = c7a::net::Group;

static const bool debug = true;

struct ChannelMultiplexerTest : public::testing::Test {
    ChannelMultiplexerTest()
        : dispatcher("dispatcher"), manager(dispatcher), single_group(0, 1) {
        manager.Connect(&single_group);
    }

    using WorkerThread = std::function<void(Manager&)>;
    void FunctionSelect(Group* group, WorkerThread f1, WorkerThread f2, WorkerThread f3 = [](Manager&) { }) {
        Manager manager(dispatcher);
        manager.Connect(group);
        switch (group->MyRank()) {
        case 0:
            GetThreadDirectory().NameThisThread("t0");
            f1(manager);
            break;
        case 1:
            GetThreadDirectory().NameThisThread("t1");
            f2(manager);
            break;
        case 2:
            GetThreadDirectory().NameThisThread("t2");
            f3(manager);
            break;
        }
        barrier->Await();
    }
    void Execute(WorkerThread f1, WorkerThread f2, WorkerThread f3) {
        barrier = new Barrier(3);
        Group::ExecuteLocalMock(3,
                                [ = ](Group* g) {
                                    FunctionSelect(g, f1, f2, f3);
                                });
        free(barrier);
    }

    void Execute(WorkerThread f1, WorkerThread f2) {
        barrier = new Barrier(2);
        Group::ExecuteLocalMock(2,
                                [ = ](Group* g) {
                                    FunctionSelect(g, f1, f2);
                                });
        free(barrier);
    }

    void Execute(WorkerThread f1) {
        barrier = new Barrier(1);
        Group::ExecuteLocalMock(1,
                                [ = ](Group* g) {
                                    FunctionSelect(g, f1, [](Manager&) { });
                                });
        free(barrier);
    }
    DispatcherThread dispatcher;
    Manager          manager;
    Group            single_group;
    Barrier          * barrier;
};

// open a Channel via data::Manager, and send a short message to all workers,
// receive and check the message.
void TalkAllToAllViaChannel(net::Group* net) {
    common::GetThreadDirectory().NameThisThread(
        "chmp" + std::to_string(net->MyRank()));

    net::DispatcherThread dispatcher(
        "chmp" + std::to_string(net->MyRank()) + "-dp");

    unsigned char send_buffer[123];
    for (size_t i = 0; i != sizeof(send_buffer); ++i)
        send_buffer[i] = i;

    static const size_t iterations = 1000;

    data::ChannelMultiplexer<1024> cmp(dispatcher);
    cmp.Connect(net);
    {
        data::ChannelId id = cmp.AllocateNext();

        // open Writers and send a message to all workers

        auto writer = cmp.GetOrCreateChannel(id)->OpenWriters();

        for (size_t tgt = 0; tgt != net->Size(); ++tgt) {
            writer[tgt]("hello I am " + std::to_string(net->MyRank())
                        + " calling " + std::to_string(tgt));

            writer[tgt].Flush();

            // write a few MiBs of oddly sized data
            for (size_t r = 0; r != iterations; ++r) {
                writer[tgt].Append(send_buffer, sizeof(send_buffer));
            }

            writer[tgt].Flush();
        }

        // open Readers and receive message from all workers

        auto reader = cmp.GetOrCreateChannel(id)->OpenReaders();

        for (size_t src = 0; src != net->Size(); ++src) {
            std::string msg = reader[src].Next<std::string>();

            ASSERT_EQ(msg, "hello I am " + std::to_string(src)
                      + " calling " + std::to_string(net->MyRank()));

            sLOG << net->MyRank() << "got msg from" << src;

            // read a few MiBs of oddly sized data
            unsigned char recv_buffer[sizeof(send_buffer)];

            for (size_t r = 0; r != iterations; ++r) {
                reader[src].Read(recv_buffer, sizeof(recv_buffer));

                ASSERT_TRUE(std::equal(send_buffer,
                                       send_buffer + sizeof(send_buffer),
                                       recv_buffer));
            }
        }
    }
}

TEST(ChannelMultiplexer, TalkAllToAllViaChannelForManyNetSizes) {
    // test for all network mesh sizes 1-8:
    for (size_t i = 1; i <= 8; ++i) {
        net::Group::ExecuteLocalMock(i, TalkAllToAllViaChannel);
    }
}

TEST_F(ChannelMultiplexerTest, ReadCompleteChannel) {
    Barrier sync(3);
    auto w0 = [&sync](Manager& manager) {
                  auto c = manager.GetNewChannel();
                  auto writers = c->OpenWriters();
                  std::string msg1 = "I came from worker 0";
                  std::string msg2 = "I am another message from worker 0";
                  writers[2](msg1);
                  //writers[2].Flush();
                  writers[2](msg2);
                  for (auto& w : writers) {
                      sLOG << "close worker";
                      w.Close();
                  }
              };
    auto w1 = [&sync](Manager& manager) {
                  auto c = manager.GetNewChannel();
                  auto writers = c->OpenWriters();
                  std::string msg1 = "I came from worker 1";
                  writers[2](msg1);
                  for (auto& w : writers) {
                      sLOG << "close worker";
                      w.Close();
                  }
              };
    auto w2 = [&sync](Manager& manager) {
                  auto c = manager.GetNewChannel();
                  auto writers = c->OpenWriters();
                  for (auto& w : writers) {
                      sLOG << "close worker";
                      w.Close();
                  }
                  auto file = c->ReadCompleteChannel();
                  for (size_t i = 0; i < file.NumBlocks(); i++)
                      sLOG << "block" << i << file.BlockAsString(i);

                  auto reader = file.GetReader();
                  ASSERT_EQ("I came from worker 0", reader.Next<std::string>());
                  ASSERT_EQ("I am another message from worker 0", reader.Next<std::string>());
                  ASSERT_EQ("I came from worker 1", reader.Next<std::string>());
              };
    Execute(w0, w1, w2);
}

/******************************************************************************/
<commit_msg>do not test 1..8, instead 1, 2, 5, 32 workers<commit_after>/*******************************************************************************
 * tests/data/channel_multiplexer_test.cpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 * Copyright (C) 2015 Tobias Sturm  <tobias.sturm@student.kit.edu>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#include <c7a/data/channel_multiplexer.hpp>
#include <c7a/data/channel.hpp>
#include <c7a/data/manager.hpp>
#include <c7a/net/group.hpp>
#include <c7a/net/dispatcher_thread.hpp>
#include <c7a/common/cyclic_barrier.hpp>

#include <gtest/gtest.h>
#include <string>

using namespace c7a;
using namespace c7a::common;
using namespace c7a::net;
using Manager = c7a::data::Manager;
using Group = c7a::net::Group;

static const bool debug = true;

struct ChannelMultiplexerTest : public::testing::Test {
    ChannelMultiplexerTest()
        : dispatcher("dispatcher"), manager(dispatcher), single_group(0, 1) {
        manager.Connect(&single_group);
    }

    using WorkerThread = std::function<void(Manager&)>;
    void FunctionSelect(Group* group, WorkerThread f1, WorkerThread f2, WorkerThread f3 = [](Manager&) { }) {
        Manager manager(dispatcher);
        manager.Connect(group);
        switch (group->MyRank()) {
        case 0:
            GetThreadDirectory().NameThisThread("t0");
            f1(manager);
            break;
        case 1:
            GetThreadDirectory().NameThisThread("t1");
            f2(manager);
            break;
        case 2:
            GetThreadDirectory().NameThisThread("t2");
            f3(manager);
            break;
        }
        barrier->Await();
    }
    void Execute(WorkerThread f1, WorkerThread f2, WorkerThread f3) {
        barrier = new Barrier(3);
        Group::ExecuteLocalMock(3,
                                [ = ](Group* g) {
                                    FunctionSelect(g, f1, f2, f3);
                                });
        free(barrier);
    }

    void Execute(WorkerThread f1, WorkerThread f2) {
        barrier = new Barrier(2);
        Group::ExecuteLocalMock(2,
                                [ = ](Group* g) {
                                    FunctionSelect(g, f1, f2);
                                });
        free(barrier);
    }

    void Execute(WorkerThread f1) {
        barrier = new Barrier(1);
        Group::ExecuteLocalMock(1,
                                [ = ](Group* g) {
                                    FunctionSelect(g, f1, [](Manager&) { });
                                });
        free(barrier);
    }
    DispatcherThread dispatcher;
    Manager          manager;
    Group            single_group;
    Barrier          * barrier;
};

// open a Channel via data::Manager, and send a short message to all workers,
// receive and check the message.
void TalkAllToAllViaChannel(net::Group* net) {
    common::GetThreadDirectory().NameThisThread(
        "chmp" + std::to_string(net->MyRank()));

    net::DispatcherThread dispatcher(
        "chmp" + std::to_string(net->MyRank()) + "-dp");

    unsigned char send_buffer[123];
    for (size_t i = 0; i != sizeof(send_buffer); ++i)
        send_buffer[i] = i;

    static const size_t iterations = 1000;

    data::ChannelMultiplexer<1024> cmp(dispatcher);
    cmp.Connect(net);
    {
        data::ChannelId id = cmp.AllocateNext();

        // open Writers and send a message to all workers

        auto writer = cmp.GetOrCreateChannel(id)->OpenWriters();

        for (size_t tgt = 0; tgt != net->Size(); ++tgt) {
            writer[tgt]("hello I am " + std::to_string(net->MyRank())
                        + " calling " + std::to_string(tgt));

            writer[tgt].Flush();

            // write a few MiBs of oddly sized data
            for (size_t r = 0; r != iterations; ++r) {
                writer[tgt].Append(send_buffer, sizeof(send_buffer));
            }

            writer[tgt].Flush();
        }

        // open Readers and receive message from all workers

        auto reader = cmp.GetOrCreateChannel(id)->OpenReaders();

        for (size_t src = 0; src != net->Size(); ++src) {
            std::string msg = reader[src].Next<std::string>();

            ASSERT_EQ(msg, "hello I am " + std::to_string(src)
                      + " calling " + std::to_string(net->MyRank()));

            sLOG << net->MyRank() << "got msg from" << src;

            // read a few MiBs of oddly sized data
            unsigned char recv_buffer[sizeof(send_buffer)];

            for (size_t r = 0; r != iterations; ++r) {
                reader[src].Read(recv_buffer, sizeof(recv_buffer));

                ASSERT_TRUE(std::equal(send_buffer,
                                       send_buffer + sizeof(send_buffer),
                                       recv_buffer));
            }
        }
    }
}

TEST(ChannelMultiplexer, TalkAllToAllViaChannelForManyNetSizes) {
    // test for all network mesh sizes 1, 2, 5, 32:
    net::Group::ExecuteLocalMock(1, TalkAllToAllViaChannel);
    net::Group::ExecuteLocalMock(2, TalkAllToAllViaChannel);
    net::Group::ExecuteLocalMock(5, TalkAllToAllViaChannel);
    net::Group::ExecuteLocalMock(32, TalkAllToAllViaChannel);
}

TEST_F(ChannelMultiplexerTest, ReadCompleteChannel) {
    Barrier sync(3);
    auto w0 = [&sync](Manager& manager) {
                  auto c = manager.GetNewChannel();
                  auto writers = c->OpenWriters();
                  std::string msg1 = "I came from worker 0";
                  std::string msg2 = "I am another message from worker 0";
                  writers[2](msg1);
                  //writers[2].Flush();
                  writers[2](msg2);
                  for (auto& w : writers) {
                      sLOG << "close worker";
                      w.Close();
                  }
              };
    auto w1 = [&sync](Manager& manager) {
                  auto c = manager.GetNewChannel();
                  auto writers = c->OpenWriters();
                  std::string msg1 = "I came from worker 1";
                  writers[2](msg1);
                  for (auto& w : writers) {
                      sLOG << "close worker";
                      w.Close();
                  }
              };
    auto w2 = [&sync](Manager& manager) {
                  auto c = manager.GetNewChannel();
                  auto writers = c->OpenWriters();
                  for (auto& w : writers) {
                      sLOG << "close worker";
                      w.Close();
                  }
                  auto file = c->ReadCompleteChannel();
                  for (size_t i = 0; i < file.NumBlocks(); i++)
                      sLOG << "block" << i << file.BlockAsString(i);

                  auto reader = file.GetReader();
                  ASSERT_EQ("I came from worker 0", reader.Next<std::string>());
                  ASSERT_EQ("I am another message from worker 0", reader.Next<std::string>());
                  ASSERT_EQ("I came from worker 1", reader.Next<std::string>());
              };
    Execute(w0, w1, w2);
}

/******************************************************************************/
<|endoftext|>


<commit_before><commit_msg>add display property of device and storage<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <boost/multiprecision/cpp_int.hpp>

#include "bytes.hh"

class big_decimal {
private:
    int32_t _scale;
    boost::multiprecision::cpp_int _unscaled_value;
public:
    enum class rounding_mode {
        HALF_EVEN,
    };

    big_decimal(sstring_view text);
    big_decimal() : big_decimal(0, 0) {}
    big_decimal(int32_t scale, boost::multiprecision::cpp_int unscaled_value)
        : _scale(scale), _unscaled_value(unscaled_value)
    { }

    int32_t scale() const { return _scale; }
    const boost::multiprecision::cpp_int& unscaled_value() const { return _unscaled_value; }

    sstring to_string() const;

    int compare(const big_decimal& other) const;

    big_decimal& operator+=(const big_decimal& other);
    big_decimal& operator-=(const big_decimal& other);
    big_decimal operator+(const big_decimal& other) const;
    big_decimal operator-(const big_decimal& other) const;
    big_decimal div(const ::uint64_t y, const rounding_mode mode) const;
    friend bool operator<(const big_decimal& x, const big_decimal& y) { return x.compare(y) < 0; }
    friend bool operator<=(const big_decimal& x, const big_decimal& y) { return x.compare(y) <= 0; }
    friend bool operator==(const big_decimal& x, const big_decimal& y) { return x.compare(y) == 0; }
    friend bool operator!=(const big_decimal& x, const big_decimal& y) { return x.compare(y) != 0; }
    friend bool operator>=(const big_decimal& x, const big_decimal& y) { return x.compare(y) >= 0; }
    friend bool operator>(const big_decimal& x, const big_decimal& y) { return x.compare(y) > 0; }
};
<commit_msg>utils: make string-based big decimal constructor explicit<commit_after>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <boost/multiprecision/cpp_int.hpp>

#include "bytes.hh"

class big_decimal {
private:
    int32_t _scale;
    boost::multiprecision::cpp_int _unscaled_value;
public:
    enum class rounding_mode {
        HALF_EVEN,
    };

    explicit big_decimal(sstring_view text);
    big_decimal() : big_decimal(0, 0) {}
    big_decimal(int32_t scale, boost::multiprecision::cpp_int unscaled_value)
        : _scale(scale), _unscaled_value(unscaled_value)
    { }

    int32_t scale() const { return _scale; }
    const boost::multiprecision::cpp_int& unscaled_value() const { return _unscaled_value; }

    sstring to_string() const;

    int compare(const big_decimal& other) const;

    big_decimal& operator+=(const big_decimal& other);
    big_decimal& operator-=(const big_decimal& other);
    big_decimal operator+(const big_decimal& other) const;
    big_decimal operator-(const big_decimal& other) const;
    big_decimal div(const ::uint64_t y, const rounding_mode mode) const;
    friend bool operator<(const big_decimal& x, const big_decimal& y) { return x.compare(y) < 0; }
    friend bool operator<=(const big_decimal& x, const big_decimal& y) { return x.compare(y) <= 0; }
    friend bool operator==(const big_decimal& x, const big_decimal& y) { return x.compare(y) == 0; }
    friend bool operator!=(const big_decimal& x, const big_decimal& y) { return x.compare(y) != 0; }
    friend bool operator>=(const big_decimal& x, const big_decimal& y) { return x.compare(y) >= 0; }
    friend bool operator>(const big_decimal& x, const big_decimal& y) { return x.compare(y) > 0; }
};
<|endoftext|>


<commit_before>#include "engine/debug/debug.h"
#include "engine/mt/atomic.h"
#include "engine/string.h"
#include "engine/system.h"
#include <cstdlib>
#include <cstdio>

static bool g_is_crash_reporting_enabled = false;

namespace Lumix
{

namespace Debug
{

void debugOutput(const char* message)
{
	puts(message);
}

void debugBreak()
{
	abort();
}

int StackTree::s_instances = 0;

class StackNode
{
public:
	~StackNode()
	{
		delete m_next;
		delete m_first_child;
	}

	void* m_instruction;
	StackNode* m_next;
	StackNode* m_first_child;
	StackNode* m_parent;
};

StackTree::StackTree()
{
}

StackTree::~StackTree()
{
}

void StackTree::refreshModuleList()
{
}

int StackTree::getPath(StackNode* node, StackNode** output, int max_size)
{
	return 0;
}

StackNode* StackTree::getParent(StackNode* node)
{
	return nullptr;
}

bool StackTree::getFunction(StackNode* node, char* out, int max_size, int* line)
{
	return false;
}

void StackTree::printCallstack(StackNode* node)
{
}

StackNode* StackTree::insertChildren(StackNode* root_node, void** instruction, void** stack)
{
	return nullptr;
}

StackNode* StackTree::record()
{
	return nullptr;
}

static const uint32 UNINITIALIZED_MEMORY_PATTERN = 0xCD;
static const uint32 FREED_MEMORY_PATTERN = 0xDD;
static const uint32 ALLOCATION_GUARD = 0xFDFDFDFD;

Allocator::Allocator(IAllocator& source)
	: m_source(source)
	, m_root(nullptr)
	, m_mutex(false)
	, m_total_size(0)
	, m_is_fill_enabled(true)
	, m_are_guards_enabled(true)
{
	m_sentinels[0].next = &m_sentinels[1];
	m_sentinels[0].previous = nullptr;
	m_sentinels[0].stack_leaf = nullptr;
	m_sentinels[0].size = 0;
	m_sentinels[0].align = 0;

	m_sentinels[1].next = nullptr;
	m_sentinels[1].previous = &m_sentinels[0];
	m_sentinels[1].stack_leaf = nullptr;
	m_sentinels[1].size = 0;
	m_sentinels[1].align = 0;

	m_root = &m_sentinels[1];
}

Allocator::~Allocator()
{
	AllocationInfo* last_sentinel = &m_sentinels[1];
	if (m_root != last_sentinel)
	{
		debugOutput("Memory leaks detected!\n");
		AllocationInfo* info = m_root;
		while (info != last_sentinel)
		{
			char tmp[2048];
			sprintf(tmp, "\nAllocation size : %Iu, memory %p\n", info->size, info + sizeof(info));
			debugOutput(tmp);
			m_stack_tree.printCallstack(info->stack_leaf);
			info = info->next;
		}
		ASSERT(false);
	}
}

void Allocator::lock()
{
	m_mutex.lock();
}

void Allocator::unlock()
{
	m_mutex.unlock();
}

void Allocator::checkGuards()
{
	if (m_are_guards_enabled) return;

	auto* info = m_root;
	while (info)
	{
		auto user_ptr = getUserPtrFromAllocationInfo(info);
		void* system_ptr = getSystemFromUser(user_ptr);
		ASSERT(*(uint32*)system_ptr == ALLOCATION_GUARD);
		ASSERT(*(uint32*)((uint8*)user_ptr + info->size) == ALLOCATION_GUARD);

		info = info->next;
	}
}

size_t Allocator::getAllocationOffset()
{
	return sizeof(AllocationInfo) + (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) : 0);
}

size_t Allocator::getNeededMemory(size_t size)
{
	return size + sizeof(AllocationInfo) + (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) << 1 : 0);
}

size_t Allocator::getNeededMemory(size_t size, size_t align)
{
	return size + sizeof(AllocationInfo) + (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) << 1 : 0) +
		align;
}

Allocator::AllocationInfo* Allocator::getAllocationInfoFromSystem(void* system_ptr)
{
	return (AllocationInfo*)(m_are_guards_enabled ? (uint8*)system_ptr + sizeof(ALLOCATION_GUARD)
		: system_ptr);
}

void* Allocator::getUserPtrFromAllocationInfo(AllocationInfo* info)
{
	return ((uint8*)info + sizeof(AllocationInfo));
}

Allocator::AllocationInfo* Allocator::getAllocationInfoFromUser(void* user_ptr)
{
	return (AllocationInfo*)((uint8*)user_ptr - sizeof(AllocationInfo));
}

uint8* Allocator::getUserFromSystem(void* system_ptr, size_t align)
{
	size_t diff = (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) : 0) + sizeof(AllocationInfo);

	if (align) diff += (align - diff % align) % align;
	return (uint8*)system_ptr + diff;
}

uint8* Allocator::getSystemFromUser(void* user_ptr)
{
	AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
	size_t diff = (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) : 0) + sizeof(AllocationInfo);
	if (info->align) diff += (info->align - diff % info->align) % info->align;
	return (uint8*)user_ptr - diff;
}

void* Allocator::reallocate(void* user_ptr, size_t size)
{
#ifndef _DEBUG
	return m_source.reallocate(user_ptr, size);
#else
	if (user_ptr == nullptr) return allocate(size);
	if (size == 0) return nullptr;

	void* new_data = allocate(size);
	if (!new_data) return nullptr;

	AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
	copyMemory(new_data, user_ptr, info->size < size ? info->size : size);

	deallocate(user_ptr);

	return new_data;
#endif
}

void* Allocator::allocate_aligned(size_t size, size_t align)
{
#ifndef _DEBUG
	return m_source.allocate_aligned(size, align);
#else
	void* system_ptr;
	AllocationInfo* info;
	uint8* user_ptr;

	size_t system_size = getNeededMemory(size, align);
	{
		MT::SpinLock lock(m_mutex);
		system_ptr = m_source.allocate_aligned(system_size, align);
		user_ptr = getUserFromSystem(system_ptr, align);
		info = new (NewPlaceholder(), getAllocationInfoFromUser(user_ptr)) AllocationInfo();

		info->previous = m_root->previous;
		m_root->previous->next = info;

		info->next = m_root;
		m_root->previous = info;

		m_root = info;

		m_total_size += size;
	} // because of the SpinLock

	info->align = uint16(align);
	info->stack_leaf = m_stack_tree.record();
	info->size = size;
	if (m_is_fill_enabled)
	{
		memset(user_ptr, UNINITIALIZED_MEMORY_PATTERN, size);
	}

	if (m_are_guards_enabled)
	{
		*(uint32*)system_ptr = ALLOCATION_GUARD;
		*(uint32*)((uint8*)system_ptr + system_size - sizeof(ALLOCATION_GUARD)) = ALLOCATION_GUARD;
	}

	return user_ptr;
#endif
}

void Allocator::deallocate_aligned(void* user_ptr)
{
#ifndef _DEBUG
	m_source.deallocate_aligned(user_ptr);
#else
	if (user_ptr)
	{
		AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
		void* system_ptr = getSystemFromUser(user_ptr);
		if (m_is_fill_enabled)
		{
			memset(user_ptr, FREED_MEMORY_PATTERN, info->size);
		}

		if (m_are_guards_enabled)
		{
			ASSERT(*(uint32*)system_ptr == ALLOCATION_GUARD);
			size_t system_size = getNeededMemory(info->size, info->align);
			ASSERT(*(uint32*)((uint8*)system_ptr + system_size - sizeof(ALLOCATION_GUARD)) == ALLOCATION_GUARD);
		}

		{
			MT::SpinLock lock(m_mutex);
			if (info == m_root)
			{
				m_root = info->next;
			}
			info->previous->next = info->next;
			info->next->previous = info->previous;

			m_total_size -= info->size;
		} // because of the SpinLock

		info->~AllocationInfo();

		m_source.deallocate_aligned((void*)system_ptr);
	}
#endif
}

void* Allocator::reallocate_aligned(void* user_ptr, size_t size, size_t align)
{
#ifndef _DEBUG
	return m_source.reallocate_aligned(user_ptr, size, align);
#else
	if (user_ptr == nullptr) return allocate_aligned(size, align);
	if (size == 0) return nullptr;

	void* new_data = allocate_aligned(size, align);
	if (!new_data) return nullptr;

	AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
	copyMemory(new_data, user_ptr, info->size < size ? info->size : size);

	deallocate_aligned(user_ptr);

	return new_data;
#endif
}

void* Allocator::allocate(size_t size)
{
#ifndef _DEBUG
	return m_source.allocate(size);
#else
	void* system_ptr;
	AllocationInfo* info;
	size_t system_size = getNeededMemory(size);
	{
		MT::SpinLock lock(m_mutex);
		system_ptr = m_source.allocate(system_size);
		info = new (NewPlaceholder(), getAllocationInfoFromSystem(system_ptr)) AllocationInfo();

		info->previous = m_root->previous;
		m_root->previous->next = info;

		info->next = m_root;
		m_root->previous = info;

		m_root = info;

		m_total_size += size;
	} // because of the SpinLock

	void* user_ptr = getUserFromSystem(system_ptr, 0);
	info->stack_leaf = m_stack_tree.record();
	info->size = size;
	info->align = 0;
	if (m_is_fill_enabled)
	{
		memset(user_ptr, UNINITIALIZED_MEMORY_PATTERN, size);
	}

	if (m_are_guards_enabled)
	{
		*(uint32*)system_ptr = ALLOCATION_GUARD;
		*(uint32*)((uint8*)system_ptr + system_size - sizeof(ALLOCATION_GUARD)) = ALLOCATION_GUARD;
	}

	return user_ptr;
#endif
}

void Allocator::deallocate(void* user_ptr)
{
#ifndef _DEBUG
	m_source.deallocate(user_ptr);
#else
	if (user_ptr)
	{
		AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
		void* system_ptr = getSystemFromUser(user_ptr);
		if (m_is_fill_enabled)
		{
			memset(user_ptr, FREED_MEMORY_PATTERN, info->size);
		}

		if (m_are_guards_enabled)
		{
			ASSERT(*(uint32*)system_ptr == ALLOCATION_GUARD);
			size_t system_size = getNeededMemory(info->size);
			ASSERT(*(uint32*)((uint8*)system_ptr + system_size - sizeof(ALLOCATION_GUARD)) == ALLOCATION_GUARD);
		}

		{
			MT::SpinLock lock(m_mutex);
			if (info == m_root)
			{
				m_root = info->next;
			}
			info->previous->next = info->next;
			info->next->previous = info->previous;

			m_total_size -= info->size;
		} // because of the SpinLock

		info->~AllocationInfo();

		m_source.deallocate((void*)system_ptr);
	}
#endif
}

} // namespace Debug

void enableCrashReporting(bool enable)
{
	g_is_crash_reporting_enabled = false;
}

void installUnhandledExceptionHandler()
{
}

} // namespace Lumix
<commit_msg>fixed linux build part #3<commit_after>#include "engine/debug/debug.h"
#include "engine/mt/atomic.h"
#include "engine/string.h"
#include "engine/system.h"
#include <cstdlib>
#include <cstdio>

static bool g_is_crash_reporting_enabled = false;

namespace Lumix
{

namespace Debug
{

void debugOutput(const char* message)
{
	puts(message);
}

void debugBreak()
{
	abort();
}

int StackTree::s_instances = 0;

class StackNode
{
public:
	~StackNode()
	{
		delete m_next;
		delete m_first_child;
	}

	void* m_instruction;
	StackNode* m_next;
	StackNode* m_first_child;
	StackNode* m_parent;
};

StackTree::StackTree()
{
}

StackTree::~StackTree()
{
}

void StackTree::refreshModuleList()
{
}

int StackTree::getPath(StackNode* node, StackNode** output, int max_size)
{
	return 0;
}

StackNode* StackTree::getParent(StackNode* node)
{
	return nullptr;
}

bool StackTree::getFunction(StackNode* node, char* out, int max_size, int* line)
{
	return false;
}

void StackTree::printCallstack(StackNode* node)
{
}

StackNode* StackTree::insertChildren(StackNode* root_node, void** instruction, void** stack)
{
	return nullptr;
}

StackNode* StackTree::record()
{
	return nullptr;
}

static const uint32 UNINITIALIZED_MEMORY_PATTERN = 0xCD;
static const uint32 FREED_MEMORY_PATTERN = 0xDD;
static const uint32 ALLOCATION_GUARD = 0xFDFDFDFD;

Allocator::Allocator(IAllocator& source)
	: m_source(source)
	, m_root(nullptr)
	, m_mutex(false)
	, m_total_size(0)
	, m_is_fill_enabled(true)
	, m_are_guards_enabled(true)
{
	m_sentinels[0].next = &m_sentinels[1];
	m_sentinels[0].previous = nullptr;
	m_sentinels[0].stack_leaf = nullptr;
	m_sentinels[0].size = 0;
	m_sentinels[0].align = 0;

	m_sentinels[1].next = nullptr;
	m_sentinels[1].previous = &m_sentinels[0];
	m_sentinels[1].stack_leaf = nullptr;
	m_sentinels[1].size = 0;
	m_sentinels[1].align = 0;

	m_root = &m_sentinels[1];
}

Allocator::~Allocator()
{
	AllocationInfo* last_sentinel = &m_sentinels[1];
	if (m_root != last_sentinel)
	{
		debugOutput("Memory leaks detected!\n");
		AllocationInfo* info = m_root;
		while (info != last_sentinel)
		{
			char tmp[2048];
			sprintf(tmp, "\nAllocation size : %zu, memory %p\n", info->size, info + sizeof(info));
			debugOutput(tmp);
			m_stack_tree.printCallstack(info->stack_leaf);
			info = info->next;
		}
		ASSERT(false);
	}
}

void Allocator::lock()
{
	m_mutex.lock();
}

void Allocator::unlock()
{
	m_mutex.unlock();
}

void Allocator::checkGuards()
{
	if (m_are_guards_enabled) return;

	auto* info = m_root;
	while (info)
	{
		auto user_ptr = getUserPtrFromAllocationInfo(info);
		void* system_ptr = getSystemFromUser(user_ptr);
		ASSERT(*(uint32*)system_ptr == ALLOCATION_GUARD);
		ASSERT(*(uint32*)((uint8*)user_ptr + info->size) == ALLOCATION_GUARD);

		info = info->next;
	}
}

size_t Allocator::getAllocationOffset()
{
	return sizeof(AllocationInfo) + (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) : 0);
}

size_t Allocator::getNeededMemory(size_t size)
{
	return size + sizeof(AllocationInfo) + (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) << 1 : 0);
}

size_t Allocator::getNeededMemory(size_t size, size_t align)
{
	return size + sizeof(AllocationInfo) + (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) << 1 : 0) +
		align;
}

Allocator::AllocationInfo* Allocator::getAllocationInfoFromSystem(void* system_ptr)
{
	return (AllocationInfo*)(m_are_guards_enabled ? (uint8*)system_ptr + sizeof(ALLOCATION_GUARD)
		: system_ptr);
}

void* Allocator::getUserPtrFromAllocationInfo(AllocationInfo* info)
{
	return ((uint8*)info + sizeof(AllocationInfo));
}

Allocator::AllocationInfo* Allocator::getAllocationInfoFromUser(void* user_ptr)
{
	return (AllocationInfo*)((uint8*)user_ptr - sizeof(AllocationInfo));
}

uint8* Allocator::getUserFromSystem(void* system_ptr, size_t align)
{
	size_t diff = (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) : 0) + sizeof(AllocationInfo);

	if (align) diff += (align - diff % align) % align;
	return (uint8*)system_ptr + diff;
}

uint8* Allocator::getSystemFromUser(void* user_ptr)
{
	AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
	size_t diff = (m_are_guards_enabled ? sizeof(ALLOCATION_GUARD) : 0) + sizeof(AllocationInfo);
	if (info->align) diff += (info->align - diff % info->align) % info->align;
	return (uint8*)user_ptr - diff;
}

void* Allocator::reallocate(void* user_ptr, size_t size)
{
#ifndef _DEBUG
	return m_source.reallocate(user_ptr, size);
#else
	if (user_ptr == nullptr) return allocate(size);
	if (size == 0) return nullptr;

	void* new_data = allocate(size);
	if (!new_data) return nullptr;

	AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
	copyMemory(new_data, user_ptr, info->size < size ? info->size : size);

	deallocate(user_ptr);

	return new_data;
#endif
}

void* Allocator::allocate_aligned(size_t size, size_t align)
{
#ifndef _DEBUG
	return m_source.allocate_aligned(size, align);
#else
	void* system_ptr;
	AllocationInfo* info;
	uint8* user_ptr;

	size_t system_size = getNeededMemory(size, align);
	{
		MT::SpinLock lock(m_mutex);
		system_ptr = m_source.allocate_aligned(system_size, align);
		user_ptr = getUserFromSystem(system_ptr, align);
		info = new (NewPlaceholder(), getAllocationInfoFromUser(user_ptr)) AllocationInfo();

		info->previous = m_root->previous;
		m_root->previous->next = info;

		info->next = m_root;
		m_root->previous = info;

		m_root = info;

		m_total_size += size;
	} // because of the SpinLock

	info->align = uint16(align);
	info->stack_leaf = m_stack_tree.record();
	info->size = size;
	if (m_is_fill_enabled)
	{
		memset(user_ptr, UNINITIALIZED_MEMORY_PATTERN, size);
	}

	if (m_are_guards_enabled)
	{
		*(uint32*)system_ptr = ALLOCATION_GUARD;
		*(uint32*)((uint8*)system_ptr + system_size - sizeof(ALLOCATION_GUARD)) = ALLOCATION_GUARD;
	}

	return user_ptr;
#endif
}

void Allocator::deallocate_aligned(void* user_ptr)
{
#ifndef _DEBUG
	m_source.deallocate_aligned(user_ptr);
#else
	if (user_ptr)
	{
		AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
		void* system_ptr = getSystemFromUser(user_ptr);
		if (m_is_fill_enabled)
		{
			memset(user_ptr, FREED_MEMORY_PATTERN, info->size);
		}

		if (m_are_guards_enabled)
		{
			ASSERT(*(uint32*)system_ptr == ALLOCATION_GUARD);
			size_t system_size = getNeededMemory(info->size, info->align);
			ASSERT(*(uint32*)((uint8*)system_ptr + system_size - sizeof(ALLOCATION_GUARD)) == ALLOCATION_GUARD);
		}

		{
			MT::SpinLock lock(m_mutex);
			if (info == m_root)
			{
				m_root = info->next;
			}
			info->previous->next = info->next;
			info->next->previous = info->previous;

			m_total_size -= info->size;
		} // because of the SpinLock

		info->~AllocationInfo();

		m_source.deallocate_aligned((void*)system_ptr);
	}
#endif
}

void* Allocator::reallocate_aligned(void* user_ptr, size_t size, size_t align)
{
#ifndef _DEBUG
	return m_source.reallocate_aligned(user_ptr, size, align);
#else
	if (user_ptr == nullptr) return allocate_aligned(size, align);
	if (size == 0) return nullptr;

	void* new_data = allocate_aligned(size, align);
	if (!new_data) return nullptr;

	AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
	copyMemory(new_data, user_ptr, info->size < size ? info->size : size);

	deallocate_aligned(user_ptr);

	return new_data;
#endif
}

void* Allocator::allocate(size_t size)
{
#ifndef _DEBUG
	return m_source.allocate(size);
#else
	void* system_ptr;
	AllocationInfo* info;
	size_t system_size = getNeededMemory(size);
	{
		MT::SpinLock lock(m_mutex);
		system_ptr = m_source.allocate(system_size);
		info = new (NewPlaceholder(), getAllocationInfoFromSystem(system_ptr)) AllocationInfo();

		info->previous = m_root->previous;
		m_root->previous->next = info;

		info->next = m_root;
		m_root->previous = info;

		m_root = info;

		m_total_size += size;
	} // because of the SpinLock

	void* user_ptr = getUserFromSystem(system_ptr, 0);
	info->stack_leaf = m_stack_tree.record();
	info->size = size;
	info->align = 0;
	if (m_is_fill_enabled)
	{
		memset(user_ptr, UNINITIALIZED_MEMORY_PATTERN, size);
	}

	if (m_are_guards_enabled)
	{
		*(uint32*)system_ptr = ALLOCATION_GUARD;
		*(uint32*)((uint8*)system_ptr + system_size - sizeof(ALLOCATION_GUARD)) = ALLOCATION_GUARD;
	}

	return user_ptr;
#endif
}

void Allocator::deallocate(void* user_ptr)
{
#ifndef _DEBUG
	m_source.deallocate(user_ptr);
#else
	if (user_ptr)
	{
		AllocationInfo* info = getAllocationInfoFromUser(user_ptr);
		void* system_ptr = getSystemFromUser(user_ptr);
		if (m_is_fill_enabled)
		{
			memset(user_ptr, FREED_MEMORY_PATTERN, info->size);
		}

		if (m_are_guards_enabled)
		{
			ASSERT(*(uint32*)system_ptr == ALLOCATION_GUARD);
			size_t system_size = getNeededMemory(info->size);
			ASSERT(*(uint32*)((uint8*)system_ptr + system_size - sizeof(ALLOCATION_GUARD)) == ALLOCATION_GUARD);
		}

		{
			MT::SpinLock lock(m_mutex);
			if (info == m_root)
			{
				m_root = info->next;
			}
			info->previous->next = info->next;
			info->next->previous = info->previous;

			m_total_size -= info->size;
		} // because of the SpinLock

		info->~AllocationInfo();

		m_source.deallocate((void*)system_ptr);
	}
#endif
}

} // namespace Debug

void enableCrashReporting(bool enable)
{
	g_is_crash_reporting_enabled = false;
}

void installUnhandledExceptionHandler()
{
}

} // namespace Lumix
<|endoftext|>


<commit_before>/*===- ShieldedCoulombForce.cpp - libSimulation -===============================
*
*                                  DEMON
*
* This file is distributed under the BSD Open Source License. See LICENSE.TXT
* for details.
*
*===-----------------------------------------------------------------------===*/

#include "ShieldedCoulombForce.h"
#include <cmath>
#include <limits>

using namespace std;

ShieldedCoulombForce::ShieldedCoulombForce(Cloud * const myCloud, const double shieldingConstant)
: Force(myCloud), shielding(shieldingConstant) {}

void ShieldedCoulombForce::force1(const double currentTime)
{
	for (unsigned int currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = _mm_load_pd(&cloud->x[currentParticle]);
		const __m128d vy1 = _mm_load_pd(&cloud->y[currentParticle]);
		double x1, x2, y1, y2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);

		force(currentParticle, currentParticle + 1, x1 - x2, y1 - y2);

		for(unsigned int i = currentParticle + 2; i < numParticles; i += 2)
		{
			const double *px2 = &cloud->x[i];
			const double *py2 = &cloud->y[i];

			force(currentParticle, i, vx1 - _mm_load_pd(px2), vy1 - _mm_load_pd(py2));
			forcer(currentParticle, i, vx1 - _mm_loadr_pd(px2), vy1 - _mm_loadr_pd(py2));
		}
	}
}

void ShieldedCoulombForce::force2(const double currentTime)
{
	const __m128d v2 = _mm_set1_pd(2.0);
	for (unsigned int currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = _mm_load_pd(&cloud->x[currentParticle]) + _mm_load_pd(&cloud->l1[currentParticle])/v2;
		const __m128d vy1 = _mm_load_pd(&cloud->y[currentParticle]) + _mm_load_pd(&cloud->n1[currentParticle])/v2;
		double x1, x2, y1, y2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);

		force(currentParticle, currentParticle + 1, x1 - x2, y1 - y2);
		for(unsigned int i = currentParticle + 2; i < numParticles; i += 2)
		{
			const double *px2 = &cloud->x[i];
			const double *py2 = &cloud->y[i];
			const double *pl = &cloud->l1[i];
			const double *pn = &cloud->n1[i];

			force(currentParticle, i, vx1 - (_mm_load_pd(px2) + _mm_load_pd(pl)/v2),
				vy1 - (_mm_load_pd(py2) + _mm_load_pd(pn)/v2));

			forcer(currentParticle, i, vx1 - (_mm_loadr_pd(px2) + _mm_loadr_pd(pl)/v2),
				vy1 - (_mm_loadr_pd(py2) + _mm_loadr_pd(pn)/v2));
		}
	}
}

void ShieldedCoulombForce::force3(const double currentTime)
{
	const __m128d v2 = _mm_set1_pd(2.0);
	for (unsigned int currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = _mm_load_pd(&cloud->x[currentParticle]) + _mm_load_pd(&cloud->l2[currentParticle])/v2;
		const __m128d vy1 = _mm_load_pd(&cloud->y[currentParticle]) + _mm_load_pd(&cloud->n2[currentParticle])/v2;
		double x1, x2, y1, y2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);

		force(currentParticle, currentParticle + 1, x1 - x2, y1 - y2);
		for(unsigned int i = currentParticle + 2; i < numParticles; i += 2)
		{
			const double *px2 = &cloud->x[i];
			const double *py2 = &cloud->y[i];
			const double *pl = &cloud->l2[i];
			const double *pn = &cloud->n2[i];

			force(currentParticle, i, vx1 - (_mm_load_pd(px2) + _mm_load_pd(pl)/v2),
				vy1 - (_mm_load_pd(py2) + _mm_load_pd(pn)/v2));

			forcer(currentParticle, i, vx1 - (_mm_loadr_pd(px2) + _mm_loadr_pd(pl)/v2),
 				vy1 - (_mm_loadr_pd(py2) + _mm_loadr_pd(pn)/v2));
		}
	}
}

void ShieldedCoulombForce::force4(const double currentTime)
{
	for (unsigned int currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = _mm_load_pd(&cloud->x[currentParticle]) + _mm_load_pd(&cloud->l3[currentParticle]);
		const __m128d vy1 = _mm_load_pd(&cloud->y[currentParticle]) + _mm_load_pd(&cloud->n3[currentParticle]);
		double x1, x2, y1, y2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);

		force(currentParticle, currentParticle + 1, x1 - x2, y1 - y2);
		for(unsigned int i = currentParticle + 2; i < numParticles; i += 2)
		{
			const double *px2 = &cloud->x[i];
			const double *py2 = &cloud->y[i];
			const double *pl = &cloud->l3[i];
			const double *pn = &cloud->n3[i];

			force(currentParticle, i, vx1 - (_mm_load_pd(px2) + _mm_load_pd(pl)),
				vy1 - (_mm_load_pd(py2) + _mm_load_pd(pn)));

			forcer(currentParticle, i, vx1 - (_mm_loadr_pd(px2) + _mm_loadr_pd(pl)),
 				vy1 - (_mm_loadr_pd(py2) + _mm_loadr_pd(pn)));
		}
	}
}

inline void ShieldedCoulombForce::force(const unsigned int currentParticle, const unsigned int iParticle, const double displacementX, const double displacementY)
{
	// Calculate displacement between particles.
	const double displacement = sqrt(displacementX*displacementX + displacementY*displacementY);
	const double valExp = displacement*shielding;

	if(valExp < 10.0) 	//restrict to 10*(ion debye length)
	{
		 //conclude force calculation:
		const double displacement3 = displacement*displacement*displacement;
		//set to charges multiplied by Coulomb's constant:
		const double exponential = (cloud->charge[currentParticle]*cloud->charge[iParticle])/(4.0*M_PI*8.85E-12)*(1.0 + valExp)/(displacement3*exp(valExp));
		cloud->forceX[currentParticle] += exponential*displacementX;
		cloud->forceY[currentParticle] += exponential*displacementY;

		//equal and opposite force:
		cloud->forceX[iParticle] -= exponential*displacementX;
		cloud->forceY[iParticle] -= exponential*displacementY;
	}
}

inline void ShieldedCoulombForce::force(const unsigned int currentParticle, const unsigned int iParticle, const __m128d displacementX, const __m128d displacementY)
{
	// Calculate displacement between particles.
	const __m128d displacement = _mm_sqrt_pd(displacementX*displacementX + displacementY*displacementY);
	const __m128d valExp = displacement*_mm_set_pd(shielding, shielding);

	double valExpL, valExpH;
	_mm_storel_pd(&valExpL, valExp);
	_mm_storeh_pd(&valExpH, valExp);

	const bool boolL = valExpL < 10.0;
	const bool boolH = valExpH < 10.0;
	if (!boolL && !boolH)
		return;

	double expL, expH;
	_mm_storel_pd(&expL, valExp);
	_mm_storeh_pd(&expH, valExp);

	__m128d expv = _mm_set_pd(boolH ? exp(-expH) : 0.0, //_mm_set_pd is backwards
							  boolL ? exp(-expL) : 0.0);

	//conclude force calculation:
	const __m128d displacement3 = displacement*displacement*displacement;
	//set to charges multiplied by Coulomb's constant:
	const double c = 4.0*M_PI*8.85E-12;
	const __m128d exponential = _mm_load_pd(&cloud->charge[currentParticle])*_mm_load_pd(&cloud->charge[iParticle])
		/_mm_set_pd(c, c)*(_mm_set1_pd(1.0) + valExp)/displacement3*expv;

	const __m128d forcevX = exponential*displacementX;
	const __m128d forcevY = exponential*displacementY;

	double *pFx = &cloud->forceX[currentParticle];
	double *pFy = &cloud->forceY[currentParticle];
	_mm_store_pd(pFx, _mm_load_pd(pFx) + forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) + forcevY);

	//equal and opposite force:
	pFx = &cloud->forceX[iParticle];
	pFy = &cloud->forceY[iParticle];
	_mm_store_pd(pFx, _mm_load_pd(pFx) - forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) - forcevY);
}

inline void ShieldedCoulombForce::forcer(const unsigned int currentParticle, const unsigned int iParticle, const __m128d displacementX, const __m128d displacementY)
{
	// Calculate displacement between particles.
	const __m128d displacement = _mm_sqrt_pd(displacementX*displacementX + displacementY*displacementY);
	const __m128d valExp = displacement*_mm_set_pd(shielding, shielding);

	double valExpL, valExpH;
	_mm_storel_pd(&valExpL, valExp);
	_mm_storeh_pd(&valExpH, valExp);

	const bool boolL = valExpL < 10.0;
	const bool boolH = valExpH < 10.0;
	if (!boolL && !boolH)
		return;

	double expL, expH;
	_mm_storel_pd(&expL, valExp);
	_mm_storeh_pd(&expH, valExp);

	__m128d expv = _mm_set_pd(boolH ? exp(-expH) : 0.0, //_mm_set_pd is backwards
							  boolL ? exp(-expL) : 0.0);

	//conclude force calculation:
	const __m128d displacement3 = displacement*displacement*displacement;
	//set to charges multiplied by Coulomb's constant:
	const double c = 4.0*M_PI*8.85e-12;
	const __m128d exponential = _mm_load_pd(&cloud->charge[currentParticle])*_mm_loadr_pd(&cloud->charge[iParticle])
		/_mm_set_pd(c, c)*(_mm_set1_pd(1.0) + valExp)/displacement3*expv;

	const __m128d forcevX = exponential*displacementX;
	const __m128d forcevY = exponential*displacementY;

	double *pFx = &cloud->forceX[currentParticle];
	double *pFy = &cloud->forceY[currentParticle];
	_mm_store_pd(pFx, _mm_load_pd(pFx) + forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) + forcevY);

	//equal and opposite force:
	pFx = &cloud->forceX[iParticle];
	pFy = &cloud->forceY[iParticle];
	_mm_storer_pd(pFx, _mm_loadr_pd(pFx) - forcevX);
	_mm_storer_pd(pFy, _mm_loadr_pd(pFy) - forcevY);
}

void ShieldedCoulombForce::writeForce(fitsfile * const file, int * const error) const
{
	//move to primary HDU:
	if(!*error)
		//file, # indicating primary HDU, HDU type, error
 		fits_movabs_hdu(file, 1, IMAGE_HDU, error);

	//add flag indicating that the drag force is used:
	if(!*error)
	{
		long forceFlags = 0;
		fits_read_key_lng(file, const_cast<char *> ("FORCES"), &forceFlags, NULL, error);

		//add ShieldedCoulombForce bit:
		forceFlags |= ShieldedCoulombForceFlag;		//compound bitwise OR

		if(*error == KEY_NO_EXIST || *error == VALUE_UNDEFINED)
			*error = 0;			//clear above error.

		//add or update keyword.
		if(!*error)
			fits_update_key(file, TLONG, const_cast<char *> ("FORCES"), &forceFlags, const_cast<char *> ("Force configuration."), error);
	}

	if(!*error)
		//file, key name, value, precision (scientific format), comment
		fits_write_key_dbl(file, const_cast<char *> ("shieldingConstant"), shielding, 6, const_cast<char *> ("[m^-1] (ShieldedCoulombForce)"), error);
}

void ShieldedCoulombForce::readForce(fitsfile * const file, int * const error)
{
	//move to primary HDU:
	if(!*error)
		//file, # indicating primary HDU, HDU type, error
 		fits_movabs_hdu(file, 1, IMAGE_HDU, error);

	if(!*error)
		//file, key name, value, don't read comment, error
		fits_read_key_dbl(file, const_cast<char *> ("shieldingConstant"), &shielding, NULL, error);
}
<commit_msg>Remove no longer used include.<commit_after>/*===- ShieldedCoulombForce.cpp - libSimulation -===============================
*
*                                  DEMON
*
* This file is distributed under the BSD Open Source License. See LICENSE.TXT
* for details.
*
*===-----------------------------------------------------------------------===*/

#include "ShieldedCoulombForce.h"
#include <cmath>

using namespace std;

ShieldedCoulombForce::ShieldedCoulombForce(Cloud * const myCloud, const double shieldingConstant)
: Force(myCloud), shielding(shieldingConstant) {}

void ShieldedCoulombForce::force1(const double currentTime)
{
	for (unsigned int currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = _mm_load_pd(&cloud->x[currentParticle]);
		const __m128d vy1 = _mm_load_pd(&cloud->y[currentParticle]);
		double x1, x2, y1, y2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);

		force(currentParticle, currentParticle + 1, x1 - x2, y1 - y2);

		for(unsigned int i = currentParticle + 2; i < numParticles; i += 2)
		{
			const double *px2 = &cloud->x[i];
			const double *py2 = &cloud->y[i];

			force(currentParticle, i, vx1 - _mm_load_pd(px2), vy1 - _mm_load_pd(py2));
			forcer(currentParticle, i, vx1 - _mm_loadr_pd(px2), vy1 - _mm_loadr_pd(py2));
		}
	}
}

void ShieldedCoulombForce::force2(const double currentTime)
{
	const __m128d v2 = _mm_set1_pd(2.0);
	for (unsigned int currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = _mm_load_pd(&cloud->x[currentParticle]) + _mm_load_pd(&cloud->l1[currentParticle])/v2;
		const __m128d vy1 = _mm_load_pd(&cloud->y[currentParticle]) + _mm_load_pd(&cloud->n1[currentParticle])/v2;
		double x1, x2, y1, y2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);

		force(currentParticle, currentParticle + 1, x1 - x2, y1 - y2);
		for(unsigned int i = currentParticle + 2; i < numParticles; i += 2)
		{
			const double *px2 = &cloud->x[i];
			const double *py2 = &cloud->y[i];
			const double *pl = &cloud->l1[i];
			const double *pn = &cloud->n1[i];

			force(currentParticle, i, vx1 - (_mm_load_pd(px2) + _mm_load_pd(pl)/v2),
				vy1 - (_mm_load_pd(py2) + _mm_load_pd(pn)/v2));

			forcer(currentParticle, i, vx1 - (_mm_loadr_pd(px2) + _mm_loadr_pd(pl)/v2),
				vy1 - (_mm_loadr_pd(py2) + _mm_loadr_pd(pn)/v2));
		}
	}
}

void ShieldedCoulombForce::force3(const double currentTime)
{
	const __m128d v2 = _mm_set1_pd(2.0);
	for (unsigned int currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = _mm_load_pd(&cloud->x[currentParticle]) + _mm_load_pd(&cloud->l2[currentParticle])/v2;
		const __m128d vy1 = _mm_load_pd(&cloud->y[currentParticle]) + _mm_load_pd(&cloud->n2[currentParticle])/v2;
		double x1, x2, y1, y2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);

		force(currentParticle, currentParticle + 1, x1 - x2, y1 - y2);
		for(unsigned int i = currentParticle + 2; i < numParticles; i += 2)
		{
			const double *px2 = &cloud->x[i];
			const double *py2 = &cloud->y[i];
			const double *pl = &cloud->l2[i];
			const double *pn = &cloud->n2[i];

			force(currentParticle, i, vx1 - (_mm_load_pd(px2) + _mm_load_pd(pl)/v2),
				vy1 - (_mm_load_pd(py2) + _mm_load_pd(pn)/v2));

			forcer(currentParticle, i, vx1 - (_mm_loadr_pd(px2) + _mm_loadr_pd(pl)/v2),
 				vy1 - (_mm_loadr_pd(py2) + _mm_loadr_pd(pn)/v2));
		}
	}
}

void ShieldedCoulombForce::force4(const double currentTime)
{
	for (unsigned int currentParticle = 0, numParticles = cloud->n, e = cloud->n - 1; currentParticle < e; currentParticle += 2)
	{
		const __m128d vx1 = _mm_load_pd(&cloud->x[currentParticle]) + _mm_load_pd(&cloud->l3[currentParticle]);
		const __m128d vy1 = _mm_load_pd(&cloud->y[currentParticle]) + _mm_load_pd(&cloud->n3[currentParticle]);
		double x1, x2, y1, y2;
		_mm_storel_pd(&x1, vx1);
		_mm_storeh_pd(&x2, vx1);
		_mm_storel_pd(&y1, vy1);
		_mm_storeh_pd(&y2, vy1);

		force(currentParticle, currentParticle + 1, x1 - x2, y1 - y2);
		for(unsigned int i = currentParticle + 2; i < numParticles; i += 2)
		{
			const double *px2 = &cloud->x[i];
			const double *py2 = &cloud->y[i];
			const double *pl = &cloud->l3[i];
			const double *pn = &cloud->n3[i];

			force(currentParticle, i, vx1 - (_mm_load_pd(px2) + _mm_load_pd(pl)),
				vy1 - (_mm_load_pd(py2) + _mm_load_pd(pn)));

			forcer(currentParticle, i, vx1 - (_mm_loadr_pd(px2) + _mm_loadr_pd(pl)),
 				vy1 - (_mm_loadr_pd(py2) + _mm_loadr_pd(pn)));
		}
	}
}

inline void ShieldedCoulombForce::force(const unsigned int currentParticle, const unsigned int iParticle, const double displacementX, const double displacementY)
{
	// Calculate displacement between particles.
	const double displacement = sqrt(displacementX*displacementX + displacementY*displacementY);
	const double valExp = displacement*shielding;

	if(valExp < 10.0) 	//restrict to 10*(ion debye length)
	{
		 //conclude force calculation:
		const double displacement3 = displacement*displacement*displacement;
		//set to charges multiplied by Coulomb's constant:
		const double exponential = (cloud->charge[currentParticle]*cloud->charge[iParticle])/(4.0*M_PI*8.85E-12)*(1.0 + valExp)/(displacement3*exp(valExp));
		cloud->forceX[currentParticle] += exponential*displacementX;
		cloud->forceY[currentParticle] += exponential*displacementY;

		//equal and opposite force:
		cloud->forceX[iParticle] -= exponential*displacementX;
		cloud->forceY[iParticle] -= exponential*displacementY;
	}
}

inline void ShieldedCoulombForce::force(const unsigned int currentParticle, const unsigned int iParticle, const __m128d displacementX, const __m128d displacementY)
{
	// Calculate displacement between particles.
	const __m128d displacement = _mm_sqrt_pd(displacementX*displacementX + displacementY*displacementY);
	const __m128d valExp = displacement*_mm_set_pd(shielding, shielding);

	double valExpL, valExpH;
	_mm_storel_pd(&valExpL, valExp);
	_mm_storeh_pd(&valExpH, valExp);

	const bool boolL = valExpL < 10.0;
	const bool boolH = valExpH < 10.0;
	if (!boolL && !boolH)
		return;

	double expL, expH;
	_mm_storel_pd(&expL, valExp);
	_mm_storeh_pd(&expH, valExp);

	__m128d expv = _mm_set_pd(boolH ? exp(-expH) : 0.0, //_mm_set_pd is backwards
							  boolL ? exp(-expL) : 0.0);

	//conclude force calculation:
	const __m128d displacement3 = displacement*displacement*displacement;
	//set to charges multiplied by Coulomb's constant:
	const double c = 4.0*M_PI*8.85E-12;
	const __m128d exponential = _mm_load_pd(&cloud->charge[currentParticle])*_mm_load_pd(&cloud->charge[iParticle])
		/_mm_set_pd(c, c)*(_mm_set1_pd(1.0) + valExp)/displacement3*expv;

	const __m128d forcevX = exponential*displacementX;
	const __m128d forcevY = exponential*displacementY;

	double *pFx = &cloud->forceX[currentParticle];
	double *pFy = &cloud->forceY[currentParticle];
	_mm_store_pd(pFx, _mm_load_pd(pFx) + forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) + forcevY);

	//equal and opposite force:
	pFx = &cloud->forceX[iParticle];
	pFy = &cloud->forceY[iParticle];
	_mm_store_pd(pFx, _mm_load_pd(pFx) - forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) - forcevY);
}

inline void ShieldedCoulombForce::forcer(const unsigned int currentParticle, const unsigned int iParticle, const __m128d displacementX, const __m128d displacementY)
{
	// Calculate displacement between particles.
	const __m128d displacement = _mm_sqrt_pd(displacementX*displacementX + displacementY*displacementY);
	const __m128d valExp = displacement*_mm_set_pd(shielding, shielding);

	double valExpL, valExpH;
	_mm_storel_pd(&valExpL, valExp);
	_mm_storeh_pd(&valExpH, valExp);

	const bool boolL = valExpL < 10.0;
	const bool boolH = valExpH < 10.0;
	if (!boolL && !boolH)
		return;

	double expL, expH;
	_mm_storel_pd(&expL, valExp);
	_mm_storeh_pd(&expH, valExp);

	__m128d expv = _mm_set_pd(boolH ? exp(-expH) : 0.0, //_mm_set_pd is backwards
							  boolL ? exp(-expL) : 0.0);

	//conclude force calculation:
	const __m128d displacement3 = displacement*displacement*displacement;
	//set to charges multiplied by Coulomb's constant:
	const double c = 4.0*M_PI*8.85e-12;
	const __m128d exponential = _mm_load_pd(&cloud->charge[currentParticle])*_mm_loadr_pd(&cloud->charge[iParticle])
		/_mm_set_pd(c, c)*(_mm_set1_pd(1.0) + valExp)/displacement3*expv;

	const __m128d forcevX = exponential*displacementX;
	const __m128d forcevY = exponential*displacementY;

	double *pFx = &cloud->forceX[currentParticle];
	double *pFy = &cloud->forceY[currentParticle];
	_mm_store_pd(pFx, _mm_load_pd(pFx) + forcevX);
	_mm_store_pd(pFy, _mm_load_pd(pFy) + forcevY);

	//equal and opposite force:
	pFx = &cloud->forceX[iParticle];
	pFy = &cloud->forceY[iParticle];
	_mm_storer_pd(pFx, _mm_loadr_pd(pFx) - forcevX);
	_mm_storer_pd(pFy, _mm_loadr_pd(pFy) - forcevY);
}

void ShieldedCoulombForce::writeForce(fitsfile * const file, int * const error) const
{
	//move to primary HDU:
	if(!*error)
		//file, # indicating primary HDU, HDU type, error
 		fits_movabs_hdu(file, 1, IMAGE_HDU, error);

	//add flag indicating that the drag force is used:
	if(!*error)
	{
		long forceFlags = 0;
		fits_read_key_lng(file, const_cast<char *> ("FORCES"), &forceFlags, NULL, error);

		//add ShieldedCoulombForce bit:
		forceFlags |= ShieldedCoulombForceFlag;		//compound bitwise OR

		if(*error == KEY_NO_EXIST || *error == VALUE_UNDEFINED)
			*error = 0;			//clear above error.

		//add or update keyword.
		if(!*error)
			fits_update_key(file, TLONG, const_cast<char *> ("FORCES"), &forceFlags, const_cast<char *> ("Force configuration."), error);
	}

	if(!*error)
		//file, key name, value, precision (scientific format), comment
		fits_write_key_dbl(file, const_cast<char *> ("shieldingConstant"), shielding, 6, const_cast<char *> ("[m^-1] (ShieldedCoulombForce)"), error);
}

void ShieldedCoulombForce::readForce(fitsfile * const file, int * const error)
{
	//move to primary HDU:
	if(!*error)
		//file, # indicating primary HDU, HDU type, error
 		fits_movabs_hdu(file, 1, IMAGE_HDU, error);

	if(!*error)
		//file, key name, value, don't read comment, error
		fits_read_key_dbl(file, const_cast<char *> ("shieldingConstant"), &shielding, NULL, error);
}
<|endoftext|>


<commit_before>#define DEBUG 1
/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 4/5/2020, 8:34:18 PM
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1000000007LL};
// constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint &operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint &operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}
// ----- main() -----

int main()
{
  vector<int> a(3);
  for (auto i = 0; i < 3; ++i)
  {
    cin >> a[i];
  }
  int N{a[0] + a[1] + a[2]};
  vector<int> V(N);
  for (auto i = 0; i < N; ++i)
  {
    V[i] = i;
  }
  int ans{0};
  do
  {
    vector<vector<int>> X(3, vector<int>(3, -1));
    auto it{V.begin()};
    for (auto i = 0; i < 3; ++i)
    {
      for (auto j = 0; j < a[i]; ++j)
      {
        X[i][j] = *it;
        it++;
      }
    }
    bool ok{true};
    for (auto i = 0; i < 3; ++i)
    {
      for (auto j = 0; j < 3; ++j)
      {
        if (X[i][j] == -1)
        {
          continue;
        }
        if (i + 1 < 3)
        {
          if (X[i + 1][j] == -1)
          {
          }
          else if (X[i][j] >= X[i + 1][j])
          {
            ok = false;
          }
        }
        if (j + 1 < 3)
        {
          if (X[i][j + 1] == -1)
          {
          }
          else if (X[i][j] >= X[i][j + 1])
          {
            ok = false;
          }
        }
      }
    }
    if (ok)
    {
      ++ans;
#if DEBUG == 1
      for (auto i = 0; i < 3; ++i)
      {
        for (auto j = 0; j < 3; ++j)
        {
          cerr << X[i][j] << " ";
        }
        cerr << endl;
      }
#endif
    }
  } while (next_permutation(V.begin(), V.end()));
  // cout << ans << endl;
}
<commit_msg>submit C.cpp to 'C - Numbering Blocks' (judge-update-202004) [C++ (GCC 9.2.1)]<commit_after>#define DEBUG 1
/**
 * File    : C.cpp
 * Author  : Kazune Takahashi
 * Created : 4/5/2020, 8:34:18 PM
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1000000007LL};
// constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint &operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint &operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}
// ----- main() -----

int main()
{
  vector<int> a(3);
  for (auto i = 0; i < 3; ++i)
  {
    cin >> a[i];
  }
  int N{a[0] + a[1] + a[2]};
  vector<int> V(N);
  for (auto i = 0; i < N; ++i)
  {
    V[i] = i;
  }
  int ans{0};
  do
  {
    vector<vector<int>> X(3, vector<int>(3, -1));
    auto it{V.begin()};
    for (auto i = 0; i < 3; ++i)
    {
      for (auto j = 0; j < a[i]; ++j)
      {
        X[i][j] = *it;
        it++;
      }
    }
    bool ok{true};
    for (auto i = 0; i < 3; ++i)
    {
      for (auto j = 0; j < 3; ++j)
      {
        if (X[i][j] == -1)
        {
          continue;
        }
        if (i + 1 < 3)
        {
          if (X[i + 1][j] == -1)
          {
          }
          else if (X[i][j] >= X[i + 1][j])
          {
            ok = false;
          }
        }
        if (j + 1 < 3)
        {
          if (X[i][j + 1] == -1)
          {
          }
          else if (X[i][j] >= X[i][j + 1])
          {
            ok = false;
          }
        }
      }
    }
    if (ok)
    {
      ++ans;
#if DEBUG == 1
      for (auto i = 0; i < 3; ++i)
      {
        for (auto j = 0; j < 3; ++j)
        {
          cerr << X[i][j] << " ";
        }
        cerr << endl;
      }
#endif
    }
  } while (next_permutation(V.begin(), V.end()));
  cout << ans << endl;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: glob.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2004-01-20 10:15:42 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SD_GLOB_HXX
#define SD_GLOB_HXX

#ifndef _SOLAR_H
#include <tools/solar.h>
#endif

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

#define DIA_SLOW    0
#define DIA_MEDIUM  1
#define DIA_FAST    2

#define SD_IF_SDAPP                     SFX_INTERFACE_SD_START + 0
#define SD_IF_SDDRAWDOCSHELL            SFX_INTERFACE_SD_START + 1
#define SD_IF_SDVIEWSHELL               SFX_INTERFACE_SD_START + 2
#define SD_IF_SDDRAWVIEWSHELL           SFX_INTERFACE_SD_START + 3
#define SD_IF_SDSLIDEVIEWSHELL          SFX_INTERFACE_SD_START + 4
#define SD_IF_SDOUTLINEVIEWSHELL        SFX_INTERFACE_SD_START + 5
#define SD_IF_SDDRAWSTDOBJECTBAR        SFX_INTERFACE_SD_START + 6
#define SD_IF_SDDRAWTEXTOBJECTBAR       SFX_INTERFACE_SD_START + 7
#define SD_IF_SDDRAWBEZIEROBJECTBAR     SFX_INTERFACE_SD_START + 8
#define SD_IF_SDDRAWGLUEPOINTSOBJECTBAR SFX_INTERFACE_SD_START + 9
#define SD_IF_SDGRAPHICDOCSHELL         SFX_INTERFACE_SD_START + 10
#define SD_IF_SDGRAPHICVIEWSHELL        SFX_INTERFACE_SD_START + 11
#define SD_IF_SDGRAPHICSTDOBJECTBAR     SFX_INTERFACE_SD_START + 12
#define SD_IF_SDDRAWGRAFOBJECTBAR       SFX_INTERFACE_SD_START + 13
#define SD_IF_SDPRESVIEWSHELL           SFX_INTERFACE_SD_START + 14
#define SD_IF_SDPREVIEWVIEWSHELL        SFX_INTERFACE_SD_START + 15
#define SD_IF_SDVIEWSHELLBASE           SFX_INTERFACE_SD_START + 16

// Inventor-Id fuer StarDraw UserData
const UINT32 SdUDInventor=UINT32('S')*0x00000001+
                          UINT32('D')*0x00000100+
                          UINT32('U')*0x00010000+
                          UINT32('D')*0x01000000;

// Object-Ids fuer StarDraw UserData
#define SD_ANIMATIONINFO_ID 1
#define SD_IMAPINFO_ID      2

// FamilyId der Praesentationsvorlagen
#define SD_LT_FAMILY (SfxStyleFamily)0xaffe

// Trennzeichen zwischen Layoutname und Vorlagenname der Praesentationsvorlagen
#define SD_LT_SEPARATOR "~LT~"

// Optionsstream-Identifier
#define SD_OPTION_MORPHING  "Morph"
#define SD_OPTION_VECTORIZE "Vectorize"

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

#endif // _SD_GLOB_HXX

<commit_msg>INTEGRATION: CWS sj05 (1.4.44); FILE MERGED 2004/02/13 14:48:58 sj 1.4.44.2: RESYNC: (1.4-1.5); FILE MERGED 2004/01/23 17:16:12 cl 1.4.44.1: #i20484# adding autoshape ui<commit_after>/*************************************************************************
 *
 *  $RCSfile: glob.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2004-04-02 13:19:09 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SD_GLOB_HXX
#define SD_GLOB_HXX

#ifndef _SOLAR_H
#include <tools/solar.h>
#endif

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

#define DIA_SLOW    0
#define DIA_MEDIUM  1
#define DIA_FAST    2

#define SD_IF_SDAPP                     SFX_INTERFACE_SD_START + 0
#define SD_IF_SDDRAWDOCSHELL            SFX_INTERFACE_SD_START + 1
#define SD_IF_SDVIEWSHELL               SFX_INTERFACE_SD_START + 2
#define SD_IF_SDDRAWVIEWSHELL           SFX_INTERFACE_SD_START + 3
#define SD_IF_SDSLIDEVIEWSHELL          SFX_INTERFACE_SD_START + 4
#define SD_IF_SDOUTLINEVIEWSHELL        SFX_INTERFACE_SD_START + 5
#define SD_IF_SDDRAWSTDOBJECTBAR        SFX_INTERFACE_SD_START + 6
#define SD_IF_SDDRAWTEXTOBJECTBAR       SFX_INTERFACE_SD_START + 7
#define SD_IF_SDDRAWBEZIEROBJECTBAR     SFX_INTERFACE_SD_START + 8
#define SD_IF_SDDRAWGLUEPOINTSOBJECTBAR SFX_INTERFACE_SD_START + 9
#define SD_IF_SDGRAPHICDOCSHELL         SFX_INTERFACE_SD_START + 10
#define SD_IF_SDGRAPHICVIEWSHELL        SFX_INTERFACE_SD_START + 11
#define SD_IF_SDGRAPHICSTDOBJECTBAR     SFX_INTERFACE_SD_START + 12
#define SD_IF_SDDRAWGRAFOBJECTBAR       SFX_INTERFACE_SD_START + 13
#define SD_IF_SDPRESVIEWSHELL           SFX_INTERFACE_SD_START + 14
#define SD_IF_SDPREVIEWVIEWSHELL        SFX_INTERFACE_SD_START + 15
#define SD_IF_SDVIEWSHELLBASE           SFX_INTERFACE_SD_START + 16
#define SD_IF_SD3DOBJECTBAR             SFX_INTERFACE_SD_START + 17
#define SD_IF_SDFONTWORKOBJECTBAR       SFX_INTERFACE_SD_START + 18

// Inventor-Id fuer StarDraw UserData
const UINT32 SdUDInventor=UINT32('S')*0x00000001+
                          UINT32('D')*0x00000100+
                          UINT32('U')*0x00010000+
                          UINT32('D')*0x01000000;

// Object-Ids fuer StarDraw UserData
#define SD_ANIMATIONINFO_ID 1
#define SD_IMAPINFO_ID      2

// FamilyId der Praesentationsvorlagen
#define SD_LT_FAMILY (SfxStyleFamily)0xaffe

// Trennzeichen zwischen Layoutname und Vorlagenname der Praesentationsvorlagen
#define SD_LT_SEPARATOR "~LT~"

// Optionsstream-Identifier
#define SD_OPTION_MORPHING  "Morph"
#define SD_OPTION_VECTORIZE "Vectorize"

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

#endif // _SD_GLOB_HXX

<|endoftext|>