<commit_before>//
// Created by gz on 6/11/16.
//

#include <lib/scheduler/scheduler.h>
#include <platform/panic.h>
#include <cstdio>
#include <platform/clock.h>
#include <lib/primitives/interrupts_mutex.h>
#include <lib/primitives/lock_guard.h>
#include <platform/process.h>
#include <lib/syscall/syscall.h>
#include <lib/scheduler/signals.h>
#include <cstring>

#define debug_log(msg, ...) if (_debugMode) kprintf(msg "\n", ##__VA_ARGS__)

static std::unique_ptr<ProcessScheduler> global_scheduler;

extern "C"
void scheduler_init(size_t initialProcSize, size_t initialQueueSize, init_main_t init_main, int argc, const char** argv)
{
    global_scheduler = std::make_unique<ProcessScheduler>(initialProcSize, initialQueueSize);

//    global_scheduler->setDebugMode();
    std::vector<const char*> arguments(argv, argv + argc);
    global_scheduler->createPreemptiveProcess("init", init_main, std::move(arguments), 4096);
//    syscall(0, "init", init_main, argc, argv, 4096);

    clock_set_handler(ProcessScheduler::onTickTimer, global_scheduler.get());
    interrupts_enable_all();
}

__attribute__((noreturn))
static int idleProcMain(int argc, const char** argv)
{
    kputs("Idle thread is running!\n");
    while (true);
}

ProcessScheduler::ProcessScheduler(size_t initialProcSize, size_t initialQueueSize)
    : _currentProc(nullptr),
      _responsiveQueue(initialQueueSize),
      _preemptiveQueue(initialQueueSize),
      _idleProc("IdleProc", idleProcMain, {}, 4096, Process::Type::Preemptive, DefaultPreemptiveQuantum),
      _processList(),
      _mutex()
{
    _processList.reserve(initialProcSize);
}

Process* ProcessScheduler::andTheWinnerIs(void)
{
    Process* newProc = nullptr;

    // first, try getting a task from _responsiveQueue
    if (_responsiveQueue.pop(newProc)) {
        debug_log("andTheWinnerIs: responsive newProc %p name %s", newProc, newProc->_name);
        return newProc;
    }

    // then try getting a task from _preemptiveQueue
    if (_preemptiveQueue.pop(newProc)) {
        debug_log("andTheWinnerIs: preemptive newProc %p name %s", newProc, newProc->_name);
        return newProc;
    }

    debug_log("andTheWinnerIs: idle proc");
    // and if that fails.. get the _idleProc...
    return &_idleProc;
}

// assumes _currentProc is non-null
Process* ProcessScheduler::handleResponsiveProc(void)
{
    if (_currentProc->_state == Process::State::YIELDING) {
        // choose a new proc before pushing current proc to responsive queue
        Process* newProc = this->andTheWinnerIs();

        // reset current proc and push to queue
        _currentProc->_quantum = _currentProc->_resetQuantum;
        _currentProc->_state = Process::State::READY;

        // if we picked the idle proc, it means we've got no one else to run but us.
        // then keep running
        if (newProc == &_idleProc) {
            newProc = _currentProc;
        } else {
            // but if we found some one else to actually run, queue us for later
            _responsiveQueue.push(_currentProc);
        }

        return newProc;
    }

    // if the process is a responsive one, keep it running until he yield()s
    // but if he passes the intentionally-very-long-quantum value, kill it.
    if (0 >= _currentProc->_quantum) {
        _currentProc->_exitCode = -127;
        _currentProc->_state = Process::State::TERMINATED;
        return this->andTheWinnerIs();
    }

    return _currentProc;
}

// assumes _currentProc is non-null
Process* ProcessScheduler::handlePreemptiveProc(void)
{
    auto currentQuantum = _currentProc->_quantum;

    debug_log("Current quantum: %d", currentQuantum);

    if (currentQuantum > 0) {
        return _currentProc;
    } else {
        // check if we're out of quantum
        _currentProc->_state = Process::State::READY;
        _currentProc->_quantum = _currentProc->_resetQuantum;
        _preemptiveQueue.push(_currentProc);
        debug_log("%s: out of quantum, rescheduling\n", _currentProc->_name);
    }

    return this->andTheWinnerIs();
}

struct user_regs* ProcessScheduler::schedule(struct user_regs* regs)
{
    lock_guard<spinlock_mutex> guard(_mutex);
    // a normal schedule starts here..
    // we've got an existing proc and a potential new one
    if (NULL != _currentProc)
    {
        // save current context
        _currentProc->_context = regs;
        // play the quantum card
        _currentProc->_quantum--;

        this->handleSignal(_currentProc);

        if (_currentProc->_state == Process::State::TERMINATED) {
            _currentProc = this->andTheWinnerIs();
            goto switch_to_proc;
        }

        if (_currentProc->_state == Process::State::SUSPENDED) {
            _currentProc = this->andTheWinnerIs();
            goto switch_to_proc;
        }

        // handle the actual switching logic
        switch (_currentProc->_type)
        {
            case Process::Responsive:
                _currentProc = this->handleResponsiveProc();
                break;

            case Process::Preemptive:
                _currentProc = this->handlePreemptiveProc();
                break;

            default:
                panic("%s: Unknown proc type %d", _currentProc->_name, _currentProc->_type);
        }

        goto switch_to_proc;
    }
    else
    {
        // first run, _currentProc is NULL and will be chosen for the first time! YAY!
        _currentProc = this->andTheWinnerIs();
        goto switch_to_proc;
    }

switch_to_proc:
    // return the context user_regs of the new/existing current proc entry
    _currentProc->_state = Process::State::RUNNING;
    platform_set_active_process_ctx(_currentProc->_pctx);
    return _currentProc->_context;
}

// assumes argument is non-null
struct user_regs *ProcessScheduler::onTickTimer(void *argument, struct user_regs *regs)
{
    ProcessScheduler* self = (ProcessScheduler*)argument;

    return self->schedule(regs);
}

pid_t ProcessScheduler::createPreemptiveProcess(const char *name, Process::EntryPointFunction main,
                                                std::vector<const char*>&& arguments, size_t stackSize, int initialQuantum)
{
    InterruptsMutex mutex;
    mutex.lock();

    std::unique_ptr<Process> newProc = std::make_unique<Process>(name, main, std::move(arguments),
                                                                 stackSize, Process::Type::Preemptive,
                                                                 initialQuantum);

    pid_t newPid = newProc->pid();
    _preemptiveQueue.push(newProc.get());
    _processList.push_back(std::move(newProc));
    return newPid;
}

pid_t ProcessScheduler::createResponsiveProcess(const char *name, Process::EntryPointFunction main,
                                                std::vector<const char*>&& arguments, size_t stackSize, int initialQuantum)
{
    InterruptsMutex mutex;
    mutex.lock();

    std::unique_ptr<Process> newProc = std::make_unique<Process>(name, main, std::move(arguments),
                                                                 stackSize, Process::Type::Responsive,
                                                                 initialQuantum);

    pid_t newPid = newProc->pid();
    _responsiveQueue.push(newProc.get());
    _processList.push_back(std::move(newProc));
    return newPid;
}

void ProcessScheduler::setDebugMode(void)
{
    lock_guard<spinlock_mutex> guard(_mutex);
    _debugMode = true;
}

struct user_regs *ProcessScheduler::yield(struct user_regs *regs)
{
    if (!_currentProc) {
        panic("wtf.. yielding with no current proc...");
    }

    _currentProc->_state = Process::State::YIELDING;
    return this->schedule(regs);
}

bool ProcessScheduler::signalProc(pid_t pid, int signal)
{
    Process* proc = this->getProcessByPid(pid);
    if (!proc) {
        return false;
    }

    if (Process::State::TERMINATED == proc->_state) {
        return false;
    }

    switch (signal)
    {
        case Signal::SIG_CONT:
        {
            proc->_quantum = proc->_resetQuantum;
            proc->_state = Process::State::READY;

            switch (proc->_type) {
                case Process::Responsive:
                    _responsiveQueue.push(proc);
                    break;
                case Process::Preemptive:
                    _preemptiveQueue.push(proc);
                    break;
            }

            return true;
        }

        default:
            return proc->signal(signal);
    }
}

Process* ProcessScheduler::getProcessByPid(pid_t pid) const
{
    for (const auto& proc : _processList)
    {
        if (proc->pid() != pid) {
            continue;
        }

        return proc.get();
    }

    return nullptr;
}

void ProcessScheduler::handleSignal(Process *proc)
{
    const int sig_nr = proc->_pending_signal_nr.exchange(SIG_NONE);

    switch (sig_nr)
    {
        case SIG_KILL:
            proc->_exitCode = -127;
            proc->_state = Process::State::TERMINATED;
            break;

        case SIG_STOP:
            proc->_state = Process::State::SUSPENDED;
            break;

        case SIG_NONE:
            break;

        default:
            kprintf("%s: unknown signal received %d\n", proc->name(), sig_nr);
            break;
    }
}

DEFINE_SYSCALL(SYS_NR_CREATE_PREEMPTIVE_PROC, create_preemptive_process)
{
    SYSCALL_ARG(const char*, name);
    SYSCALL_ARG(Process::EntryPointFunction, main);
    SYSCALL_ARG(int, argc);
    SYSCALL_ARG(const char**, argv);
    SYSCALL_ARG(size_t, stackSize);

    std::vector<const char*> arguments(argv, argv + argc);
    return global_scheduler->createPreemptiveProcess(name, main, std::move(arguments), stackSize);
}

DEFINE_SYSCALL(SYS_NR_CREATE_RESPONSIVE_PROC, create_responsive_process)
{
    SYSCALL_ARG(const char*, name);
    SYSCALL_ARG(Process::EntryPointFunction, main);
    SYSCALL_ARG(int, argc);
    SYSCALL_ARG(const char**, argv);
    SYSCALL_ARG(size_t, stackSize);

    std::vector<const char*> arguments(argv, argv + argc);
    return global_scheduler->createResponsiveProcess(name, main, std::move(arguments), stackSize);
}

DEFINE_SYSCALL(SYS_NR_GET_PID, get_pid)
{
    return global_scheduler->getCurrentPid();
}

DEFINE_SYSCALL(SYS_NR_YIELD, yield)
{
    *regs = global_scheduler->yield(*regs);
    return 0;
}

DEFINE_SYSCALL(SYS_NR_SIGNAL, signal)
{
    SYSCALL_ARG(pid_t, pid);
    SYSCALL_ARG(int, signal_nr);

    if (!global_scheduler->signalProc(pid, signal_nr)) {
        return -1;
    }

    return 0;
}

static const char* g_states[] = {
        "Ready",
        "Running",
        "Suspended",
        "Yielding",
        "Terminated"
};

static const char* g_types[] = {
        "Responsive",
        "Preemptive"
};

static bool fill_ps_ent(const Process* proc, struct ps_ent* ent, size_t size_left)
{
    if (sizeof(struct ps_ent) > size_left) {
        return false;
    }

    ent->pid = proc->pid();
    ent->exit_code = proc->exit_code();
    ent->state = g_states[proc->state()];
    ent->type = g_types[proc->type()];
    strncpy(ent->name, proc->name(), sizeof(ent->name));

    return true;
}

DEFINE_SYSCALL(SYS_NR_PS, ps)
{
    SYSCALL_ARG(uint8_t*, buffer);
    SYSCALL_ARG(size_t, size);

    if (nullptr == buffer || size <= 0) {
        return -1;
    }

    size_t buf_pos = sizeof(struct ps_ent);
    int entries = 1;
    if (!fill_ps_ent(&global_scheduler->_idleProc, (struct ps_ent *)buffer, size)) {
        return 0;
    }

    const auto& procList = global_scheduler->processList();
    auto list_pos = procList.cbegin();
    while ((buf_pos < size) && (list_pos != procList.cend())) {
        const auto proc = list_pos->get();
        struct ps_ent* ent = (struct ps_ent*)(buffer + buf_pos);
        if (!fill_ps_ent(proc, ent, size - buf_pos)) {
            break;
        }

        entries++;
        list_pos++;
        buf_pos += sizeof(struct ps_ent);
    }

    return entries;
}
<commit_msg>Added comments to clarify signals handeling (delivery handeling vs runtime handling)<commit_after>//
// Created by gz on 6/11/16.
//

#include <lib/scheduler/scheduler.h>
#include <platform/panic.h>
#include <cstdio>
#include <platform/clock.h>
#include <lib/primitives/interrupts_mutex.h>
#include <lib/primitives/lock_guard.h>
#include <platform/process.h>
#include <lib/syscall/syscall.h>
#include <lib/scheduler/signals.h>
#include <cstring>

#define debug_log(msg, ...) if (_debugMode) kprintf(msg "\n", ##__VA_ARGS__)

static std::unique_ptr<ProcessScheduler> global_scheduler;

extern "C"
void scheduler_init(size_t initialProcSize, size_t initialQueueSize, init_main_t init_main, int argc, const char** argv)
{
    global_scheduler = std::make_unique<ProcessScheduler>(initialProcSize, initialQueueSize);

//    global_scheduler->setDebugMode();
    std::vector<const char*> arguments(argv, argv + argc);
    global_scheduler->createPreemptiveProcess("init", init_main, std::move(arguments), 4096);
//    syscall(0, "init", init_main, argc, argv, 4096);

    clock_set_handler(ProcessScheduler::onTickTimer, global_scheduler.get());
    interrupts_enable_all();
}

__attribute__((noreturn))
static int idleProcMain(int argc, const char** argv)
{
    kputs("Idle thread is running!\n");
    while (true);
}

ProcessScheduler::ProcessScheduler(size_t initialProcSize, size_t initialQueueSize)
    : _currentProc(nullptr),
      _responsiveQueue(initialQueueSize),
      _preemptiveQueue(initialQueueSize),
      _idleProc("IdleProc", idleProcMain, {}, 4096, Process::Type::Preemptive, DefaultPreemptiveQuantum),
      _processList(),
      _mutex()
{
    _processList.reserve(initialProcSize);
}

Process* ProcessScheduler::andTheWinnerIs(void)
{
    Process* newProc = nullptr;

    // first, try getting a task from _responsiveQueue
    if (_responsiveQueue.pop(newProc)) {
        debug_log("andTheWinnerIs: responsive newProc %p name %s", newProc, newProc->_name);
        return newProc;
    }

    // then try getting a task from _preemptiveQueue
    if (_preemptiveQueue.pop(newProc)) {
        debug_log("andTheWinnerIs: preemptive newProc %p name %s", newProc, newProc->_name);
        return newProc;
    }

    debug_log("andTheWinnerIs: idle proc");
    // and if that fails.. get the _idleProc...
    return &_idleProc;
}

// assumes _currentProc is non-null
Process* ProcessScheduler::handleResponsiveProc(void)
{
    if (_currentProc->_state == Process::State::YIELDING) {
        // choose a new proc before pushing current proc to responsive queue
        Process* newProc = this->andTheWinnerIs();

        // reset current proc and push to queue
        _currentProc->_quantum = _currentProc->_resetQuantum;
        _currentProc->_state = Process::State::READY;

        // if we picked the idle proc, it means we've got no one else to run but us.
        // then keep running
        if (newProc == &_idleProc) {
            newProc = _currentProc;
        } else {
            // but if we found some one else to actually run, queue us for later
            _responsiveQueue.push(_currentProc);
        }

        return newProc;
    }

    // if the process is a responsive one, keep it running until he yield()s
    // but if he passes the intentionally-very-long-quantum value, kill it.
    if (0 >= _currentProc->_quantum) {
        _currentProc->_exitCode = -127;
        _currentProc->_state = Process::State::TERMINATED;
        return this->andTheWinnerIs();
    }

    return _currentProc;
}

// assumes _currentProc is non-null
Process* ProcessScheduler::handlePreemptiveProc(void)
{
    auto currentQuantum = _currentProc->_quantum;

    debug_log("Current quantum: %d", currentQuantum);

    if (currentQuantum > 0) {
        return _currentProc;
    } else {
        // check if we're out of quantum
        _currentProc->_state = Process::State::READY;
        _currentProc->_quantum = _currentProc->_resetQuantum;
        _preemptiveQueue.push(_currentProc);
        debug_log("%s: out of quantum, rescheduling\n", _currentProc->_name);
    }

    return this->andTheWinnerIs();
}

struct user_regs* ProcessScheduler::schedule(struct user_regs* regs)
{
    lock_guard<spinlock_mutex> guard(_mutex);
    // a normal schedule starts here..
    // we've got an existing proc and a potential new one
    if (NULL != _currentProc)
    {
        // save current context
        _currentProc->_context = regs;
        // play the quantum card
        _currentProc->_quantum--;

        this->handleSignal(_currentProc);

        if (_currentProc->_state == Process::State::TERMINATED) {
            _currentProc = this->andTheWinnerIs();
            goto switch_to_proc;
        }

        if (_currentProc->_state == Process::State::SUSPENDED) {
            _currentProc = this->andTheWinnerIs();
            goto switch_to_proc;
        }

        // handle the actual switching logic
        switch (_currentProc->_type)
        {
            case Process::Responsive:
                _currentProc = this->handleResponsiveProc();
                break;

            case Process::Preemptive:
                _currentProc = this->handlePreemptiveProc();
                break;

            default:
                panic("%s: Unknown proc type %d", _currentProc->_name, _currentProc->_type);
        }

        goto switch_to_proc;
    }
    else
    {
        // first run, _currentProc is NULL and will be chosen for the first time! YAY!
        _currentProc = this->andTheWinnerIs();
        goto switch_to_proc;
    }

switch_to_proc:
    // return the context user_regs of the new/existing current proc entry
    _currentProc->_state = Process::State::RUNNING;
    platform_set_active_process_ctx(_currentProc->_pctx);
    return _currentProc->_context;
}

// assumes argument is non-null
struct user_regs *ProcessScheduler::onTickTimer(void *argument, struct user_regs *regs)
{
    ProcessScheduler* self = (ProcessScheduler*)argument;

    return self->schedule(regs);
}

pid_t ProcessScheduler::createPreemptiveProcess(const char *name, Process::EntryPointFunction main,
                                                std::vector<const char*>&& arguments, size_t stackSize, int initialQuantum)
{
    InterruptsMutex mutex;
    mutex.lock();

    std::unique_ptr<Process> newProc = std::make_unique<Process>(name, main, std::move(arguments),
                                                                 stackSize, Process::Type::Preemptive,
                                                                 initialQuantum);

    pid_t newPid = newProc->pid();
    _preemptiveQueue.push(newProc.get());
    _processList.push_back(std::move(newProc));
    return newPid;
}

pid_t ProcessScheduler::createResponsiveProcess(const char *name, Process::EntryPointFunction main,
                                                std::vector<const char*>&& arguments, size_t stackSize, int initialQuantum)
{
    InterruptsMutex mutex;
    mutex.lock();

    std::unique_ptr<Process> newProc = std::make_unique<Process>(name, main, std::move(arguments),
                                                                 stackSize, Process::Type::Responsive,
                                                                 initialQuantum);

    pid_t newPid = newProc->pid();
    _responsiveQueue.push(newProc.get());
    _processList.push_back(std::move(newProc));
    return newPid;
}

void ProcessScheduler::setDebugMode(void)
{
    lock_guard<spinlock_mutex> guard(_mutex);
    _debugMode = true;
}

struct user_regs *ProcessScheduler::yield(struct user_regs *regs)
{
    if (!_currentProc) {
        panic("wtf.. yielding with no current proc...");
    }

    _currentProc->_state = Process::State::YIELDING;
    return this->schedule(regs);
}

bool ProcessScheduler::signalProc(pid_t pid, int signal)
{
    Process* proc = this->getProcessByPid(pid);
    if (!proc) {
        return false;
    }

    if (Process::State::TERMINATED == proc->_state) {
        return false;
    }

    // handle signals that need to be taken care of before then get to the running process..
    switch (signal)
    {
        case Signal::SIG_CONT:
        {
            proc->_quantum = proc->_resetQuantum;
            proc->_state = Process::State::READY;

            switch (proc->_type) {
                case Process::Responsive:
                    _responsiveQueue.push(proc);
                    break;
                case Process::Preemptive:
                    _preemptiveQueue.push(proc);
                    break;
            }

            return true;
        }

        default:
            return proc->signal(signal);
    }
}

Process* ProcessScheduler::getProcessByPid(pid_t pid) const
{
    for (const auto& proc : _processList)
    {
        if (proc->pid() != pid) {
            continue;
        }

        return proc.get();
    }

    return nullptr;
}

// handle signal as it gets to the running process.
void ProcessScheduler::handleSignal(Process *proc)
{
    const int sig_nr = proc->_pending_signal_nr.exchange(SIG_NONE);

    switch (sig_nr)
    {
        case SIG_KILL:
            proc->_exitCode = -127;
            proc->_state = Process::State::TERMINATED;
            break;

        case SIG_STOP:
            proc->_state = Process::State::SUSPENDED;
            break;

        case SIG_NONE:
            break;

        default:
            kprintf("%s: unknown signal received %d\n", proc->name(), sig_nr);
            break;
    }
}

DEFINE_SYSCALL(SYS_NR_CREATE_PREEMPTIVE_PROC, create_preemptive_process)
{
    SYSCALL_ARG(const char*, name);
    SYSCALL_ARG(Process::EntryPointFunction, main);
    SYSCALL_ARG(int, argc);
    SYSCALL_ARG(const char**, argv);
    SYSCALL_ARG(size_t, stackSize);

    std::vector<const char*> arguments(argv, argv + argc);
    return global_scheduler->createPreemptiveProcess(name, main, std::move(arguments), stackSize);
}

DEFINE_SYSCALL(SYS_NR_CREATE_RESPONSIVE_PROC, create_responsive_process)
{
    SYSCALL_ARG(const char*, name);
    SYSCALL_ARG(Process::EntryPointFunction, main);
    SYSCALL_ARG(int, argc);
    SYSCALL_ARG(const char**, argv);
    SYSCALL_ARG(size_t, stackSize);

    std::vector<const char*> arguments(argv, argv + argc);
    return global_scheduler->createResponsiveProcess(name, main, std::move(arguments), stackSize);
}

DEFINE_SYSCALL(SYS_NR_GET_PID, get_pid)
{
    return global_scheduler->getCurrentPid();
}

DEFINE_SYSCALL(SYS_NR_YIELD, yield)
{
    *regs = global_scheduler->yield(*regs);
    return 0;
}

DEFINE_SYSCALL(SYS_NR_SIGNAL, signal)
{
    SYSCALL_ARG(pid_t, pid);
    SYSCALL_ARG(int, signal_nr);

    if (!global_scheduler->signalProc(pid, signal_nr)) {
        return -1;
    }

    return 0;
}

static const char* g_states[] = {
        "Ready",
        "Running",
        "Suspended",
        "Yielding",
        "Terminated"
};

static const char* g_types[] = {
        "Responsive",
        "Preemptive"
};

static bool fill_ps_ent(const Process* proc, struct ps_ent* ent, size_t size_left)
{
    if (sizeof(struct ps_ent) > size_left) {
        return false;
    }

    ent->pid = proc->pid();
    ent->exit_code = proc->exit_code();
    ent->state = g_states[proc->state()];
    ent->type = g_types[proc->type()];
    strncpy(ent->name, proc->name(), sizeof(ent->name));

    return true;
}

DEFINE_SYSCALL(SYS_NR_PS, ps)
{
    SYSCALL_ARG(uint8_t*, buffer);
    SYSCALL_ARG(size_t, size);

    if (nullptr == buffer || size <= 0) {
        return -1;
    }

    size_t buf_pos = sizeof(struct ps_ent);
    int entries = 1;
    if (!fill_ps_ent(&global_scheduler->_idleProc, (struct ps_ent *)buffer, size)) {
        return 0;
    }

    const auto& procList = global_scheduler->processList();
    auto list_pos = procList.cbegin();
    while ((buf_pos < size) && (list_pos != procList.cend())) {
        const auto proc = list_pos->get();
        struct ps_ent* ent = (struct ps_ent*)(buffer + buf_pos);
        if (!fill_ps_ent(proc, ent, size - buf_pos)) {
            break;
        }

        entries++;
        list_pos++;
        buf_pos += sizeof(struct ps_ent);
    }

    return entries;
}
<|endoftext|>


<commit_before>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "echo-client.h"
#include <iostream>
#include <pthread.h>
#include <signal.h>

using namespace std;

static const char *ECHO_SERVER_NAME = "org.freedesktop.DBus.Examples.Echo";
static const char *ECHO_SERVER_PATH = "/org/freedesktop/DBus/Examples/Echo";

EchoClient::EchoClient(DBus::Connection &connection, const char *path, const char *name)
: DBus::ObjectProxy(connection, path, name)
{
}

void EchoClient::Echoed(const DBus::Variant &value)
{
	cout << "!";
}

/*
 * For some strange reason, libdbus frequently dies with an OOM
 */

static const int THREADS = 3;

static bool spin = true;

void *greeter_thread(void *arg)
{
	DBus::Connection *conn = reinterpret_cast<DBus::Connection *>(arg);

	EchoClient client(*conn, ECHO_SERVER_PATH, ECHO_SERVER_NAME);

	char idstr[16];

	snprintf(idstr, sizeof(idstr), "%lu", pthread_self());

	for (int i = 0; i < 30 && spin; ++i)
	{
		cout << client.Hello(idstr) << endl;
	}

	cout << idstr << " done " << endl;

	return NULL;
}

DBus::BusDispatcher dispatcher;

void niam(int sig)
{
	spin = false;

	dispatcher.leave();
}

int main()
{
	signal(SIGTERM, niam);
	signal(SIGINT, niam);

	DBus::_init_threading();

	DBus::default_dispatcher = &dispatcher;

	DBus::Connection conn = DBus::Connection::SessionBus();

	pthread_t threads[THREADS];

	for (int i = 0; i < THREADS; ++i)
	{
		pthread_create(threads+i, NULL, greeter_thread, &conn);
	}

	dispatcher.enter();

	cout << "terminating" << endl;

	for (int i = 0; i < THREADS; ++i)
	{
		pthread_join(threads[i], NULL);
	}

	return 0;
}
<commit_msg>Missing header for gcc 4.4<commit_after>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "echo-client.h"
#include <iostream>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>

using namespace std;

static const char *ECHO_SERVER_NAME = "org.freedesktop.DBus.Examples.Echo";
static const char *ECHO_SERVER_PATH = "/org/freedesktop/DBus/Examples/Echo";

EchoClient::EchoClient(DBus::Connection &connection, const char *path, const char *name)
: DBus::ObjectProxy(connection, path, name)
{
}

void EchoClient::Echoed(const DBus::Variant &value)
{
	cout << "!";
}

/*
 * For some strange reason, libdbus frequently dies with an OOM
 */

static const int THREADS = 3;

static bool spin = true;

void *greeter_thread(void *arg)
{
	DBus::Connection *conn = reinterpret_cast<DBus::Connection *>(arg);

	EchoClient client(*conn, ECHO_SERVER_PATH, ECHO_SERVER_NAME);

	char idstr[16];

	snprintf(idstr, sizeof(idstr), "%lu", pthread_self());

	for (int i = 0; i < 30 && spin; ++i)
	{
		cout << client.Hello(idstr) << endl;
	}

	cout << idstr << " done " << endl;

	return NULL;
}

DBus::BusDispatcher dispatcher;

void niam(int sig)
{
	spin = false;

	dispatcher.leave();
}

int main()
{
	signal(SIGTERM, niam);
	signal(SIGINT, niam);

	DBus::_init_threading();

	DBus::default_dispatcher = &dispatcher;

	DBus::Connection conn = DBus::Connection::SessionBus();

	pthread_t threads[THREADS];

	for (int i = 0; i < THREADS; ++i)
	{
		pthread_create(threads+i, NULL, greeter_thread, &conn);
	}

	dispatcher.enter();

	cout << "terminating" << endl;

	for (int i = 0; i < THREADS; ++i)
	{
		pthread_join(threads[i], NULL);
	}

	return 0;
}
<|endoftext|>


<commit_before>#include "planetsuniverse.h"
#include "planet.h"
#include <chrono>
#include <glm/gtx/norm.hpp>
#include <glm/gtx/vector_query.hpp>
#include <glm/gtx/fast_square_root.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/random.hpp>
#include <cstdio>

#ifndef EMSCRIPTEN
#include <tinyxml.h>
#endif

#define RGB_MASK 0x00ffffff

using std::uniform_int_distribution;
using std::uniform_real_distribution;

PlanetsUniverse::PlanetsUniverse() : generator(std::chrono::system_clock::now().time_since_epoch().count()) { }

#ifndef EMSCRIPTEN
int PlanetsUniverse::load(const std::string& filename, bool clear) {
    TiXmlDocument doc(filename);

    if (!doc.LoadFile())
        throw std::runtime_error("Unable to load file \"" + filename + "\"!\n" + doc.ErrorDesc());

    TiXmlElement* root = doc.FirstChildElement("planets-3d-universe");
    if (root == nullptr)
        throw std::runtime_error("\"" + filename + "\" is not a valid universe file!");

    if (clear)
        deleteAll();

    int loaded = 0;

    for (TiXmlElement* element = root->FirstChildElement(); element != nullptr; element = element->NextSiblingElement()) {
        if (element->ValueStr() == "planet") {
            Planet planet;
            planet.setMass(std::stof(element->Attribute("mass")));

            key_type color = 0;

            try {
                std::string colorStr = element->Attribute("color");
                colorStr.replace(0, 1, "");
                color = std::stoul(colorStr, nullptr, 16);
            } catch(...) { /* Just ignore if it doesn't work. It isn't that critical. */ }

            for (TiXmlElement* sub = element->FirstChildElement(); sub != nullptr; sub = sub->NextSiblingElement()) {
                if (sub->ValueStr() == "position")
                    planet.position = glm::vec3(std::stof(sub->Attribute("x")),
                                                std::stof(sub->Attribute("y")),
                                                std::stof(sub->Attribute("z")));
                else if (sub->ValueStr() == "velocity")
                    planet.velocity = glm::vec3(std::stof(sub->Attribute("x")),
                                                std::stof(sub->Attribute("y")),
                                                std::stof(sub->Attribute("z"))) * velocityfac;
            }
            addPlanet(planet, color);
            ++loaded;
        }
    }

    return loaded;
}

void PlanetsUniverse::save(const std::string& filename) {
    TiXmlDocument doc;

    doc.LinkEndChild(new TiXmlDeclaration("1.0", "", ""));

    TiXmlElement* root = new TiXmlElement("planets-3d-universe");

    for (const_iterator i = planets.cbegin(); i != planets.cend(); ++i) {
        TiXmlElement* planet = new TiXmlElement("planet");
        planet->SetAttribute("mass", std::to_string(i->second.mass()));

        /* Puts uint32_t key into hexadecimal format #RRGGBB (No need to save alpha, as that's always 0xff) */
        const char* hex = "0123456789abcdef";
        planet->SetAttribute("color", std::string{'#',
                                                  hex[i->first >> 20 & 0xf],
                                                  hex[i->first >> 16 & 0xf],
                                                  hex[i->first >> 12 & 0xf],
                                                  hex[i->first >>  8 & 0xf],
                                                  hex[i->first >>  4 & 0xf],
                                                  hex[i->first       & 0xf]});

        TiXmlElement* position = new TiXmlElement("position");
        position->SetAttribute("x", std::to_string(i->second.position.x));
        position->SetAttribute("y", std::to_string(i->second.position.y));
        position->SetAttribute("z", std::to_string(i->second.position.z));
        planet->LinkEndChild(position);

        TiXmlElement* velocity = new TiXmlElement("velocity");
        velocity->SetAttribute("x", std::to_string(i->second.velocity.x / velocityfac));
        velocity->SetAttribute("y", std::to_string(i->second.velocity.y / velocityfac));
        velocity->SetAttribute("z", std::to_string(i->second.velocity.z / velocityfac));
        planet->LinkEndChild(velocity);

        root->LinkEndChild(planet);
    }

    doc.LinkEndChild(root);

    if (!doc.SaveFile(filename))
        throw std::runtime_error(doc.ErrorDesc());
}
#endif

void PlanetsUniverse::advance(float time) {
    time *= simspeed;
    time /= stepsPerFrame;

    for (int s = 0; s < stepsPerFrame; ++s) {
        iterator i = planets.begin();
        while (i != planets.end()) {
            /* In case there are planets with negative or empty mass for some reason, we don't want them messing things up. */
            if (i->second.mass() <= 0.0f) {
                i = planets.erase(i);
            } else {
                /* We only have to run this for planets after the current one,
                 * because all the planets before this have already been calculated with this one. */
                iterator o = i; ++o;

                while (o != planets.end()) {
                    glm::vec3 direction = o->second.position - i->second.position;
                    float distancesqr = glm::length2(direction);

                    /* Planets are close enough to merge. */
                    if (distancesqr < glm::pow(i->second.radius() + o->second.radius(), 2.0f)) {
                        /* Set the position and velocity to the wieghted average between the planets. */
                        i->second.position = o->second.position * o->second.mass() + i->second.position * i->second.mass();
                        i->second.velocity = o->second.velocity * o->second.mass() + i->second.velocity * i->second.mass();
                        i->second.setMass(i->second.mass() + o->second.mass());
                        i->second.position /= i->second.mass();
                        i->second.velocity /= i->second.mass();

                        /* If the one we're deleting happens to be selected, select the remaining planet. */
                        if (o->first == selected)
                            selected = i->first;
                        /* If the planet being followed happens to be the one being deleted, follow the remaining planet. */
                        if (o->first == following)
                            following = i->first;

                        /* The path would be invalid after this. */
                        i->second.path.clear();
                        o = planets.erase(o);
                    } else {
                        /* The gravity math to calculate the force between the planets. */
                        direction *= gravityconst * time * ((o->second.mass() * i->second.mass()) / distancesqr) * glm::fastInverseSqrt(distancesqr);

                        /* Apply the force to the velocity of both planets. */
                        i->second.velocity += direction / i->second.mass();
                        o->second.velocity -= direction / o->second.mass();

                        /* Keep going. (Not in for loop because of the possibility of erase() getting called.) */
                        ++o;
                    }
                }

                /* Apply the velocity to the position of the planet and update the path. */
                i->second.position += i->second.velocity * time;
                i->second.updatePath(pathLength, pathRecordDistance);

                /* Onward! (Same situation as with ++o above.) */
                ++i;
            }
        }
    }
}

key_type PlanetsUniverse::addPlanet(const Planet& planet, key_type keyHint) {
    uniform_int_distribution<key_type> color_gen(0xFF000001, 0xFFFFFFFF);

    /* Keep generating until we find an unused key. */
    while (planets.count(keyHint) > 0 || (keyHint & RGB_MASK) == 0)
        keyHint = color_gen(generator);

    planets[keyHint] = planet;
    return keyHint;
}

void PlanetsUniverse::generateRandom(const int& count, const float& positionRange, const float& maxVelocity, const float& maxMass) {
    uniform_real_distribution<float> position(-positionRange, positionRange);
    uniform_real_distribution<float> velocity(-maxVelocity, maxVelocity);
    uniform_real_distribution<float> mass(min_mass, maxMass);

    for (int i = 0; i < count; ++i)
        addPlanet(Planet(glm::vec3(position(generator), position(generator), position(generator)),
                         glm::vec3(velocity(generator), velocity(generator), velocity(generator)),
                         mass(generator)));
}

/* TODO - This function currently does not account for other planets.
 * Doing so would be very complicated. IDK if it'd even be possible... I'll have to look into it sometime. */
key_type PlanetsUniverse::addOrbital(Planet& around, const float& radius, const float& mass, const glm::mat4& plane) {
    /* Calculate the speed based on gravitational force and distance. */
    float speed = sqrt((around.mass() * around.mass() * gravityconst) / ((around.mass() + mass) * radius));

    /* Velocity is the y column of the plane matrix * speed. */
    glm::vec3 velocity = glm::vec3(plane[1]) * speed;

    /* The x column is the relative position of the orbiting planet. */
    key_type planet = addPlanet(Planet(around.position + glm::vec3(plane[0]) * radius, around.velocity + velocity, mass));

    /* Apply force on the planet being orbited in the opposite direction of the resulting planets velocity. */
    around.velocity -= velocity * (mass / around.mass());

    return planet;
}

void PlanetsUniverse::generateRandomOrbital(const int& count, key_type target) {
    /* We need a planet to orbit around. */
    if (!isEmpty()) {
        /* Ensure we have a valid target planet, if none was provided select at random. */
        if (!isValid(target))
            target = getRandomPlanet();

        Planet &around = planets[target];

        uniform_real_distribution<float> angle(-glm::pi<float>(), glm::pi<float>());
        uniform_real_distribution<float> radius(around.radius() * 1.5f, around.radius() * 80.0f);
        uniform_real_distribution<float> mass(min_mass, around.mass() * 0.2f);

        for (int i = 0; i < count; ++i) {
            glm::mat4 plane;
            /* This is sort of a cheap way of making a random orbit plane. */
            plane *= glm::rotate(angle(generator), glm::sphericalRand(1.0f));
            plane *= glm::rotate(angle(generator), glm::sphericalRand(1.0f));
            addOrbital(around, radius(generator), mass(generator), plane);
        }
    }
}

void PlanetsUniverse::deleteEscapees() {
    /* We delete anything too far from the weighted average position. */
    glm::vec3 averagePosition;
    float totalMass = 0.0f;

    for (const auto& planet : planets) {
        averagePosition += planet.second.position * planet.second.mass();
        totalMass += planet.second.mass();
    }

    averagePosition /= totalMass;

    /* The squared distance from the center outside of which we delete things. */
    const float limits2 = 1.0e12f;

    for (iterator i = planets.begin(); i != planets.end();) {
        if (glm::distance2(i->second.position, averagePosition) > limits2)
            i = planets.erase(i);
        else
            ++i;
    }
}

key_type PlanetsUniverse::getRandomPlanet() {
    if (isEmpty())
        return 0;

    uniform_int_distribution<list_type::size_type> random_n(0, size() - 1);
    auto iter = begin();
    std::advance(iter, random_n(generator));

    return iter->first;
}

key_type PlanetsUniverse::nextKey(key_type key) const {
    if (!isEmpty()) {
        const_iterator current = find(key);

        if (current == cend() || ++current == cend())
            /* If the planet was not found or the planet was the last in the list, start at the beginning. */
            current = cbegin();

        /* Get the key back from the iterator. */
        return current->first;
    }

    return 0;
}

key_type PlanetsUniverse::prevKey(key_type key) const {
    if (!isEmpty()) {
        const_iterator current = find(key);

        if (current == cend()) {
            /* If the planet was not found, start at the beginning. */
            current = cbegin();
        } else {
            /* If the planet was the first planet in the list, start at the end. */
            if (current == cbegin())
                current = cend();
            --current;
        }

        /* Get the key back from the iterator. */
        return current->first;
    }

    return 0;
}

void PlanetsUniverse::centerAll() {
    /* We need the weighted average position and velocity to center. */
    glm::vec3 averagePosition, averageVelocity;
    float totalMass = 0.0f;

    for (const auto& planet : planets) {
        averagePosition += planet.second.position * planet.second.mass();
        averageVelocity += planet.second.velocity * planet.second.mass();
        totalMass += planet.second.mass();
    }

    averagePosition /= totalMass;
    averageVelocity /= totalMass;

    const float epsilon = glm::epsilon<float>();

    /* Don't bother centering if we're already reasonably centered. */
    if (!glm::isNull(averagePosition, epsilon) || !glm::isNull(averageVelocity, epsilon)) {
        for (auto& planet : planets) {
            planet.second.position -= averagePosition;
            planet.second.velocity -= averageVelocity;
            planet.second.path.clear();
        }
    }
}
<commit_msg>Lib: cleanup/comments planetsuniverse.cpp.<commit_after>#include "planetsuniverse.h"
#include "planet.h"
#include <chrono>
#include <glm/gtx/norm.hpp>
#include <glm/gtx/vector_query.hpp>
#include <glm/gtx/fast_square_root.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/random.hpp>
#include <cstdio>

#ifndef EMSCRIPTEN
#include <tinyxml.h>
#endif

#define RGB_MASK 0x00ffffff

using std::uniform_int_distribution;
using std::uniform_real_distribution;

PlanetsUniverse::PlanetsUniverse() : generator(std::chrono::system_clock::now().time_since_epoch().count()) { }

/* Emscripten does IO from javascript. */
#ifndef EMSCRIPTEN
int PlanetsUniverse::load(const std::string& filename, bool clear) {
    TiXmlDocument doc(filename);

    if (!doc.LoadFile())
        throw std::runtime_error("Unable to load file \"" + filename + "\"!\n" + doc.ErrorDesc());

    TiXmlElement* root = doc.FirstChildElement("planets-3d-universe");
    if (root == nullptr)
        throw std::runtime_error("\"" + filename + "\" is not a valid universe file!");

    if (clear)
        deleteAll();

    /* keep track of how many planets were loaded. */
    int loaded = 0;

    for (TiXmlElement* element = root->FirstChildElement(); element != nullptr; element = element->NextSiblingElement()) {
        if (element->ValueStr() == "planet") {
            Planet planet;
            planet.setMass(std::stof(element->Attribute("mass")));

            key_type color = 0;

            try {
                std::string colorStr = element->Attribute("color");
                colorStr.replace(0, 1, "");
                color = std::stoul(colorStr, nullptr, 16);
            } catch(...) { /* Just ignore if it doesn't work. It isn't that critical. */ }

            for (TiXmlElement* sub = element->FirstChildElement(); sub != nullptr; sub = sub->NextSiblingElement()) {
                if (sub->ValueStr() == "position")
                    planet.position = glm::vec3(std::stof(sub->Attribute("x")),
                                                std::stof(sub->Attribute("y")),
                                                std::stof(sub->Attribute("z")));
                else if (sub->ValueStr() == "velocity")
                    /* Velocity is saved with velocity factor. */
                    planet.velocity = glm::vec3(std::stof(sub->Attribute("x")),
                                                std::stof(sub->Attribute("y")),
                                                std::stof(sub->Attribute("z"))) * velocityfac;
            }
            addPlanet(planet, color);
            ++loaded;
        }
    }

    return loaded;
}

void PlanetsUniverse::save(const std::string& filename) {
    TiXmlDocument doc;

    doc.LinkEndChild(new TiXmlDeclaration("1.0", "", ""));

    TiXmlElement* root = new TiXmlElement("planets-3d-universe");

    for (const_iterator i = planets.cbegin(); i != planets.cend(); ++i) {
        TiXmlElement* planet = new TiXmlElement("planet");
        planet->SetAttribute("mass", std::to_string(i->second.mass()));

        /* Puts uint32_t key into hexadecimal format #RRGGBB (No need to save alpha, as that's always 0xff) */
        const char* hex = "0123456789abcdef";
        planet->SetAttribute("color", std::string{'#',
                                                  hex[i->first >> 20 & 0xf],
                                                  hex[i->first >> 16 & 0xf],
                                                  hex[i->first >> 12 & 0xf],
                                                  hex[i->first >>  8 & 0xf],
                                                  hex[i->first >>  4 & 0xf],
                                                  hex[i->first       & 0xf]});

        TiXmlElement* position = new TiXmlElement("position");
        position->SetAttribute("x", std::to_string(i->second.position.x));
        position->SetAttribute("y", std::to_string(i->second.position.y));
        position->SetAttribute("z", std::to_string(i->second.position.z));
        planet->LinkEndChild(position);

        TiXmlElement* velocity = new TiXmlElement("velocity");
        /* Velocity is saved with velocity factor. */
        velocity->SetAttribute("x", std::to_string(i->second.velocity.x / velocityfac));
        velocity->SetAttribute("y", std::to_string(i->second.velocity.y / velocityfac));
        velocity->SetAttribute("z", std::to_string(i->second.velocity.z / velocityfac));
        planet->LinkEndChild(velocity);

        root->LinkEndChild(planet);
    }

    doc.LinkEndChild(root);

    if (!doc.SaveFile(filename))
        throw std::runtime_error(doc.ErrorDesc());
}
#endif

void PlanetsUniverse::advance(float time) {
    /* Factor the simulation speed and number of steps into the time value. */
    time *= simspeed / stepsPerFrame;

    for (int s = 0; s < stepsPerFrame; ++s) {
        iterator i = planets.begin();
        while (i != planets.end()) {
            /* In case there are planets with negative or empty mass for some reason, we don't want them messing things up. */
            if (i->second.mass() <= 0.0f) {
                i = planets.erase(i);
            } else {
                /* We only have to run this for planets after the current one,
                 * because all the planets before this have already been calculated with this one. */
                iterator o = i; ++o;

                while (o != planets.end()) {
                    glm::vec3 direction = o->second.position - i->second.position;
                    float distancesqr = glm::length2(direction);

                    /* Planets are close enough to merge. */
                    if (distancesqr < glm::pow(i->second.radius() + o->second.radius(), 2.0f)) {
                        /* Set the position and velocity to the wieghted average between the planets. */
                        i->second.position = o->second.position * o->second.mass() + i->second.position * i->second.mass();
                        i->second.velocity = o->second.velocity * o->second.mass() + i->second.velocity * i->second.mass();

                        /* Add the masses together. */
                        i->second.setMass(i->second.mass() + o->second.mass());

                        /* Finish the weighted average calculation. */
                        i->second.position /= i->second.mass();
                        i->second.velocity /= i->second.mass();

                        /* If the one we're deleting happens to be selected, select the remaining planet. */
                        if (o->first == selected)
                            selected = i->first;
                        /* If the planet being followed happens to be the one being deleted, follow the remaining planet. */
                        if (o->first == following)
                            following = i->first;

                        /* The path would be invalid after this. */
                        i->second.path.clear();
                        o = planets.erase(o);
                    } else {
                        /* The gravity math to calculate the force between the planets. */
                        direction *= gravityconst * time * ((o->second.mass() * i->second.mass()) / distancesqr) * glm::fastInverseSqrt(distancesqr);

                        /* Apply the force to the velocity of both planets. */
                        i->second.velocity += direction / i->second.mass();
                        o->second.velocity -= direction / o->second.mass();

                        /* Keep going. (Not in for loop because of the possibility of erase() getting called.) */
                        ++o;
                    }
                }

                /* Apply the velocity to the position of the planet and update the path. */
                i->second.position += i->second.velocity * time;
                i->second.updatePath(pathLength, pathRecordDistance);

                /* Onward! (Same situation as with ++o above.) */
                ++i;
            }
        }
    }
}

key_type PlanetsUniverse::addPlanet(const Planet& planet, key_type keyHint) {
    uniform_int_distribution<key_type> color_gen(0xFF000001, 0xFFFFFFFF);

    /* Keep generating until we find an unused key. */
    while (planets.count(keyHint) > 0 || (keyHint & RGB_MASK) == 0)
        keyHint = color_gen(generator);

    planets[keyHint] = planet;
    return keyHint;
}

void PlanetsUniverse::generateRandom(const int& count, const float& positionRange, const float& maxVelocity, const float& maxMass) {
    uniform_real_distribution<float> position(-positionRange, positionRange);
    uniform_real_distribution<float> velocity(-maxVelocity, maxVelocity);
    uniform_real_distribution<float> mass(min_mass, maxMass);

    for (int i = 0; i < count; ++i)
        addPlanet(Planet(glm::vec3(position(generator), position(generator), position(generator)),
                         glm::vec3(velocity(generator), velocity(generator), velocity(generator)),
                         mass(generator)));
}

/* TODO - This function currently does not account for other planets.
 * Doing so would be very complicated. IDK if it'd even be possible... I'll have to look into it sometime. */
key_type PlanetsUniverse::addOrbital(Planet& around, const float& radius, const float& mass, const glm::mat4& plane) {
    /* Calculate the speed based on gravitational force and distance. */
    float speed = sqrt((around.mass() * around.mass() * gravityconst) / ((around.mass() + mass) * radius));

    /* Velocity is the y column of the plane matrix * speed. */
    glm::vec3 velocity = glm::vec3(plane[1]) * speed;

    /* The x column is the relative position of the orbiting planet. */
    key_type planet = addPlanet(Planet(around.position + glm::vec3(plane[0]) * radius, around.velocity + velocity, mass));

    /* Apply force on the planet being orbited in the opposite direction of the resulting planets velocity. */
    around.velocity -= velocity * (mass / around.mass());

    return planet;
}

void PlanetsUniverse::generateRandomOrbital(const int& count, key_type target) {
    /* We need a planet to orbit around. */
    if (!isEmpty()) {
        /* Ensure we have a valid target planet, if none was provided select at random. */
        if (!isValid(target))
            target = getRandomPlanet();

        Planet &around = planets[target];

        uniform_real_distribution<float> angle(-glm::pi<float>(), glm::pi<float>());
        uniform_real_distribution<float> radius(around.radius() * 1.5f, around.radius() * 80.0f);
        uniform_real_distribution<float> mass(min_mass, around.mass() * 0.2f);

        for (int i = 0; i < count; ++i) {
            glm::mat4 plane;
            /* This is sort of a cheap way of making a random orbit plane. */
            plane *= glm::rotate(angle(generator), glm::sphericalRand(1.0f));
            plane *= glm::rotate(angle(generator), glm::sphericalRand(1.0f));
            addOrbital(around, radius(generator), mass(generator), plane);
        }
    }
}

void PlanetsUniverse::deleteEscapees() {
    /* We delete anything too far from the weighted average position. */
    glm::vec3 averagePosition;
    float totalMass = 0.0f;

    for (const auto& planet : planets) {
        averagePosition += planet.second.position * planet.second.mass();
        totalMass += planet.second.mass();
    }

    averagePosition /= totalMass;

    /* The squared distance from the center outside of which we delete things. */
    const float limits2 = 1.0e12f;

    for (iterator i = planets.begin(); i != planets.end();) {
        if (glm::distance2(i->second.position, averagePosition) > limits2)
            i = planets.erase(i);
        else
            ++i;
    }
}

key_type PlanetsUniverse::getRandomPlanet() {
    if (isEmpty())
        return 0;

    uniform_int_distribution<list_type::size_type> random_n(0, size() - 1);
    auto iter = begin();
    std::advance(iter, random_n(generator));

    return iter->first;
}

key_type PlanetsUniverse::nextKey(key_type key) const {
    if (!isEmpty()) {
        const_iterator current = find(key);

        if (current == cend() || ++current == cend())
            /* If the planet was not found or the planet was the last in the list, start at the beginning. */
            current = cbegin();

        /* Get the key back from the iterator. */
        return current->first;
    }

    return 0;
}

key_type PlanetsUniverse::prevKey(key_type key) const {
    if (!isEmpty()) {
        const_iterator current = find(key);

        if (current == cend()) {
            /* If the planet was not found, start at the beginning. */
            current = cbegin();
        } else {
            /* If the planet was the first planet in the list, start at the end. */
            if (current == cbegin())
                current = cend();
            --current;
        }

        /* Get the key back from the iterator. */
        return current->first;
    }

    return 0;
}

void PlanetsUniverse::centerAll() {
    /* We need the weighted average position and velocity to center. */
    glm::vec3 averagePosition, averageVelocity;
    float totalMass = 0.0f;

    for (const auto& planet : planets) {
        averagePosition += planet.second.position * planet.second.mass();
        averageVelocity += planet.second.velocity * planet.second.mass();
        totalMass += planet.second.mass();
    }

    averagePosition /= totalMass;
    averageVelocity /= totalMass;

    const float epsilon = glm::epsilon<float>();

    /* Don't bother centering if we're already reasonably centered. */
    if (!glm::isNull(averagePosition, epsilon) || !glm::isNull(averageVelocity, epsilon)) {
        for (auto& planet : planets) {
            planet.second.position -= averagePosition;
            planet.second.velocity -= averageVelocity;
            planet.second.path.clear();
        }
    }
}
<|endoftext|>


<commit_before>/*!
 * \file
 * Defines helpful utilities which contribute to compiler compatibility.
 *
 * \author Andres Jaan Tack <andres.jaan.tack@eesti.ee>
 */
#pragma once

//
// Check for support of the C++11 noexcept keyword. The macro RIAK_CPP_NOEXCEPT will safely expand
// to this keyword if it is available, and otherwise yield a blank.
//
#ifdef __GNUC__
#   include <features.h>
#   if __GNUC_PREREQ(4,6)
#       define RIAK_CPP_NOEXCEPT noexcept
#   else
#       define RIAK_CPP_NOEXCEPT
#  endif
#else
    // TODO: Check for clang >= 3.0 and verify.
#   define RIAK_CPP_NOEXCEPT
#endif
<commit_msg>(GH-21) Fixed an afterthought flub; apparently that file doesn't exist, and I don't know what I compiled.<commit_after>/*!
 * \file
 * Defines helpful utilities which contribute to compiler compatibility.
 *
 * \author Andres Jaan Tack <andres.jaan.tack@eesti.ee>
 */
#pragma once

//
// Check for support of the C++11 noexcept keyword. The macro RIAK_CPP_NOEXCEPT will safely expand
// to this keyword if it is available, and otherwise yield a blank.
//
#ifdef __GNUC__
#   if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
#       define RIAK_CPP_NOEXCEPT noexcept
#   else
#       define RIAK_CPP_NOEXCEPT
#  endif
#else
    // TODO: Check for clang >= 3.0 and verify.
#   define RIAK_CPP_NOEXCEPT
#endif
<|endoftext|>


<commit_before>// Copyright (2015) Gustav

#include "ride/finddlg.h"

#include <ride/wx.h>

#include <wx/dir.h>

#include <wx/stc/stc.h>

#include <memory>
#include <vector>

#include "ride/generated/ui.h"

#include "ride/fileedit.h"
#include "ride/mainwindow.h"
#include "ride/settings.h"
#include "ride/wxutils.h"
#include "ride/findresultscontrol.h"

class FindDlg : public ui::Find {
 public:
  FindDlg(wxWindow* parent, const wxString& find, const ride::FindDlg& data,
          FindAction find_action, FindScope find_scope);

  const wxString GetText() const { return uiFindText->GetValue(); }

  const int GetFlags();

  void ToData(ride::FindDlg* data) const;

  wxStyledTextCtrl* GetStc() { return m_scintilla1; }

  bool LookInCurrentFile() const { return uiLookIn->GetSelection() == 0; }

  bool IsRecursive() const { return uiIncludeSubFolders->GetValue(); }

  const wxString getReplaceText() const { return uiReplaceText->GetValue(); }

  bool KeepFilesOpen() const { return uiKeepFilesOpen->GetValue(); }

 protected:
  void OnCancel(wxCommandEvent& event);
  void OnOk(wxCommandEvent& event);
  void OnEnter(wxCommandEvent& event) { OnOk(event); }
};

FindDlg::FindDlg(wxWindow* parent, const wxString& find,
                 const ride::FindDlg& data, FindAction find_action,
                 FindScope find_scope)
    : ui::Find(parent, wxID_ANY) {
  uiFindText->SetValue(find);
  uiFindText->SelectAll();
  uiFindText->SetFocus();

  uiLookIn->Append("Current file");
  uiLookIn->Append("This project");
  uiLookIn->SetSelection(
      static_cast<int>(find_scope));  // assume the enum is file -> project

  uiFindTarget->Append("Normal text");
  uiFindTarget->Append("Regex");
  uiFindTarget->Append("Posix");

  uiIncludeSubFolders->SetValue(data.sub_folders());
  uiMatchCase->SetValue(data.match_case());
  uiMatchWholeWord->SetValue(data.match_whole_word());
  uiFindWordStart->SetValue(data.match_start());
  uiFileTypes->SetValue(data.file_types().c_str());
  uiFindTarget->SetSelection(data.target());

  uiReplaceStatic->Enable(find_action == FindAction::Replace);
  uiReplaceText->Enable(find_action == FindAction::Replace);
}

void FindDlg::ToData(ride::FindDlg* data) const {
  data->set_sub_folders(uiIncludeSubFolders->GetValue());
  data->set_match_case(uiMatchCase->GetValue());
  data->set_match_whole_word(uiMatchWholeWord->GetValue());
  data->set_match_start(uiFindWordStart->GetValue());
  data->set_file_types(uiFileTypes->GetValue());
  data->set_target(
      static_cast<ride::FindDlgTarget>(uiFindTarget->GetSelection()));
}

void FindDlg::OnCancel(wxCommandEvent& event) { EndModal(wxID_CANCEL); }

void FindDlg::OnOk(wxCommandEvent& event) {
  if (uiFindText->GetValue().length() <= 0) {
    ShowInfo(this, "Need to enter search text", "Missing Search Text");
    return;
  }
  EndModal(wxID_OK);
}

const int FindDlg::GetFlags() {
  int ret = 0;

  if (uiMatchCase->GetValue()) {
    ret |= wxSTC_FIND_MATCHCASE;
  }

  if (uiMatchWholeWord->GetValue()) {
    ret |= wxSTC_FIND_WHOLEWORD;
  }

  if (uiFindWordStart->GetValue()) {
    ret |= wxSTC_FIND_WORDSTART;
  }

  switch (uiFindTarget->GetSelection()) {
    case 0:
      break;
    case 1:
      ret |= wxSTC_FIND_REGEXP;
      break;
    case 2:
      ret |= wxSTC_FIND_POSIX;
      break;
    default:
      assert(false && "invalid selection");
      break;
  }

  return ret;
}

struct FindResult {
  FindResult(const wxString& f, const wxString& co, const int sl, const int sc,
             const int el, const int ec)
      : file(f),
        content(co),
        start_line(sl),
        start_col(sc),
        end_line(el),
        end_col(ec) {}

  wxString file;
  wxString content;
  int start_line;
  int start_col;
  int end_line;
  int end_col;
};

class UndoRedo {
 public:
  explicit UndoRedo(wxStyledTextCtrl* s) : stc(s) {
    assert(stc);
    stc->BeginUndoAction();
  }
  ~UndoRedo() { stc->EndUndoAction(); }

  wxStyledTextCtrl* stc;
};

int FindInStc(wxStyledTextCtrl* stc, const wxString& file, const wxString& text,
              int flags, std::vector<FindResult>* res, FindAction find_action,
              const wxString& replaceText) {
  assert(res);
  assert(stc);
  std::unique_ptr<UndoRedo> undoredo;

  // there is only need to create a undo/redo object if we're replacing
  if (find_action == FindAction::Replace) {
    undoredo.reset(new UndoRedo(stc));
  }
  int next_index = 0;
  int count = 0;
  while (true) {
    int end_index = 0;
    const int start_index =
        FindStcText(stc, next_index, stc->GetLength(), text, flags, &end_index);
    if (start_index == -1) return count;
    assert(start_index != end_index);

    const int target_start_index = start_index;
    int target_end_index = end_index;

    // replace text
    if (find_action == FindAction::Replace) {
      stc->SetTargetStart(start_index);
      stc->SetTargetEnd(end_index);
      const bool useRegex =
          flags & wxSTC_FIND_REGEXP || flags & wxSTC_FIND_POSIX;
      const int change = useRegex ? stc->ReplaceTargetRE(replaceText)
                                  : stc->ReplaceTarget(replaceText);
      assert(change > 0);
      next_index = start_index + change;
      target_end_index = start_index + change;
    } else {
      next_index = end_index;
    }

    // add item to the result list
    const int start_line = stc->LineFromPosition(target_start_index);
    const int start_col =
        target_start_index - stc->PositionFromLine(start_line);
    const int end_line = stc->LineFromPosition(target_end_index);
    const int end_col = target_end_index - stc->PositionFromLine(end_line);
    res->push_back(
        FindResult(file, stc->GetLine(start_line).Trim(true).Trim(false),
                   start_line + 1, start_col + 1, end_line + 1, end_col + 1));
    ++count;
  }

  return count;
}

void FindInFiles(MainWindow* parent, wxStyledTextCtrl* fallback,
                 const wxString& file, const wxString& text, int flags,
                 std::vector<FindResult>* res, FindAction find_action,
                 const wxString& replaceText, bool keepFilesOpen) {
  FileEdit* edit = parent->GetFile(file);
  wxStyledTextCtrl* stc = NULL;
  if (edit) {
    stc = edit->GetStc();
  } else {
    fallback->LoadFile(file);

    if (find_action == FindAction::Replace && keepFilesOpen) {
      int found = FindStcText(fallback, 0, stc->GetLength(), text, flags, NULL);
      if (found > 0) {
        FileEdit* opened_edit = parent->OpenFile(file);
        stc = opened_edit->GetStc();
      }
    }
    if (stc == NULL) {
      stc = fallback;
    }
  }
  assert(stc);
  int count = FindInStc(stc, file, text, flags, res, find_action, replaceText);

  if (find_action == FindAction::Replace && count > 0 && stc == fallback) {
    if (false == stc->SaveFile(file)) {
      ShowError(parent, "Failed to save after replace!", "Error saving!");
    }
  }
}

bool ShowFindDlg(MainWindow* parent, const wxString& current_selection,
                 const wxString& current_file, const wxString root_folder,
                 FindResultsControl* output, FindAction find_action,
                 FindScope find_scope) {
  static ride::FindDlg find_dlg_data;
  FindDlg dlg(parent, current_selection, find_dlg_data, find_action,
              find_scope);

  if (wxID_OK != dlg.ShowModal()) return false;
  dlg.ToData(&find_dlg_data);

  std::vector<FindResult> results;
  wxString file_info = current_file;

  // we can't create a styled ctrl so we cheat by having a 0x0 widget on the
  // find dlg
  // and use that for searching/replacing...
  wxStyledTextCtrl* fallback = dlg.GetStc();

  if (dlg.LookInCurrentFile()) {
    FindInFiles(parent, fallback, current_file, dlg.GetText(), dlg.GetFlags(),
                &results, find_action, dlg.getReplaceText(),
                dlg.KeepFilesOpen());
  } else {
    wxArrayString files;
    const std::vector<wxString> patterns =
        Split(find_dlg_data.file_types(), ";");
    size_t count = 0;
    for (const auto pattern : patterns) {
      count += wxDir::GetAllFiles(
          root_folder, &files, pattern,
          dlg.IsRecursive() ? wxDIR_FILES | wxDIR_DIRS : wxDIR_FILES);
    }

    file_info = wxString::Format("%d files in %s", count, root_folder);
    for (const auto file : files) {
      FindInFiles(parent, fallback, file, dlg.GetText(), dlg.GetFlags(),
                  &results, find_action, dlg.getReplaceText(),
                  dlg.KeepFilesOpen());
    }
  }

  const auto count = results.size();

  output->ClearOutput();

  const wxString find_text =
      find_action == FindAction::Find
          ? wxString::Format("Searched for '%s'", dlg.GetText())
          : wxString::Format("Replaced '%s' with '%s'", dlg.GetText(),
                             dlg.getReplaceText());
  output->WriteLine(wxString::Format("%s in %s", find_text, file_info));
  output->WriteLine(wxString::Format(
      "%s %d matches", find_action == FindAction::Find ? "Found" : "Replaced",
      count));
  output->WriteLine("");
  for (auto res : results) {
    // try to format the same way rust related error looks like so we can reuse
    // the parser code for both and get some synergy effects
    const wxString mess = wxString::Format(
        "%s:%d : %d : %d : %d %s: %s", res.file, res.start_line, res.start_col,
        res.end_line, res.end_col,
        find_action == FindAction::Find ? "found" : "replaced", res.content);
    output->WriteLine(mess);
  }

  return true;
}
<commit_msg>fixed potential crash<commit_after>// Copyright (2015) Gustav

#include "ride/finddlg.h"

#include <ride/wx.h>

#include <wx/dir.h>

#include <wx/stc/stc.h>

#include <memory>
#include <vector>

#include "ride/generated/ui.h"

#include "ride/fileedit.h"
#include "ride/mainwindow.h"
#include "ride/settings.h"
#include "ride/wxutils.h"
#include "ride/findresultscontrol.h"

class FindDlg : public ui::Find {
 public:
  FindDlg(wxWindow* parent, const wxString& find, const ride::FindDlg& data,
          FindAction find_action, FindScope find_scope);

  const wxString GetText() const { return uiFindText->GetValue(); }

  const int GetFlags();

  void ToData(ride::FindDlg* data) const;

  wxStyledTextCtrl* GetStc() { return m_scintilla1; }

  bool LookInCurrentFile() const { return uiLookIn->GetSelection() == 0; }

  bool IsRecursive() const { return uiIncludeSubFolders->GetValue(); }

  const wxString getReplaceText() const { return uiReplaceText->GetValue(); }

  bool KeepFilesOpen() const { return uiKeepFilesOpen->GetValue(); }

 protected:
  void OnCancel(wxCommandEvent& event);
  void OnOk(wxCommandEvent& event);
  void OnEnter(wxCommandEvent& event) { OnOk(event); }
};

FindDlg::FindDlg(wxWindow* parent, const wxString& find,
                 const ride::FindDlg& data, FindAction find_action,
                 FindScope find_scope)
    : ui::Find(parent, wxID_ANY) {
  uiFindText->SetValue(find);
  uiFindText->SelectAll();
  uiFindText->SetFocus();

  uiLookIn->Append("Current file");
  uiLookIn->Append("This project");
  uiLookIn->SetSelection(
      static_cast<int>(find_scope));  // assume the enum is file -> project

  uiFindTarget->Append("Normal text");
  uiFindTarget->Append("Regex");
  uiFindTarget->Append("Posix");

  uiIncludeSubFolders->SetValue(data.sub_folders());
  uiMatchCase->SetValue(data.match_case());
  uiMatchWholeWord->SetValue(data.match_whole_word());
  uiFindWordStart->SetValue(data.match_start());
  uiFileTypes->SetValue(data.file_types().c_str());
  uiFindTarget->SetSelection(data.target());

  uiReplaceStatic->Enable(find_action == FindAction::Replace);
  uiReplaceText->Enable(find_action == FindAction::Replace);
}

void FindDlg::ToData(ride::FindDlg* data) const {
  data->set_sub_folders(uiIncludeSubFolders->GetValue());
  data->set_match_case(uiMatchCase->GetValue());
  data->set_match_whole_word(uiMatchWholeWord->GetValue());
  data->set_match_start(uiFindWordStart->GetValue());
  data->set_file_types(uiFileTypes->GetValue());
  data->set_target(
      static_cast<ride::FindDlgTarget>(uiFindTarget->GetSelection()));
}

void FindDlg::OnCancel(wxCommandEvent& event) { EndModal(wxID_CANCEL); }

void FindDlg::OnOk(wxCommandEvent& event) {
  if (uiFindText->GetValue().length() <= 0) {
    ShowInfo(this, "Need to enter search text", "Missing Search Text");
    return;
  }
  EndModal(wxID_OK);
}

const int FindDlg::GetFlags() {
  int ret = 0;

  if (uiMatchCase->GetValue()) {
    ret |= wxSTC_FIND_MATCHCASE;
  }

  if (uiMatchWholeWord->GetValue()) {
    ret |= wxSTC_FIND_WHOLEWORD;
  }

  if (uiFindWordStart->GetValue()) {
    ret |= wxSTC_FIND_WORDSTART;
  }

  switch (uiFindTarget->GetSelection()) {
    case 0:
      break;
    case 1:
      ret |= wxSTC_FIND_REGEXP;
      break;
    case 2:
      ret |= wxSTC_FIND_POSIX;
      break;
    default:
      assert(false && "invalid selection");
      break;
  }

  return ret;
}

struct FindResult {
  FindResult(const wxString& f, const wxString& co, const int sl, const int sc,
             const int el, const int ec)
      : file(f),
        content(co),
        start_line(sl),
        start_col(sc),
        end_line(el),
        end_col(ec) {}

  wxString file;
  wxString content;
  int start_line;
  int start_col;
  int end_line;
  int end_col;
};

class UndoRedo {
 public:
  explicit UndoRedo(wxStyledTextCtrl* s) : stc(s) {
    assert(stc);
    stc->BeginUndoAction();
  }
  ~UndoRedo() { stc->EndUndoAction(); }

  wxStyledTextCtrl* stc;
};

int FindInStc(wxStyledTextCtrl* stc, const wxString& file, const wxString& text,
              int flags, std::vector<FindResult>* res, FindAction find_action,
              const wxString& replaceText) {
  assert(res);
  assert(stc);
  std::unique_ptr<UndoRedo> undoredo;

  // there is only need to create a undo/redo object if we're replacing
  if (find_action == FindAction::Replace) {
    undoredo.reset(new UndoRedo(stc));
  }
  int next_index = 0;
  int count = 0;
  while (true) {
    int end_index = 0;
    const int start_index =
        FindStcText(stc, next_index, stc->GetLength(), text, flags, &end_index);
    if (start_index == -1) return count;
    assert(start_index != end_index);

    const int target_start_index = start_index;
    int target_end_index = end_index;

    // replace text
    if (find_action == FindAction::Replace) {
      stc->SetTargetStart(start_index);
      stc->SetTargetEnd(end_index);
      const bool useRegex =
          flags & wxSTC_FIND_REGEXP || flags & wxSTC_FIND_POSIX;
      const int change = useRegex ? stc->ReplaceTargetRE(replaceText)
                                  : stc->ReplaceTarget(replaceText);
      assert(change > 0);
      next_index = start_index + change;
      target_end_index = start_index + change;
    } else {
      next_index = end_index;
    }

    // add item to the result list
    const int start_line = stc->LineFromPosition(target_start_index);
    const int start_col =
        target_start_index - stc->PositionFromLine(start_line);
    const int end_line = stc->LineFromPosition(target_end_index);
    const int end_col = target_end_index - stc->PositionFromLine(end_line);
    res->push_back(
        FindResult(file, stc->GetLine(start_line).Trim(true).Trim(false),
                   start_line + 1, start_col + 1, end_line + 1, end_col + 1));
    ++count;
  }

  return count;
}

void FindInFiles(MainWindow* parent, wxStyledTextCtrl* fallback,
                 const wxString& file, const wxString& text, int flags,
                 std::vector<FindResult>* res, FindAction find_action,
                 const wxString& replaceText, bool keepFilesOpen) {
  FileEdit* edit = parent->GetFile(file);
  wxStyledTextCtrl* stc = NULL;
  if (edit) {
    stc = edit->GetStc();
  } else {
    // use fallback stc
    stc = fallback;
    fallback->LoadFile(file);

    // if we are replacing with keep-open, do a find to see if we should
    // open the file and if so use that file instead of the 'fallback file'
    if (find_action == FindAction::Replace && keepFilesOpen) {
      int found = FindStcText(fallback, 0, stc->GetLength(), text, flags, NULL);
      if (found > 0) {
        FileEdit* opened_edit = parent->OpenFile(file);
        stc = opened_edit->GetStc();
      }
    }
  }

  assert(stc);
  int count = FindInStc(stc, file, text, flags, res, find_action, replaceText);

  if (find_action == FindAction::Replace && count > 0 && stc == fallback) {
    if (false == stc->SaveFile(file)) {
      ShowError(parent, "Failed to save after replace!", "Error saving!");
    }
  }
}

bool ShowFindDlg(MainWindow* parent, const wxString& current_selection,
                 const wxString& current_file, const wxString root_folder,
                 FindResultsControl* output, FindAction find_action,
                 FindScope find_scope) {
  static ride::FindDlg find_dlg_data;
  FindDlg dlg(parent, current_selection, find_dlg_data, find_action,
              find_scope);

  if (wxID_OK != dlg.ShowModal()) return false;
  dlg.ToData(&find_dlg_data);

  std::vector<FindResult> results;
  wxString file_info = current_file;

  // we can't create a styled ctrl so we cheat by having a 0x0 widget on the
  // find dlg
  // and use that for searching/replacing...
  wxStyledTextCtrl* fallback = dlg.GetStc();

  if (dlg.LookInCurrentFile()) {
    FindInFiles(parent, fallback, current_file, dlg.GetText(), dlg.GetFlags(),
                &results, find_action, dlg.getReplaceText(),
                dlg.KeepFilesOpen());
  } else {
    wxArrayString files;
    const std::vector<wxString> patterns =
        Split(find_dlg_data.file_types(), ";");
    size_t count = 0;
    for (const auto pattern : patterns) {
      count += wxDir::GetAllFiles(
          root_folder, &files, pattern,
          dlg.IsRecursive() ? wxDIR_FILES | wxDIR_DIRS : wxDIR_FILES);
    }

    file_info = wxString::Format("%d files in %s", count, root_folder);
    for (const auto file : files) {
      FindInFiles(parent, fallback, file, dlg.GetText(), dlg.GetFlags(),
                  &results, find_action, dlg.getReplaceText(),
                  dlg.KeepFilesOpen());
    }
  }

  const auto count = results.size();

  output->ClearOutput();

  const wxString find_text =
      find_action == FindAction::Find
          ? wxString::Format("Searched for '%s'", dlg.GetText())
          : wxString::Format("Replaced '%s' with '%s'", dlg.GetText(),
                             dlg.getReplaceText());
  output->WriteLine(wxString::Format("%s in %s", find_text, file_info));
  output->WriteLine(wxString::Format(
      "%s %d matches", find_action == FindAction::Find ? "Found" : "Replaced",
      count));
  output->WriteLine("");
  for (auto res : results) {
    // try to format the same way rust related error looks like so we can reuse
    // the parser code for both and get some synergy effects
    const wxString mess = wxString::Format(
        "%s:%d : %d : %d : %d %s: %s", res.file, res.start_line, res.start_col,
        res.end_line, res.end_col,
        find_action == FindAction::Find ? "found" : "replaced", res.content);
    output->WriteLine(mess);
  }

  return true;
}
<|endoftext|>


<commit_before>/**
 * This file is part of TelepathyQt
 *
 * Copyright © 2009-2012 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright © 2009 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt/Farstream/Channel>

#include "TelepathyQt/Farstream/_gen/channel.moc.hpp"

#include "TelepathyQt/debug-internal.h"

#include <TelepathyQt/CallChannel>
#include <TelepathyQt/Connection>

#include <telepathy-farstream/telepathy-farstream.h>
#include <telepathy-glib/channel.h>
#include <telepathy-glib/connection.h>
#include <telepathy-glib/dbus.h>

namespace Tp
{
namespace Farstream
{

struct TP_QT_FS_NO_EXPORT PendingChannel::Private
{
    Private()
        : mTfChannel(0)
    {
    }

    static void onTfChannelNewFinish(GObject *sourceObject, GAsyncResult *res, gpointer userData);

    TfChannel *mTfChannel;
};

PendingChannel::PendingChannel(const CallChannelPtr &channel)
    : Tp::PendingOperation(channel),
      mPriv(new PendingChannel::Private)
{
    if (!channel->handlerStreamingRequired()) {
        warning() << "Handler streaming not required";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Handler streaming not required"));
        return;
    }

    TpDBusDaemon *dbus = tp_dbus_daemon_dup(0);
    if (!dbus) {
        warning() << "Unable to connect to D-Bus";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to connect to D-Bus"));
        return;
    }

    Tp::ConnectionPtr connection = channel->connection();
    if (connection.isNull()) {
        warning() << "Connection not available";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Connection not available"));
        g_object_unref(dbus);
        return;
    }

    TpConnection *gconnection = tp_connection_new(dbus,
            connection->busName().toAscii(),
            connection->objectPath().toAscii(),
            0);
    g_object_unref(dbus);
    dbus = 0;
    if (!gconnection) {
        warning() << "Unable to construct TpConnection";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to construct TpConnection"));
        return;
    }

    TpChannel *gchannel = tp_channel_new(gconnection,
            channel->objectPath().toAscii(),
            TP_QT_IFACE_CHANNEL_TYPE_CALL.latin1(),
            (TpHandleType) channel->targetHandleType(),
            channel->targetHandle(),
            0);
    g_object_unref(gconnection);
    gconnection = 0;
    if (!gchannel) {
        warning() << "Unable to construct TpChannel";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to construct TpChannel"));
        return;
    }

    tf_channel_new_async(gchannel, PendingChannel::Private::onTfChannelNewFinish, this);
    g_object_unref(gchannel);
}

PendingChannel::~PendingChannel()
{
    delete mPriv;
}

void PendingChannel::Private::onTfChannelNewFinish(GObject *sourceObject,
        GAsyncResult *res, gpointer userData)
{
    PendingChannel *self = reinterpret_cast<PendingChannel *>(userData);

    GError *error = NULL;
    TfChannel *ret = tf_channel_new_finish(sourceObject, res, &error);
    if (error) {
        warning() << "Fs::PendingChannel::Private::onTfChannelNewFinish: error " << error->message;
        self->setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String(error->message));
        g_clear_error(&error);
        return;
    }

    self->mPriv->mTfChannel = ret;
    self->setFinished();
}

TfChannel *PendingChannel::tfChannel() const
{
    return mPriv->mTfChannel;
}

CallChannelPtr PendingChannel::callChannel() const
{
    return CallChannelPtr::staticCast(object());
}

PendingChannel *createChannel(const CallChannelPtr &channel)
{
    PendingChannel *ptf = new PendingChannel(channel);
    return ptf;
}

} // Farstream
} // Tp
<commit_msg>farstream: Fix TpCallChannel creation.<commit_after>/**
 * This file is part of TelepathyQt
 *
 * Copyright © 2009-2012 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright © 2009 Nokia Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt/Farstream/Channel>

#include "TelepathyQt/Farstream/_gen/channel.moc.hpp"

#include "TelepathyQt/debug-internal.h"

#include <TelepathyQt/CallChannel>
#include <TelepathyQt/Connection>

#include <telepathy-farstream/telepathy-farstream.h>
#include <telepathy-glib/call-channel.h>
#include <telepathy-glib/connection.h>
#include <telepathy-glib/dbus.h>

namespace Tp
{
namespace Farstream
{

struct TP_QT_FS_NO_EXPORT PendingChannel::Private
{
    Private()
        : mTfChannel(0)
    {
    }

    static void onTfChannelNewFinish(GObject *sourceObject, GAsyncResult *res, gpointer userData);

    TfChannel *mTfChannel;
};

PendingChannel::PendingChannel(const CallChannelPtr &channel)
    : Tp::PendingOperation(channel),
      mPriv(new PendingChannel::Private)
{
    if (!channel->handlerStreamingRequired()) {
        warning() << "Handler streaming not required";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Handler streaming not required"));
        return;
    }

    TpDBusDaemon *dbus = tp_dbus_daemon_dup(0);
    if (!dbus) {
        warning() << "Unable to connect to D-Bus";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to connect to D-Bus"));
        return;
    }

    Tp::ConnectionPtr connection = channel->connection();
    if (connection.isNull()) {
        warning() << "Connection not available";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Connection not available"));
        g_object_unref(dbus);
        return;
    }

    TpConnection *gconnection = tp_connection_new(dbus,
            connection->busName().toAscii(),
            connection->objectPath().toAscii(),
            0);
    if (!gconnection) {
        warning() << "Unable to construct TpConnection";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to construct TpConnection"));
        g_object_unref(dbus);
        return;
    }

    TpChannel *gchannel = (TpChannel*) g_object_new(TP_TYPE_CALL_CHANNEL,
            "bus-name", connection->busName().toAscii().constData(),
            "connection", gconnection,
            "dbus-daemon", dbus,
            "object-path", channel->objectPath().toAscii().constData(),
            NULL);
    g_object_unref(dbus);
    dbus = 0;
    g_object_unref(gconnection);
    gconnection = 0;
    if (!gchannel) {
        warning() << "Unable to construct TpChannel";
        setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE,
                QLatin1String("Unable to construct TpChannel"));
        return;
    }

    tf_channel_new_async(gchannel, PendingChannel::Private::onTfChannelNewFinish, this);
    g_object_unref(gchannel);
}

PendingChannel::~PendingChannel()
{
    delete mPriv;
}

void PendingChannel::Private::onTfChannelNewFinish(GObject *sourceObject,
        GAsyncResult *res, gpointer userData)
{
    PendingChannel *self = reinterpret_cast<PendingChannel *>(userData);

    GError *error = NULL;
    TfChannel *ret = tf_channel_new_finish(sourceObject, res, &error);
    if (error) {
        warning() << "Fs::PendingChannel::Private::onTfChannelNewFinish: error " << error->message;
        self->setFinishedWithError(TP_QT_ERROR_NOT_AVAILABLE, QLatin1String(error->message));
        g_clear_error(&error);
        return;
    }

    self->mPriv->mTfChannel = ret;
    self->setFinished();
}

TfChannel *PendingChannel::tfChannel() const
{
    return mPriv->mTfChannel;
}

CallChannelPtr PendingChannel::callChannel() const
{
    return CallChannelPtr::staticCast(object());
}

PendingChannel *createChannel(const CallChannelPtr &channel)
{
    PendingChannel *ptf = new PendingChannel(channel);
    return ptf;
}

} // Farstream
} // Tp
<|endoftext|>


<commit_before>/*
 * BitboardCA. Cellular Automata using bitboard algorithms.
 * Copyright (C) Toshiyuki Hirooka <toshi.hirooka@gmail.com> http://wasabi.in/
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

/**
 * sample
 */

#include <iostream>
#include <time.h>
#include <stdlib.h>

#include "bbca.h"

namespace BCA = BitboardCA;

class MyCA : public BCA::CA
{
	public:
		MyCA(int size_x, int size_y)
			: CA(size_x, size_y)
		{
		};

	protected:
		BCA::Bitboard rule(
				BCA::Bitboard board,
				BCA::Bitboard s0, BCA::Bitboard s1, BCA::Bitboard s2,
				BCA::Bitboard s3, BCA::Bitboard s4, BCA::Bitboard s5,
				BCA::Bitboard s6, BCA::Bitboard s7, BCA::Bitboard s8 )
		{
			// making automata rule
			return ( ~board & s3 ) | ( board & ( s2 | s3 ) ); // Conway's game of life
//            return ( ~board & s3 ) | ( board & ( s2 | s3 | s4 ) ); // maze
//            return ( ~board & ( s3 | s4 | s6 | s7 | s8 ) ) | ( board & ( s3 | s6 | s7 | s8 ) ); // Day & Night
		};
};

int main()
{
	const int count = 100000;
	MyCA ca(12,8);

	ca.randomize();

	clock_t start, end;
	start = clock();
	for ( int steps = 0 ; steps < count ; steps ++ )
	{
		ca.step();
		ca.view();
	}
	end = clock();
	std::cout << "count = " << count << std::endl;
	std::cout << "size = " << "(" << ca.getSizeX() << ", " << ca.getSizeY() << ")" << std::endl;
	std::cout << "time = " << (double)(end - start)/CLOCKS_PER_SEC << std::endl;
	std::cout << (double)(end - start)/count/CLOCKS_PER_SEC << " sec per count " << std::endl;

	return 0;
}

<commit_msg>crushed building sample. fix it.<commit_after>/*
 * BitboardCA. Cellular Automata using bitboard algorithms.
 * Copyright (C) Toshiyuki Hirooka <toshi.hirooka@gmail.com> http://wasabi.in/
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

/**
 * sample
 */

#include <iostream>
#include <time.h>
#include <stdlib.h>

#include "bbca.h"

namespace BCA = BitboardCA;

class MyCA : public BCA::CA
{
	public:
		MyCA(std::size_t size_x, std::size_t size_y)
			: CA(size_x, size_y)
		{
		};

	protected:
		BCA::Bitboard Rule(
				BCA::Bitboard board,
				BCA::Bitboard s0, BCA::Bitboard s1, BCA::Bitboard s2,
				BCA::Bitboard s3, BCA::Bitboard s4, BCA::Bitboard s5,
				BCA::Bitboard s6, BCA::Bitboard s7, BCA::Bitboard s8 )
		{
			// making automata rule
			return ( ~board & s3 ) | ( board & ( s2 | s3 ) ); // Conway's game of life
//            return ( ~board & s3 ) | ( board & ( s2 | s3 | s4 ) ); // maze
//            return ( ~board & ( s3 | s4 | s6 | s7 | s8 ) ) | ( board & ( s3 | s6 | s7 | s8 ) ); // Day & Night
		};
};

int main()
{
	const int count = 100000;
	MyCA ca(12,8);

	ca.Randomize();

	clock_t start, end;
	start = clock();
	for ( int steps = 0 ; steps < count ; steps ++ )
	{
		ca.Step();
		ca.View();
	}
	end = clock();
	std::cout << "count = " << count << std::endl;
	std::cout << "size = " << "(" << ca.GetSizeX() << ", " << ca.GetSizeY() << ")" << std::endl;
	std::cout << "time = " << (double)(end - start)/CLOCKS_PER_SEC << std::endl;
	std::cout << (double)(end - start)/count/CLOCKS_PER_SEC << " sec per count " << std::endl;

	return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */
#include <string>
#include <iostream>
#include "halAlignmentTest.h"
#include "halValidateTest.h"
#include "halRandomData.h"
#include "halGappedTopSegmentIterator.h"
#include "halGappedBottomSegmentIterator.h"
#include "halRandNumberGen.h"

extern "C" {
#include "commonC.h"
}

using namespace std;
using namespace hal;

static RandNumberGen rng;

void ValidateSmallTest::createCallBack(Alignment* alignment)
{
    createRandomAlignment(rng, alignment, 0.75, 0.1, 2, 5, 10, 1000, 5, 10);

}

void ValidateSmallTest::checkCallBack(const Alignment* alignment)
{
  validateAlignment(alignment);
}

void ValidateMediumTest::createCallBack(Alignment* alignment)
{
    createRandomAlignment(rng, alignment, 1.25, 0.7, 10, 20, 2, 50, 1000, 50000);

}

void ValidateMediumTest::checkCallBack(const Alignment* alignment)
{
  validateAlignment(alignment);
}

void ValidateLargeTest::createCallBack(Alignment* alignment)
{
    createRandomAlignment(rng, alignment, 2.0, 1.0, 50, 100, 2, 10, 10000,
                          500000);

}

void ValidateLargeTest::checkCallBack(const Alignment* alignment)
{
  validateAlignment(alignment);
}

void ValidateManyGenomesTest::createCallBack(Alignment* alignment)
{
    createRandomAlignment(rng, alignment, 0.75, 0.1, 363, 400, 1, 10, 1, 2);
}

void ValidateManyGenomesTest::checkCallBack(const Alignment* alignment)
{
    validateAlignment(alignment);
}

void halValidateSmallTest(CuTest *testCase)
{
    ValidateSmallTest tester;
    tester.check(testCase);
}

void halValidateMediumTest(CuTest *testCase)
{
    ValidateMediumTest tester;
    tester.check(testCase);
}

void halValidateLargeTest(CuTest *testCase)
{
    ValidateLargeTest tester;
    tester.check(testCase);
}

void halValidateManyGenomesTest(CuTest *testCase)
{
    ValidateManyGenomesTest tester;
    tester.check(testCase);
}

CuSuite* halValidateTestSuite(void)
{
  CuSuite* suite = CuSuiteNew();
  SUITE_ADD_TEST(suite, halValidateSmallTest);
  SUITE_ADD_TEST(suite, halValidateMediumTest);
  SUITE_ADD_TEST(suite, halValidateManyGenomesTest);
#if 0  // this is very slow
  SUITE_ADD_TEST(suite, halValidateLargeTest);
#endif
  return suite;
}

<commit_msg>Run with hundreds of genomes only in mmap mode<commit_after>/*
 * Copyright (C) 2012 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */
#include <string>
#include <iostream>
#include "halAlignmentTest.h"
#include "halValidateTest.h"
#include "halRandomData.h"
#include "halGappedTopSegmentIterator.h"
#include "halGappedBottomSegmentIterator.h"
#include "halRandNumberGen.h"

extern "C" {
#include "commonC.h"
}

using namespace std;
using namespace hal;

static RandNumberGen rng;

void ValidateSmallTest::createCallBack(Alignment* alignment)
{
    createRandomAlignment(rng, alignment, 0.75, 0.1, 2, 5, 10, 1000, 5, 10);

}

void ValidateSmallTest::checkCallBack(const Alignment* alignment)
{
  validateAlignment(alignment);
}

void ValidateMediumTest::createCallBack(Alignment* alignment)
{
    createRandomAlignment(rng, alignment, 1.25, 0.7, 10, 20, 2, 50, 1000, 50000);

}

void ValidateMediumTest::checkCallBack(const Alignment* alignment)
{
  validateAlignment(alignment);
}

void ValidateLargeTest::createCallBack(Alignment* alignment)
{
    createRandomAlignment(rng, alignment, 2.0, 1.0, 50, 100, 2, 10, 10000,
                          500000);

}

void ValidateLargeTest::checkCallBack(const Alignment* alignment)
{
  validateAlignment(alignment);
}

void ValidateManyGenomesTest::createCallBack(Alignment* alignment)
{
    // hdf5 runs out of memory on Travis.
    if (alignment->getStorageFormat() == "mmap") {
        cout << "running" << endl;
        createRandomAlignment(rng, alignment, 0.75, 0.1, 363, 400, 1, 10, 1, 2);
    }
}

void ValidateManyGenomesTest::checkCallBack(const Alignment* alignment)
{
    if (alignment->getStorageFormat() == "mmap") {
        validateAlignment(alignment);
    }
}

void halValidateSmallTest(CuTest *testCase)
{
    ValidateSmallTest tester;
    tester.check(testCase);
}

void halValidateMediumTest(CuTest *testCase)
{
    ValidateMediumTest tester;
    tester.check(testCase);
}

void halValidateLargeTest(CuTest *testCase)
{
    ValidateLargeTest tester;
    tester.check(testCase);
}

void halValidateManyGenomesTest(CuTest *testCase)
{
    ValidateManyGenomesTest tester;
    tester.check(testCase);
}

CuSuite* halValidateTestSuite(void)
{
  CuSuite* suite = CuSuiteNew();
  SUITE_ADD_TEST(suite, halValidateSmallTest);
  SUITE_ADD_TEST(suite, halValidateMediumTest);
  SUITE_ADD_TEST(suite, halValidateManyGenomesTest);
#if 0  // this is very slow
  SUITE_ADD_TEST(suite, halValidateLargeTest);
#endif
  return suite;
}

<|endoftext|>