<commit_before>//===------------------------- thread.cpp----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "__config"
#ifndef _LIBCPP_HAS_NO_THREADS

#include "thread"
#include "exception"
#include "vector"
#include "future"
#include "limits"
#include <sys/types.h>

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# include <sys/param.h>
# if defined(BSD)
#   include <sys/sysctl.h>
# endif // defined(BSD)
#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__)
# include <unistd.h>
#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__)

#if defined(__NetBSD__)
#pragma weak pthread_create // Do not create libpthread dependency
#endif

#if defined(_LIBCPP_WIN32API)
#include <windows.h>
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

thread::~thread()
{
    if (!__libcpp_thread_isnull(&__t_))
        terminate();
}

void
thread::join()
{
    int ec = EINVAL;
    if (!__libcpp_thread_isnull(&__t_))
    {
        ec = __libcpp_thread_join(&__t_);
        if (ec == 0)
            __t_ = _LIBCPP_NULL_THREAD;
    }

    if (ec)
        __throw_system_error(ec, "thread::join failed");
}

void
thread::detach()
{
    int ec = EINVAL;
    if (!__libcpp_thread_isnull(&__t_))
    {
        ec = __libcpp_thread_detach(&__t_);
        if (ec == 0)
            __t_ = _LIBCPP_NULL_THREAD;
    }

    if (ec)
        __throw_system_error(ec, "thread::detach failed");
}

unsigned
thread::hardware_concurrency() _NOEXCEPT
{
#if defined(CTL_HW) && defined(HW_NCPU)
    unsigned n;
    int mib[2] = {CTL_HW, HW_NCPU};
    std::size_t s = sizeof(n);
    sysctl(mib, 2, &n, &s, 0, 0);
    return n;
#elif defined(_SC_NPROCESSORS_ONLN)
    long result = sysconf(_SC_NPROCESSORS_ONLN);
    // sysconf returns -1 if the name is invalid, the option does not exist or
    // does not have a definite limit.
    // if sysconf returns some other negative number, we have no idea
    // what is going on. Default to something safe.
    if (result < 0)
        return 0;
    return static_cast<unsigned>(result);
#elif defined(_LIBCPP_WIN32API)
    SYSTEM_INFO info;
    GetSystemInfo(&info);
    return info.dwNumberOfProcessors;
#else  // defined(CTL_HW) && defined(HW_NCPU)
    // TODO: grovel through /proc or check cpuid on x86 and similar
    // instructions on other architectures.
#   if defined(_LIBCPP_WARNING)
        _LIBCPP_WARNING("hardware_concurrency not yet implemented")
#   else
#       warning hardware_concurrency not yet implemented
#   endif
    return 0;  // Means not computable [thread.thread.static]
#endif  // defined(CTL_HW) && defined(HW_NCPU)
}

namespace this_thread
{

void
sleep_for(const chrono::nanoseconds& ns)
{
    if (ns > chrono::nanoseconds::zero())
    {
        __libcpp_thread_sleep_for(ns);
    }
}

}  // this_thread

__thread_specific_ptr<__thread_struct>&
__thread_local_data()
{
    static __thread_specific_ptr<__thread_struct> __p;
    return __p;
}

// __thread_struct_imp

template <class T>
class _LIBCPP_HIDDEN __hidden_allocator
{
public:
    typedef T  value_type;

    T* allocate(size_t __n)
        {return static_cast<T*>(::operator new(__n * sizeof(T)));}
    void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));}

    size_t max_size() const {return size_t(~0) / sizeof(T);}
};

class _LIBCPP_HIDDEN __thread_struct_imp
{
    typedef vector<__assoc_sub_state*,
                          __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
    typedef vector<pair<condition_variable*, mutex*>,
               __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;

    _AsyncStates async_states_;
    _Notify notify_;

    __thread_struct_imp(const __thread_struct_imp&);
    __thread_struct_imp& operator=(const __thread_struct_imp&);
public:
    __thread_struct_imp() {}
    ~__thread_struct_imp();

    void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
    void __make_ready_at_thread_exit(__assoc_sub_state* __s);
};

__thread_struct_imp::~__thread_struct_imp()
{
    for (_Notify::iterator i = notify_.begin(), e = notify_.end();
            i != e; ++i)
    {
        i->second->unlock();
        i->first->notify_all();
    }
    for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
            i != e; ++i)
    {
        (*i)->__make_ready();
        (*i)->__release_shared();
    }
}

void
__thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
{
    notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
}

void
__thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
{
    async_states_.push_back(__s);
    __s->__add_shared();
}

// __thread_struct

__thread_struct::__thread_struct()
    : __p_(new __thread_struct_imp)
{
}

__thread_struct::~__thread_struct()
{
    delete __p_;
}

void
__thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
{
    __p_->notify_all_at_thread_exit(cv, m);
}

void
__thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
{
    __p_->__make_ready_at_thread_exit(__s);
}

_LIBCPP_END_NAMESPACE_STD

#endif // !_LIBCPP_HAS_NO_THREADS
<commit_msg>[libcxx] GNU/Hurd uses BSD-based interfaces, but does not (and won't) provide <sys/sysctl.h><commit_after>//===------------------------- thread.cpp----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "__config"
#ifndef _LIBCPP_HAS_NO_THREADS

#include "thread"
#include "exception"
#include "vector"
#include "future"
#include "limits"
#include <sys/types.h>

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# include <sys/param.h>
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
#   include <sys/sysctl.h>
# endif
#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__)
# include <unistd.h>
#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__CloudABI__) || defined(__Fuchsia__)

#if defined(__NetBSD__)
#pragma weak pthread_create // Do not create libpthread dependency
#endif

#if defined(_LIBCPP_WIN32API)
#include <windows.h>
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

thread::~thread()
{
    if (!__libcpp_thread_isnull(&__t_))
        terminate();
}

void
thread::join()
{
    int ec = EINVAL;
    if (!__libcpp_thread_isnull(&__t_))
    {
        ec = __libcpp_thread_join(&__t_);
        if (ec == 0)
            __t_ = _LIBCPP_NULL_THREAD;
    }

    if (ec)
        __throw_system_error(ec, "thread::join failed");
}

void
thread::detach()
{
    int ec = EINVAL;
    if (!__libcpp_thread_isnull(&__t_))
    {
        ec = __libcpp_thread_detach(&__t_);
        if (ec == 0)
            __t_ = _LIBCPP_NULL_THREAD;
    }

    if (ec)
        __throw_system_error(ec, "thread::detach failed");
}

unsigned
thread::hardware_concurrency() _NOEXCEPT
{
#if defined(CTL_HW) && defined(HW_NCPU)
    unsigned n;
    int mib[2] = {CTL_HW, HW_NCPU};
    std::size_t s = sizeof(n);
    sysctl(mib, 2, &n, &s, 0, 0);
    return n;
#elif defined(_SC_NPROCESSORS_ONLN)
    long result = sysconf(_SC_NPROCESSORS_ONLN);
    // sysconf returns -1 if the name is invalid, the option does not exist or
    // does not have a definite limit.
    // if sysconf returns some other negative number, we have no idea
    // what is going on. Default to something safe.
    if (result < 0)
        return 0;
    return static_cast<unsigned>(result);
#elif defined(_LIBCPP_WIN32API)
    SYSTEM_INFO info;
    GetSystemInfo(&info);
    return info.dwNumberOfProcessors;
#else  // defined(CTL_HW) && defined(HW_NCPU)
    // TODO: grovel through /proc or check cpuid on x86 and similar
    // instructions on other architectures.
#   if defined(_LIBCPP_WARNING)
        _LIBCPP_WARNING("hardware_concurrency not yet implemented")
#   else
#       warning hardware_concurrency not yet implemented
#   endif
    return 0;  // Means not computable [thread.thread.static]
#endif  // defined(CTL_HW) && defined(HW_NCPU)
}

namespace this_thread
{

void
sleep_for(const chrono::nanoseconds& ns)
{
    if (ns > chrono::nanoseconds::zero())
    {
        __libcpp_thread_sleep_for(ns);
    }
}

}  // this_thread

__thread_specific_ptr<__thread_struct>&
__thread_local_data()
{
    static __thread_specific_ptr<__thread_struct> __p;
    return __p;
}

// __thread_struct_imp

template <class T>
class _LIBCPP_HIDDEN __hidden_allocator
{
public:
    typedef T  value_type;

    T* allocate(size_t __n)
        {return static_cast<T*>(::operator new(__n * sizeof(T)));}
    void deallocate(T* __p, size_t) {::operator delete(static_cast<void*>(__p));}

    size_t max_size() const {return size_t(~0) / sizeof(T);}
};

class _LIBCPP_HIDDEN __thread_struct_imp
{
    typedef vector<__assoc_sub_state*,
                          __hidden_allocator<__assoc_sub_state*> > _AsyncStates;
    typedef vector<pair<condition_variable*, mutex*>,
               __hidden_allocator<pair<condition_variable*, mutex*> > > _Notify;

    _AsyncStates async_states_;
    _Notify notify_;

    __thread_struct_imp(const __thread_struct_imp&);
    __thread_struct_imp& operator=(const __thread_struct_imp&);
public:
    __thread_struct_imp() {}
    ~__thread_struct_imp();

    void notify_all_at_thread_exit(condition_variable* cv, mutex* m);
    void __make_ready_at_thread_exit(__assoc_sub_state* __s);
};

__thread_struct_imp::~__thread_struct_imp()
{
    for (_Notify::iterator i = notify_.begin(), e = notify_.end();
            i != e; ++i)
    {
        i->second->unlock();
        i->first->notify_all();
    }
    for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end();
            i != e; ++i)
    {
        (*i)->__make_ready();
        (*i)->__release_shared();
    }
}

void
__thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
{
    notify_.push_back(pair<condition_variable*, mutex*>(cv, m));
}

void
__thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s)
{
    async_states_.push_back(__s);
    __s->__add_shared();
}

// __thread_struct

__thread_struct::__thread_struct()
    : __p_(new __thread_struct_imp)
{
}

__thread_struct::~__thread_struct()
{
    delete __p_;
}

void
__thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m)
{
    __p_->notify_all_at_thread_exit(cv, m);
}

void
__thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s)
{
    __p_->__make_ready_at_thread_exit(__s);
}

_LIBCPP_END_NAMESPACE_STD

#endif // !_LIBCPP_HAS_NO_THREADS
<|endoftext|>


<commit_before>// Copyright (c) 2011 Zeex
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <sampgdk/config.h>
#include <sampgdk/export.h>
#include <sampgdk/samp.h>

#include <set>
#include <vector>

#include "timers.h"

std::vector<Timer*> Timer::timers_;

Timer::Timer(int interval, bool repeat, TimerHandler hander, void *param)
	: interval_(interval)
	, repeating_(repeat)
	, handler_(hander)
	, param_(param)
	, startTime_(GetServerTickCount())
{
}

Timer::~Timer() {
}

void Timer::Fire(int elapsedTime) {
	size_t timerid = 0;
	while (timerid < timers_.size()) {
		if (timers_[timerid] == this) {
			break;
		}
	}
	handler_(timerid, param_);
	if (repeating_) {
		startTime_ = GetServerTickCount() - (elapsedTime - interval_);
	}
}

int Timer::CreateTimer(int interval, bool repeat, TimerHandler handler, void *param) {
	Timer *timer = new Timer(interval, repeat, handler, param);
	size_t timerid = 0;
	while (timerid < timers_.size()) {
		if (timers_[timerid] == 0) {
			timers_[timerid] = timer;
			break;
		}
	}
	if (timerid == timers_.size()) {
		timers_.push_back(timer);
	}
	return timerid;
}

bool Timer::DestroyTimer(int timerid) {
	if (timerid < 0 || timerid >= static_cast<int>(timers_.size())) {
		return false;
	}

	Timer *timer = timers_[timerid];
	delete timer;

	if (timerid == timers_.size()) {
		timers_.pop_back();
	} else {
		timers_[timerid] = 0;
	}

	return true;
}

void Timer::ProcessTimers() {
	int time = GetServerTickCount();
	for (size_t i = 0; i < timers_.size(); ++i) {
		Timer *timer = timers_[i];
		int elapsedTime = time - timer->GetStartTime();
		if (elapsedTime >= timer->GetInterval()) {
			timer->Fire(elapsedTime);
			if (!timer->IsRepeating()) {
				DestroyTimer(i);
			}
		}
	}
}

SAMPGDK_EXPORT void SAMPGDK_CALL sampgdk_process_timers() {
	Timer::ProcessTimers();
}

SAMPGDK_EXPORT int SAMPGDK_CALL CreateTimer(int interval, bool repeat, TimerHandler handler, void *param) {
	return Timer::CreateTimer(interval, repeat, handler, param);
}

SAMPGDK_EXPORT bool SAMPGDK_CALL DestroyTimer(int timerid) {
	return Timer::DestroyTimer(timerid);
}
<commit_msg>Fix infinite loop in CreateTimer and Timer::Fire<commit_after>// Copyright (c) 2011 Zeex
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <sampgdk/config.h>
#include <sampgdk/export.h>
#include <sampgdk/samp.h>

#include <set>
#include <vector>

#include "timers.h"

std::vector<Timer*> Timer::timers_;

Timer::Timer(int interval, bool repeat, TimerHandler hander, void *param)
	: interval_(interval)
	, repeating_(repeat)
	, handler_(hander)
	, param_(param)
	, startTime_(GetServerTickCount())
{
}

Timer::~Timer() {
}

void Timer::Fire(int elapsedTime) {
	size_t timerid = 0;
	while (timerid < timers_.size()) {
		if (timers_[timerid] == this) {
			break;
		}
		++timerid;
	}
	handler_(timerid, param_);
	if (repeating_) {
		startTime_ = GetServerTickCount() - (elapsedTime - interval_);
	}
}

int Timer::CreateTimer(int interval, bool repeat, TimerHandler handler, void *param) {
	Timer *timer = new Timer(interval, repeat, handler, param);
	size_t timerid = 0;
	while (timerid < timers_.size()) {
		if (timers_[timerid] == 0) {
			timers_[timerid] = timer;
			break;
		}
		++timerid;
	}
	if (timerid == timers_.size()) {
		timers_.push_back(timer);
	}
	return timerid;
}

bool Timer::DestroyTimer(int timerid) {
	if (timerid < 0 || timerid >= static_cast<int>(timers_.size())) {
		return false;
	}

	Timer *timer = timers_[timerid];
	delete timer;

	if (timerid == timers_.size()) {
		timers_.pop_back();
	} else {
		timers_[timerid] = 0;
	}

	return true;
}

void Timer::ProcessTimers() {
	int time = GetServerTickCount();
	for (size_t i = 0; i < timers_.size(); ++i) {
		Timer *timer = timers_[i];
		int elapsedTime = time - timer->GetStartTime();
		if (elapsedTime >= timer->GetInterval()) {
			timer->Fire(elapsedTime);
			if (!timer->IsRepeating()) {
				DestroyTimer(i);
			}
		}
	}
}

SAMPGDK_EXPORT void SAMPGDK_CALL sampgdk_process_timers() {
	Timer::ProcessTimers();
}

SAMPGDK_EXPORT int SAMPGDK_CALL CreateTimer(int interval, bool repeat, TimerHandler handler, void *param) {
	return Timer::CreateTimer(interval, repeat, handler, param);
}

SAMPGDK_EXPORT bool SAMPGDK_CALL DestroyTimer(int timerid) {
	return Timer::DestroyTimer(timerid);
}
<|endoftext|>


<commit_before>#include "arc_utilities/timing.hpp"
#include <iostream>
#include <cassert>
#include <algorithm>
#include <cstdio>

using namespace arc_utilities;

double GlobalStopwatch(const StopwatchControl control)
{
    static Stopwatch global_stopwatch;
    return global_stopwatch(control);
}

Profiler* Profiler::m_instance = NULL;

Profiler* Profiler::getInstance()
{
    if (m_instance == NULL)
    {
        m_instance = new Profiler();
    }
    return m_instance;
}

void Profiler::reset_and_preallocate(size_t num_names, size_t num_events)
{
    Profiler* monitor = getInstance();
    monitor->data.clear();
    monitor->prealloc_buffer.resize(num_names);
    for (size_t i=0; i<num_names; i++)
    {
        monitor->prealloc_buffer[i].reserve(num_events);
    }
}

void Profiler::reset(std::string name)
{
    Profiler* m = getInstance();
    if(m->data.find(name) != m->data.end())
    {
        m->data[name].resize(0);
        startTimer(name);
    }

}

void Profiler::addData(std::string name, double datum)
{
    Profiler* m = getInstance();
    if (m->data.find(name) == m->data.end())
    {
        m->data[name] = std::vector<double>();
        if (m->prealloc_buffer.size() > 0)
        {
            m->data[name].swap(m->prealloc_buffer.back());
            m->prealloc_buffer.pop_back();
        }
    }
    m->data[name].push_back(datum);
}

void Profiler::startTimer(std::string timer_name)
{
    Profiler* m = getInstance();
    if (m->timers.find(timer_name) == m->timers.end())
    {
        m->timers[timer_name] = Stopwatch();
    }
    m->timers[timer_name](RESET);
}

double Profiler::record(std::string timer_name)
{
    Profiler* m = getInstance();
    if (m->timers.find(timer_name) == m->timers.end())
    {
        std::cout << "Attempting to record timer \""<< timer_name <<
            "\" before timer started\n";
        assert(false);
    }
    double time_elapsed = m->timers[timer_name]();
    m->addData(timer_name, time_elapsed);
    return time_elapsed;
}

std::vector<double> Profiler::getData(std::string name)
{
    Profiler* m = getInstance();
    return m->data[name];
}

void Profiler::printSingleSummary(std::string name)
{
    Profiler* m = getInstance();
    std::string box = std::string(2+name.length(), '=');
    std::cout << " ." << box << ". " << "\n";
    std::cout << "|| " << name << " || Summary :\n";
    std::cout << " '" << box << "' " << "\n";
    if (m->data.find(name) == m->data.end())
    {
        std::cout << name << " never called\n\n";
        return;
    }

    std::vector<double> data = m->getData(name);

    size_t n = data.size();
    double sum = 0;
    for(auto& num : data)
    {
        sum += num;
    }

    std::cout << "total time : " << sum << " s\n";
    std::cout << "called " << n << " times\n";
    std::cout << "min time   : "   << *std::min_element(data.begin(), data.end()) << "s\n";
    std::cout << "max time   : "   << *std::max_element(data.begin(), data.end()) << "s\n";
    std::cout << "average    : "   << sum/(double)n << "s\n";

    std::cout << "\n";
}

void Profiler::printGroupSummary(const std::vector<std::string> &names)
{

    Profiler* m = getInstance();
    std::cout << " .=======================. \n";
    std::cout << "||    Profile Summary    ||\n";
    std::cout << " '=======================' \n";

    std::size_t label_len = max_element(names.begin(), names.end(),
                                        [] (const std::string &a, const std::string &b)
                                        {return a.length() < b.length();}) -> length() + 2;

    label_len = std::max(label_len, (size_t)8);

    const std::string label_format = ("%-" + std::to_string(label_len) + "s");

    printf(label_format.c_str(), "Label");
    printf("%16s", "tot time (s)");
    printf("%16s", "num_calls");
    printf("%16s", "avg time (s)");
    printf("\n");

    std::string seperator = std::string(label_len-2, '~') + "      " + std::string(12, '.')
        + "       " + std::string(9, '~') + "    " + std::string(12, '.');

    for(const auto& name: names)
    {
        if(name.find("~~~~~")==0)
        {

            printf("%s\n", seperator.c_str());
            continue;
        }
        printf(label_format.c_str(), name.c_str());
        double tot_time = 0.0;
        double avg_time = 0.0;
        size_t num_calls = 0;
        if(m->data.find(name) != m->data.end())
        {
            std::vector<double> &data = m->data[name];
            tot_time = 0;
            for(auto& val : data)
            {
                tot_time += val;
            }
            num_calls = data.size();
            avg_time = tot_time/(double)num_calls;
        }
        printf(" %15f %15ld %15f\n", tot_time, num_calls, avg_time);
    }
}

void Profiler::writeGroupSummary(const std::string &filename,
                                 const std::vector<std::string> &names)
{
    FILE * outfile;
    outfile = std::fopen(filename.c_str(), "a");

    Profiler* m = getInstance();
    // std::cout << " .=======================. \n";
    // std::cout << "||    Profile Summary    ||\n";
    // std::cout << " '=======================' \n";

    std::size_t label_len = max_element(names.begin(), names.end(),
                                        [] (const std::string &a, const std::string &b)
                                        {return a.length() < b.length();}) -> length() + 2;

    label_len = std::max(label_len, (size_t)8);

    const std::string label_format = ("%-" + std::to_string(label_len) + "s");

    fprintf(outfile, label_format.c_str(), "Label");
    fprintf(outfile, "%16s", "tot time (s)");
    fprintf(outfile, "%16s", "num_calls");
    fprintf(outfile, "%16s", "avg time (s)");
    fprintf(outfile, "\n");

    std::string seperator = std::string(label_len-2, '~') + "      " + std::string(12, '.')
        + "       " + std::string(9, '~') + "    " + std::string(12, '.');

    for(const auto& name: names)
    {
        if(name.find("~~~~~")==0)
        {

            fprintf(outfile, "%s\n", seperator.c_str());
            continue;
        }
        fprintf(outfile, label_format.c_str(), name.c_str());
        double tot_time = 0.0;
        double avg_time = 0.0;
        size_t num_calls = 0;
        if(m->data.find(name) != m->data.end())
        {
            std::vector<double> &data = m->data[name];
            tot_time = 0;
            for(auto& val : data)
            {
                tot_time += val;
            }
            num_calls = data.size();
            avg_time = tot_time/(double)num_calls;
        }
        fprintf(outfile, " %15f %15ld %15f\n", tot_time, num_calls, avg_time);

    }
    std::fclose(outfile);

}
<commit_msg>Create file if it does not exist<commit_after>#include "arc_utilities/timing.hpp"
#include <iostream>
#include <cassert>
#include <algorithm>
#include <cstdio>

using namespace arc_utilities;

double GlobalStopwatch(const StopwatchControl control)
{
    static Stopwatch global_stopwatch;
    return global_stopwatch(control);
}

Profiler* Profiler::m_instance = NULL;

Profiler* Profiler::getInstance()
{
    if (m_instance == NULL)
    {
        m_instance = new Profiler();
    }
    return m_instance;
}

void Profiler::reset_and_preallocate(size_t num_names, size_t num_events)
{
    Profiler* monitor = getInstance();
    monitor->data.clear();
    monitor->prealloc_buffer.resize(num_names);
    for (size_t i=0; i<num_names; i++)
    {
        monitor->prealloc_buffer[i].reserve(num_events);
    }
}

void Profiler::reset(std::string name)
{
    Profiler* m = getInstance();
    if(m->data.find(name) != m->data.end())
    {
        m->data[name].resize(0);
        startTimer(name);
    }

}

void Profiler::addData(std::string name, double datum)
{
    Profiler* m = getInstance();
    if (m->data.find(name) == m->data.end())
    {
        m->data[name] = std::vector<double>();
        if (m->prealloc_buffer.size() > 0)
        {
            m->data[name].swap(m->prealloc_buffer.back());
            m->prealloc_buffer.pop_back();
        }
    }
    m->data[name].push_back(datum);
}

void Profiler::startTimer(std::string timer_name)
{
    Profiler* m = getInstance();
    if (m->timers.find(timer_name) == m->timers.end())
    {
        m->timers[timer_name] = Stopwatch();
    }
    m->timers[timer_name](RESET);
}

double Profiler::record(std::string timer_name)
{
    Profiler* m = getInstance();
    if (m->timers.find(timer_name) == m->timers.end())
    {
        std::cout << "Attempting to record timer \""<< timer_name <<
            "\" before timer started\n";
        assert(false);
    }
    double time_elapsed = m->timers[timer_name]();
    m->addData(timer_name, time_elapsed);
    return time_elapsed;
}

std::vector<double> Profiler::getData(std::string name)
{
    Profiler* m = getInstance();
    return m->data[name];
}

void Profiler::printSingleSummary(std::string name)
{
    Profiler* m = getInstance();
    std::string box = std::string(2+name.length(), '=');
    std::cout << " ." << box << ". " << "\n";
    std::cout << "|| " << name << " || Summary :\n";
    std::cout << " '" << box << "' " << "\n";
    if (m->data.find(name) == m->data.end())
    {
        std::cout << name << " never called\n\n";
        return;
    }

    std::vector<double> data = m->getData(name);

    size_t n = data.size();
    double sum = 0;
    for(auto& num : data)
    {
        sum += num;
    }

    std::cout << "total time : " << sum << " s\n";
    std::cout << "called " << n << " times\n";
    std::cout << "min time   : "   << *std::min_element(data.begin(), data.end()) << "s\n";
    std::cout << "max time   : "   << *std::max_element(data.begin(), data.end()) << "s\n";
    std::cout << "average    : "   << sum/(double)n << "s\n";

    std::cout << "\n";
}

void Profiler::printGroupSummary(const std::vector<std::string> &names)
{

    Profiler* m = getInstance();
    std::cout << " .=======================. \n";
    std::cout << "||    Profile Summary    ||\n";
    std::cout << " '=======================' \n";

    std::size_t label_len = max_element(names.begin(), names.end(),
                                        [] (const std::string &a, const std::string &b)
                                        {return a.length() < b.length();}) -> length() + 2;

    label_len = std::max(label_len, (size_t)8);

    const std::string label_format = ("%-" + std::to_string(label_len) + "s");

    printf(label_format.c_str(), "Label");
    printf("%16s", "tot time (s)");
    printf("%16s", "num_calls");
    printf("%16s", "avg time (s)");
    printf("\n");

    std::string seperator = std::string(label_len-2, '~') + "      " + std::string(12, '.')
        + "       " + std::string(9, '~') + "    " + std::string(12, '.');

    for(const auto& name: names)
    {
        if(name.find("~~~~~")==0)
        {

            printf("%s\n", seperator.c_str());
            continue;
        }
        printf(label_format.c_str(), name.c_str());
        double tot_time = 0.0;
        double avg_time = 0.0;
        size_t num_calls = 0;
        if(m->data.find(name) != m->data.end())
        {
            std::vector<double> &data = m->data[name];
            tot_time = 0;
            for(auto& val : data)
            {
                tot_time += val;
            }
            num_calls = data.size();
            avg_time = tot_time/(double)num_calls;
        }
        printf(" %15f %15ld %15f\n", tot_time, num_calls, avg_time);
    }
}

void Profiler::writeGroupSummary(const std::string &filename,
                                 const std::vector<std::string> &names)
{
    FILE * outfile;
    outfile = std::fopen(filename.c_str(), "a+");

    Profiler* m = getInstance();
    // std::cout << " .=======================. \n";
    // std::cout << "||    Profile Summary    ||\n";
    // std::cout << " '=======================' \n";

    std::size_t label_len = max_element(names.begin(), names.end(),
                                        [] (const std::string &a, const std::string &b)
                                        {return a.length() < b.length();}) -> length() + 2;

    label_len = std::max(label_len, (size_t)8);

    const std::string label_format = ("%-" + std::to_string(label_len) + "s");

    fprintf(outfile, label_format.c_str(), "Label");
    fprintf(outfile, "%16s", "tot time (s)");
    fprintf(outfile, "%16s", "num_calls");
    fprintf(outfile, "%16s", "avg time (s)");
    fprintf(outfile, "\n");

    std::string seperator = std::string(label_len-2, '~') + "      " + std::string(12, '.')
        + "       " + std::string(9, '~') + "    " + std::string(12, '.');

    for(const auto& name: names)
    {
        if(name.find("~~~~~")==0)
        {

            fprintf(outfile, "%s\n", seperator.c_str());
            continue;
        }
        fprintf(outfile, label_format.c_str(), name.c_str());
        double tot_time = 0.0;
        double avg_time = 0.0;
        size_t num_calls = 0;
        if(m->data.find(name) != m->data.end())
        {
            std::vector<double> &data = m->data[name];
            tot_time = 0;
            for(auto& val : data)
            {
                tot_time += val;
            }
            num_calls = data.size();
            avg_time = tot_time/(double)num_calls;
        }
        fprintf(outfile, " %15f %15ld %15f\n", tot_time, num_calls, avg_time);

    }
    std::fclose(outfile);

}
<|endoftext|>


<commit_before>#include "vision.hpp"
#include "operators.hpp"

#include <QTemporaryFile>
#include <iomanip>
#include <iostream>
#include <sstream>

vision::vision (QStatusBar& statusbar, augmentation_widget& augmentation, QObject* parent)
: QObject (parent)
, _movement3d_average (1)
, _failed_frames_counter (0)
, _debug_mode (0)
, _augmentation (augmentation)
, _cam (new QCamera (QCamera::BackFace))
, _video_player (NULL)
, _acquisition (this)
, _operators ()
, _statusbar (statusbar) {
    _cam->setViewfinder (&_acquisition);
    connect (&_acquisition, SIGNAL (frameAvailable (const QVideoFrame&)), this,
    SLOT (frame_callback (const QVideoFrame&)));
    _cam->start ();
}

void vision::set_debug_mode (const int mode) {
    _debug_mode = mode;
}
int vision::debug_mode () {
    return _debug_mode;
}

void vision::set_input (const QCameraInfo& cameraInfo) {
    if (_video_player != NULL) {
        delete _video_player;
    }
    _video_player = NULL;
    if (_cam != NULL) {
        delete _cam;
    }

    _cam = new QCamera (cameraInfo);
    _cam->setViewfinder (&_acquisition);
    _cam->start ();
    if (_cam->status () != QCamera::ActiveStatus) {
        _statusbar.showMessage (QString ("camera status %1").arg (_cam->status ()), 2000);
    }
}

void vision::set_input (const QString& resource_path) {
    QFile resource_file (resource_path);
    if (resource_file.exists ()) {
        auto temp_file  = QTemporaryFile::createNativeFile (resource_file);
        QString fs_path = temp_file->fileName ();

        if (!fs_path.isEmpty ()) {
            if (_cam != NULL) {
                delete _cam;
            }
            _cam = NULL;
            if (_video_player != NULL) {
                delete _video_player;
            }

            _video_player = new QMediaPlayer ();
            _video_player->setVideoOutput (&_acquisition);
            _video_player->setMedia (QUrl::fromLocalFile (fs_path));
            _video_player->play ();
        }
    }
}

void vision::set_paused (bool paused) {
    if (paused) {
        disconnect (&_acquisition, SIGNAL (frameAvailable (const QVideoFrame&)),
        this, SLOT (frame_callback (const QVideoFrame&)));
    } else {
        connect (&_acquisition, SIGNAL (frameAvailable (const QVideoFrame&)),
        this, SLOT (frame_callback (const QVideoFrame&)));
    }
}

void set_focus () {
    ; // TODO: add focus implementation
}

void vision::set_reference () {
    _markers_mutex.lock ();
    _reference = _markers;
    _markers_mutex.unlock ();
}

void vision::frame_callback (const QVideoFrame& const_buffer) {
    bool status = true;
    image_t image;
    if (const_buffer.isValid ()) {
        // copy image into cpu memory
        QVideoFrame frame (const_buffer);
        if (frame.map (QAbstractVideoBuffer::ReadOnly)) {
            image.data = (uint8_t*)malloc (frame.mappedBytes ());
            memcpy (image.data, frame.bits (), frame.mappedBytes ());

            if (frame.pixelFormat () == QVideoFrame::Format_RGB24) {
                image.format = RGB24;
                image.width  = frame.width ();
                image.height = frame.height ();
            } else if (frame.pixelFormat () == QVideoFrame::Format_YUV420P) {
                image.format = YUV;
                image.width  = frame.width ();
                image.height = frame.height ();
            } else {
                _statusbar.showMessage (
                QString ("unsuported format %1").arg (frame.pixelFormat ()), 2000);
            }
        } else {
            status = false;
        }
        frame.unmap ();
    }

    if (status) {
        if (_debug_mode == 0) {
            _augmentation.setBackground (image);
            _augmentation.update ();
        }
        // start image processing
        _operators.preprocessing (image);
        if (_debug_mode == 1) {
            _augmentation.setBackground (image);
            _augmentation.update ();
        }

        _operators.segmentation (image);
        if (_debug_mode == 2) {
            _augmentation.setBackground (image);
            _augmentation.update ();
        }

        _markers_mutex.lock ();
        _markers.clear ();
        _operators.extraction (image, _markers);
        if (_debug_mode == 3) {
            _augmentation.setBackground (image);
            _augmentation.update ();
        }

        movement3d movement;
        _operators.classification (_reference, _markers, movement); // classify
        _markers_mutex.unlock ();
        movement = _movement3d_average.average (movement);
        _augmentation.setScale (movement.scale ());
        translation_t translation = movement.translation ();
        movement.translation (
        { movement.translation_delta_to_absolute (translation.x, image.width, -1, 1),
        movement.translation_delta_to_absolute (translation.y, image.height, -1, 1) });
        _augmentation.setXPosition (movement.translation ().x);
        _augmentation.setYPosition (movement.translation ().y);

        _augmentation.setYRotation (movement.yaw ());
        _augmentation.setZRotation (movement.roll ());
        _augmentation.setXRotation ((movement.pitch ()) - 90);
        std::cout << movement << std::endl;

        std::stringstream stream;
        stream << std::setprecision (2);
        // stream << "T(" << movement.translation ().x << ","
        //        << movement.translation ().y << ") ";
        stream << "S: " << movement.scale () << " ";
        stream << "yaw: " << movement.yaw () << " ";
        stream << "pitch: " << movement.pitch () << " ";
        stream << "roll: " << movement.roll () << std::endl;
        _statusbar.showMessage (stream.str ().c_str ());

        QImage debug_image ((const unsigned char*)image.data, image.width,
        image.height, QImage::Format_Grayscale8);
        debug_image.save ("debug_image.png");

        delete image.data;
    }
}
<commit_msg>fix error handling when not enough markers are found<commit_after>#include "vision.hpp"
#include "operators.hpp"

#include <QTemporaryFile>
#include <iomanip>
#include <iostream>
#include <sstream>

vision::vision (QStatusBar& statusbar, augmentation_widget& augmentation, QObject* parent)
: QObject (parent)
, _movement3d_average (1)
, _failed_frames_counter (0)
, _debug_mode (0)
, _augmentation (augmentation)
, _cam (new QCamera (QCamera::BackFace))
, _video_player (NULL)
, _acquisition (this)
, _operators ()
, _statusbar (statusbar) {
    _cam->setViewfinder (&_acquisition);
    connect (&_acquisition, SIGNAL (frameAvailable (const QVideoFrame&)), this,
    SLOT (frame_callback (const QVideoFrame&)));
    _cam->start ();
}

void vision::set_debug_mode (const int mode) {
    _debug_mode = mode;
}
int vision::debug_mode () {
    return _debug_mode;
}

void vision::set_input (const QCameraInfo& cameraInfo) {
    if (_video_player != NULL) {
        delete _video_player;
    }
    _video_player = NULL;
    if (_cam != NULL) {
        delete _cam;
    }

    _cam = new QCamera (cameraInfo);
    _cam->setViewfinder (&_acquisition);
    _cam->start ();
    if (_cam->status () != QCamera::ActiveStatus) {
        _statusbar.showMessage (QString ("camera status %1").arg (_cam->status ()), 2000);
    }
}

void vision::set_input (const QString& resource_path) {
    QFile resource_file (resource_path);
    if (resource_file.exists ()) {
        auto temp_file  = QTemporaryFile::createNativeFile (resource_file);
        QString fs_path = temp_file->fileName ();

        if (!fs_path.isEmpty ()) {
            if (_cam != NULL) {
                delete _cam;
            }
            _cam = NULL;
            if (_video_player != NULL) {
                delete _video_player;
            }

            _video_player = new QMediaPlayer ();
            _video_player->setVideoOutput (&_acquisition);
            _video_player->setMedia (QUrl::fromLocalFile (fs_path));
            _video_player->play ();
        }
    }
}

void vision::set_paused (bool paused) {
    if (paused) {
        disconnect (&_acquisition, SIGNAL (frameAvailable (const QVideoFrame&)),
        this, SLOT (frame_callback (const QVideoFrame&)));
    } else {
        connect (&_acquisition, SIGNAL (frameAvailable (const QVideoFrame&)),
        this, SLOT (frame_callback (const QVideoFrame&)));
    }
}

void set_focus () {
    ; // TODO: add focus implementation
}

void vision::set_reference () {
    _markers_mutex.lock ();
    _reference = _markers;
    _markers_mutex.unlock ();
}

void vision::frame_callback (const QVideoFrame& const_buffer) {
    bool status = true;
    image_t image;
    if (const_buffer.isValid ()) {
        // copy image into cpu memory
        QVideoFrame frame (const_buffer);
        if (frame.map (QAbstractVideoBuffer::ReadOnly)) {
            image.data = (uint8_t*)malloc (frame.mappedBytes ());
            memcpy (image.data, frame.bits (), frame.mappedBytes ());

            if (frame.pixelFormat () == QVideoFrame::Format_RGB24) {
                image.format = RGB24;
                image.width  = frame.width ();
                image.height = frame.height ();
            } else if (frame.pixelFormat () == QVideoFrame::Format_YUV420P) {
                image.format = YUV;
                image.width  = frame.width ();
                image.height = frame.height ();
            } else {
                _statusbar.showMessage (
                QString ("unsuported format %1").arg (frame.pixelFormat ()), 2000);
            }
        } else {
            status = false;
        }
        frame.unmap ();
    }

    if (status) {
        if (_debug_mode == 0) {
            _augmentation.setBackground (image);
            _augmentation.update ();
        }
        // start image processing
        _operators.preprocessing (image);
        if (_debug_mode == 1) {
            _augmentation.setBackground (image);
            _augmentation.update ();
        }

        _operators.segmentation (image);
        if (_debug_mode == 2) {
            _augmentation.setBackground (image);
            _augmentation.update ();
        }

        _markers_mutex.lock ();
        _markers.clear ();
        _operators.extraction (image, _markers);
        if (_debug_mode == 3) {
            _augmentation.setBackground (image);
            _augmentation.update ();
        }

        movement3d movement;
        bool clasified = _operators.classification (_reference, _markers, movement); // classify
        if (clasified) {
            _markers_mutex.unlock ();
            movement = _movement3d_average.average (movement);
            _augmentation.setScale (movement.scale ());
            translation_t translation = movement.translation ();
            movement.translation (
            { movement.translation_delta_to_absolute (translation.x, image.width, -1, 1),
            movement.translation_delta_to_absolute (translation.y, image.height, -1, 1) });
            _augmentation.setXPosition (movement.translation ().x);
            _augmentation.setYPosition (movement.translation ().y);

            _augmentation.setYRotation (movement.yaw ());
            _augmentation.setZRotation (movement.roll ());
            _augmentation.setXRotation ((movement.pitch ()) - 90);
            std::cout << movement << std::endl;

            std::stringstream stream;
            stream << std::setprecision (2);
            // stream << "T(" << movement.translation ().x << ","
            //        << movement.translation ().y << ") ";
            stream << "S: " << movement.scale () << " ";
            stream << "yaw: " << movement.yaw () << " ";
            stream << "pitch: " << movement.pitch () << " ";
            stream << "roll: " << movement.roll () << std::endl;
            _statusbar.showMessage (stream.str ().c_str ());
        } else {
            _statusbar.showMessage ("No markers! You idiot...");
        }

        QImage debug_image ((const unsigned char*)image.data, image.width,
        image.height, QImage::Format_Grayscale8);
        debug_image.save ("debug_image.png");

        delete image.data;
    }
}
<|endoftext|>


<commit_before>/*!
 * @file window.cpp
 *
 * @brief Window class source file
 */

#include <algorithm>

#include "window.hpp"

#include "spoa/spoa.hpp"

namespace racon {

std::shared_ptr<Window> createWindow(uint64_t id, uint32_t rank, WindowType type,
    const char* backbone, uint32_t backbone_length, const char* quality,
    uint32_t quality_length) {

    if (backbone_length == 0 || backbone_length != quality_length) {
        fprintf(stderr, "[racon::createWindow] error: "
            "empty backbone sequence/unequal quality length!\n");
        exit(1);
    }

    return std::shared_ptr<Window>(new Window(id, rank, type, backbone,
        backbone_length, quality, quality_length));
}

Window::Window(uint64_t id, uint32_t rank, WindowType type, const char* backbone,
    uint32_t backbone_length, const char* quality, uint32_t quality_length)
        : id_(id), rank_(rank), type_(type), consensus_(), sequences_(),
        qualities_(), positions_() {

    sequences_.emplace_back(backbone, backbone_length);
    qualities_.emplace_back(quality, quality_length);
    positions_.emplace_back(0, 0);
}

Window::~Window() {
}

void Window::add_layer(const char* sequence, uint32_t sequence_length,
    const char* quality, uint32_t quality_length, uint32_t begin, uint32_t end) {

    if (quality != nullptr && sequence_length != quality_length) {
        fprintf(stderr, "[racon::Window::add_layer] error: "
            "unequal quality size!\n");
        exit(1);
    }
    if (begin >= end || begin > sequences_.front().second || end > sequences_.front().second) {
        fprintf(stderr, "[racon::Window::add_layer] error: "
            "layer begin and end positions are invalid!\n");
        exit(1);
    }

    sequences_.emplace_back(sequence, sequence_length);
    qualities_.emplace_back(quality, quality_length);
    positions_.emplace_back(begin, end);
}

bool Window::generate_consensus(std::shared_ptr<spoa::AlignmentEngine> alignment_engine) {

    if (sequences_.size() < 3) {
        consensus_ = std::string(sequences_.front().first, sequences_.front().second);
        return false;
    }

    auto graph = spoa::createGraph();
    graph->add_alignment(spoa::Alignment(), sequences_.front().first,
        sequences_.front().second, qualities_.front().first,
        qualities_.front().second);

    std::vector<uint32_t> rank;
    rank.reserve(sequences_.size());
    for (uint32_t i = 0; i < sequences_.size(); ++i) {
        rank.emplace_back(i);
    }

    std::sort(rank.begin() + 1, rank.end(), [&](uint32_t lhs, uint32_t rhs) {
        return positions_[lhs].first < positions_[rhs].first; });

    uint32_t offset = 0.01 * sequences_.front().second;
    for (uint32_t i = 1; i < sequences_.size(); ++i) {
        //uint32_t i = rank[j];

        spoa::Alignment alignment;
        //if (positions_[i].first < offset && positions_[i].second >
        //    sequences_.front().second - offset) {
            alignment = alignment_engine->align_sequence_with_graph(
                sequences_[i].first, sequences_[i].second, graph);
        //} else {
        //    std::vector<int32_t> mapping;
        //    auto subgraph = graph->subgraph(positions_[i].first,
        //        positions_[i].second, mapping);
        //    alignment = alignment_engine->align_sequence_with_graph(
        //        sequences_[i].first, sequences_[i].second, subgraph);
        //    subgraph->update_alignment(alignment, mapping);
        //}

        if (qualities_[i].first == nullptr) {
            graph->add_alignment(alignment, sequences_[i].first,
                sequences_[i].second);
        } else {
            graph->add_alignment(alignment, sequences_[i].first,
                sequences_[i].second, qualities_[i].first,
                qualities_[i].second);
        }
    }

    std::vector<uint32_t> coverages;
    consensus_ = graph->generate_consensus(coverages);

    if (type_ == WindowType::kTGS) {
        uint32_t average_coverage = (sequences_.size() - 1) / 2;

        int32_t begin = 0, end = consensus_.size() - 1;
        for (; begin < static_cast<int32_t>(consensus_.size()); ++begin) {
            if (coverages[begin] >= average_coverage) {
                break;
            }
        }
        for (; end >= 0; --end) {
            if (coverages[end] >= average_coverage) {
                break;
            }
        }

        if (begin >= end) {
            fprintf(stderr, "[racon::Window::generate_consensus] warning: "
                "contig %lu might be chimeric in window %u!\n", id_, rank_);
        } else {
            //consensus_ = consensus_.substr(begin, end - begin + 1);
        }
    }

    return true;
}

}
<commit_msg>undid commenting out of line<commit_after>/*!
 * @file window.cpp
 *
 * @brief Window class source file
 */

#include <algorithm>

#include "window.hpp"

#include "spoa/spoa.hpp"

namespace racon {

std::shared_ptr<Window> createWindow(uint64_t id, uint32_t rank, WindowType type,
    const char* backbone, uint32_t backbone_length, const char* quality,
    uint32_t quality_length) {

    if (backbone_length == 0 || backbone_length != quality_length) {
        fprintf(stderr, "[racon::createWindow] error: "
            "empty backbone sequence/unequal quality length!\n");
        exit(1);
    }

    return std::shared_ptr<Window>(new Window(id, rank, type, backbone,
        backbone_length, quality, quality_length));
}

Window::Window(uint64_t id, uint32_t rank, WindowType type, const char* backbone,
    uint32_t backbone_length, const char* quality, uint32_t quality_length)
        : id_(id), rank_(rank), type_(type), consensus_(), sequences_(),
        qualities_(), positions_() {

    sequences_.emplace_back(backbone, backbone_length);
    qualities_.emplace_back(quality, quality_length);
    positions_.emplace_back(0, 0);
}

Window::~Window() {
}

void Window::add_layer(const char* sequence, uint32_t sequence_length,
    const char* quality, uint32_t quality_length, uint32_t begin, uint32_t end) {

    if (quality != nullptr && sequence_length != quality_length) {
        fprintf(stderr, "[racon::Window::add_layer] error: "
            "unequal quality size!\n");
        exit(1);
    }
    if (begin >= end || begin > sequences_.front().second || end > sequences_.front().second) {
        fprintf(stderr, "[racon::Window::add_layer] error: "
            "layer begin and end positions are invalid!\n");
        exit(1);
    }

    sequences_.emplace_back(sequence, sequence_length);
    qualities_.emplace_back(quality, quality_length);
    positions_.emplace_back(begin, end);
}

bool Window::generate_consensus(std::shared_ptr<spoa::AlignmentEngine> alignment_engine) {

    if (sequences_.size() < 3) {
        consensus_ = std::string(sequences_.front().first, sequences_.front().second);
        return false;
    }

    auto graph = spoa::createGraph();
    graph->add_alignment(spoa::Alignment(), sequences_.front().first,
        sequences_.front().second, qualities_.front().first,
        qualities_.front().second);

    std::vector<uint32_t> rank;
    rank.reserve(sequences_.size());
    for (uint32_t i = 0; i < sequences_.size(); ++i) {
        rank.emplace_back(i);
    }

    std::sort(rank.begin() + 1, rank.end(), [&](uint32_t lhs, uint32_t rhs) {
        return positions_[lhs].first < positions_[rhs].first; });

    uint32_t offset = 0.01 * sequences_.front().second;
    for (uint32_t i = 1; i < sequences_.size(); ++i) {
        //uint32_t i = rank[j];

        spoa::Alignment alignment;
        //if (positions_[i].first < offset && positions_[i].second >
        //    sequences_.front().second - offset) {
            alignment = alignment_engine->align_sequence_with_graph(
                sequences_[i].first, sequences_[i].second, graph);
        //} else {
        //    std::vector<int32_t> mapping;
        //    auto subgraph = graph->subgraph(positions_[i].first,
        //        positions_[i].second, mapping);
        //    alignment = alignment_engine->align_sequence_with_graph(
        //        sequences_[i].first, sequences_[i].second, subgraph);
        //    subgraph->update_alignment(alignment, mapping);
        //}

        if (qualities_[i].first == nullptr) {
            graph->add_alignment(alignment, sequences_[i].first,
                sequences_[i].second);
        } else {
            graph->add_alignment(alignment, sequences_[i].first,
                sequences_[i].second, qualities_[i].first,
                qualities_[i].second);
        }
    }

    std::vector<uint32_t> coverages;
    consensus_ = graph->generate_consensus(coverages);

    if (type_ == WindowType::kTGS) {
        uint32_t average_coverage = (sequences_.size() - 1) / 2;

        int32_t begin = 0, end = consensus_.size() - 1;
        for (; begin < static_cast<int32_t>(consensus_.size()); ++begin) {
            if (coverages[begin] >= average_coverage) {
                break;
            }
        }
        for (; end >= 0; --end) {
            if (coverages[end] >= average_coverage) {
                break;
            }
        }

        if (begin >= end) {
            fprintf(stderr, "[racon::Window::generate_consensus] warning: "
                "contig %lu might be chimeric in window %u!\n", id_, rank_);
        } else {
            consensus_ = consensus_.substr(begin, end - begin + 1);
        }
    }

    return true;
}

}
<|endoftext|>


<commit_before>/*********************************
** Tsunagari Tile Engine        **
** window.cpp                   **
** Copyright 2011-2012 OmegaSDG **
*********************************/

#include <Gosu/Graphics.hpp> // for Gosu::Graphics
#include <Gosu/Timing.hpp>
#include <Gosu/Utility.hpp>

#include "config.h"
#include "resourcer.h"
#include "world.h"
#include "window.h"

static GameWindow* globalWindow = NULL;

const GameWindow& GameWindow::getWindow()
{
	return *globalWindow;
}

GameWindow::GameWindow(ClientValues* conf)
	: Gosu::Window((unsigned)conf->windowSize.x,
	  (unsigned)conf->windowSize.y, conf->fullscreen),
	  lastTime((int)Gosu::milliseconds()),
	  now(lastTime),
	  currentSecond(now/1000),
	  conf(conf)
{
	globalWindow = this;
}

GameWindow::~GameWindow()
{
}

bool GameWindow::init(char** argv)
{
	rc.reset(new Resourcer(this, conf));
	world.reset(new World(this, rc.get(), conf));
	return rc->init(argv) && world->init();
}

int GameWindow::width() const
{
	return (int)graphics().width();
}

int GameWindow::height() const
{
	return (int)graphics().height();
}

void GameWindow::buttonDown(const Gosu::Button btn)
{
	now = (int)Gosu::milliseconds();
	if (btn == Gosu::kbEscape)
		close();
	else {
		if (keystates.find(btn) == keystates.end()) {
			keystate& state = keystates[btn];
			state.since = now;
			state.initiallyResolved = false;
			state.consecutive = false;

			// We process the initial buttonDown here so that it
			// gets handled even if we receive a buttonUp before an
			// update.
			world->buttonDown(btn);
		}
	}
}

void GameWindow::buttonUp(const Gosu::Button btn)
{
	keystates.erase(btn);
	world->buttonUp(btn);
}

void GameWindow::draw()
{
	world->draw();
}

bool GameWindow::needsRedraw() const
{
	return world->needsRedraw();
}

void GameWindow::update()
{
	calculateDt();
	if (conf->moveMode == TURN)
		handleKeyboardInput();
	world->update(dt);

	// Run once per second.
	if (now/1000 > currentSecond) {
		currentSecond = now/1000;
		rc->garbageCollect();
	}
}

int GameWindow::time() const
{
	return now;
}

void GameWindow::calculateDt()
{
	now = (int)Gosu::milliseconds();
	dt = now - lastTime;
	lastTime = now;
}

void GameWindow::handleKeyboardInput()
{
	std::map<Gosu::Button, keystate>::iterator it;

	// Persistent input handling code
	for (it = keystates.begin(); it != keystates.end(); it++) {
		Gosu::Button btn = it->first;
		keystate& state = it->second;

		// If there is PERSIST_DELAY_CONSECUTIVE milliseconds of latency
		// between when a button is depressed and when we first look at
		// it here, we'll incorrectly try to fire off a second round of
		// input.
		// This can happen if an intermediary function blocks the thread
		// for a while.
		if (!state.initiallyResolved) {
			state.initiallyResolved = true;
			continue;
		}

		int delay = state.consecutive ?
		    ROGUELIKE_PERSIST_DELAY_CONSECUTIVE : ROGUELIKE_PERSIST_DELAY_INIT;
		if (now >= state.since + delay) {
			state.since = now;
			world->buttonDown(btn);
			state.consecutive = true;
		}
	}
}

<commit_msg>fix Gosu's faux fullscreen aspect ratio<commit_after>/*********************************
** Tsunagari Tile Engine        **
** window.cpp                   **
** Copyright 2011-2012 OmegaSDG **
*********************************/

#include <Gosu/Graphics.hpp> // for Gosu::Graphics
#include <Gosu/Timing.hpp>
#include <Gosu/Utility.hpp>

#include "config.h"
#include "resourcer.h"
#include "world.h"
#include "window.h"

static GameWindow* globalWindow = NULL;

const GameWindow& GameWindow::getWindow()
{
	return *globalWindow;
}

GameWindow::GameWindow(ClientValues* conf)
	// Gosu emulates the requested screen resolution on fullscreen,
	// but this breaks our aspect ratio-correcting letterbox.
	// Ergo we just make a window the size of the screen.
	: Gosu::Window(
	    conf->fullscreen ? Gosu::screenWidth() :
	                       (unsigned)conf->windowSize.x,
	    conf->fullscreen ? Gosu::screenHeight() :
	                       (unsigned)conf->windowSize.y,
	    conf->fullscreen
	  ),
	  lastTime((int)Gosu::milliseconds()),
	  now(lastTime),
	  currentSecond(now/1000),
	  conf(conf)
{
	globalWindow = this;
}

GameWindow::~GameWindow()
{
}

bool GameWindow::init(char** argv)
{
	rc.reset(new Resourcer(this, conf));
	world.reset(new World(this, rc.get(), conf));
	return rc->init(argv) && world->init();
}

int GameWindow::width() const
{
	return (int)graphics().width();
}

int GameWindow::height() const
{
	return (int)graphics().height();
}

void GameWindow::buttonDown(const Gosu::Button btn)
{
	now = (int)Gosu::milliseconds();
	if (btn == Gosu::kbEscape)
		close();
	else {
		if (keystates.find(btn) == keystates.end()) {
			keystate& state = keystates[btn];
			state.since = now;
			state.initiallyResolved = false;
			state.consecutive = false;

			// We process the initial buttonDown here so that it
			// gets handled even if we receive a buttonUp before an
			// update.
			world->buttonDown(btn);
		}
	}
}

void GameWindow::buttonUp(const Gosu::Button btn)
{
	keystates.erase(btn);
	world->buttonUp(btn);
}

void GameWindow::draw()
{
	world->draw();
}

bool GameWindow::needsRedraw() const
{
	return world->needsRedraw();
}

void GameWindow::update()
{
	calculateDt();
	if (conf->moveMode == TURN)
		handleKeyboardInput();
	world->update(dt);

	// Run once per second.
	if (now/1000 > currentSecond) {
		currentSecond = now/1000;
		rc->garbageCollect();
	}
}

int GameWindow::time() const
{
	return now;
}

void GameWindow::calculateDt()
{
	now = (int)Gosu::milliseconds();
	dt = now - lastTime;
	lastTime = now;
}

void GameWindow::handleKeyboardInput()
{
	std::map<Gosu::Button, keystate>::iterator it;

	// Persistent input handling code
	for (it = keystates.begin(); it != keystates.end(); it++) {
		Gosu::Button btn = it->first;
		keystate& state = it->second;

		// If there is PERSIST_DELAY_CONSECUTIVE milliseconds of latency
		// between when a button is depressed and when we first look at
		// it here, we'll incorrectly try to fire off a second round of
		// input.
		// This can happen if an intermediary function blocks the thread
		// for a while.
		if (!state.initiallyResolved) {
			state.initiallyResolved = true;
			continue;
		}

		int delay = state.consecutive ?
		    ROGUELIKE_PERSIST_DELAY_CONSECUTIVE : ROGUELIKE_PERSIST_DELAY_INIT;
		if (now >= state.since + delay) {
			state.since = now;
			world->buttonDown(btn);
			state.consecutive = true;
		}
	}
}

<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Devices/LabJack/LabJackDevice.h"

#include "SurgSim/Devices/LabJack/LabJackScaffold.h"
#include "SurgSim/Framework/Log.h"

namespace SurgSim
{
namespace Device
{

LabJackDevice::LabJackDevice(const std::string& uniqueName) :
	SurgSim::Input::CommonDevice(uniqueName, LabJackScaffold::buildDeviceInputData()),
	m_model(LabJack::MODEL_SEARCH),
	m_connection(LabJack::CONNECTION_SEARCH),
	m_address(""),
	m_timerBase(LabJack::TIMERBASE_DEFAULT),
	m_timerClockDivisor(1),
	m_timerCounterPinOffset(0),
	m_threadRate(1000.0),
	m_analogInputResolution(0),
	m_analogInputSettling(0)
{
}

LabJackDevice::~LabJackDevice()
{
	if (isInitialized())
	{
		finalize();
	}
}

bool LabJackDevice::initialize()
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice already initialized.";

	if (getDigitalOutputs().size() > 0)
	{
		SURGSIM_ASSERT(hasOutputProducer()) << "LabJackDevice named " << getName() <<
			" has digital output channels. An output producer is required, call setOutputProducer.";
	}

	if (getAnalogOutputs().size() > 0)
	{
		SURGSIM_ASSERT(hasOutputProducer()) << "LabJackDevice named " << getName() <<
			" has analog output channels. An output producer is required, call setOutputProducer.";
	}

	if (getTimers().size() > 0)
	{
		SURGSIM_ASSERT(hasOutputProducer()) << "LabJackDevice named " << getName() <<
			" has timers. An output producer is required, call setOutputProducer.";
	}

	std::shared_ptr<LabJackScaffold> scaffold = LabJackScaffold::getOrCreateSharedInstance();
	SURGSIM_ASSERT(scaffold) << "LabJackDevice failed to get a LabJackScaffold.";

	bool found = false;
	// registerDevice will set this object's type and/or connection, if they are currently set to SEARCH.
	if (scaffold->registerDevice(this))
	{
		m_scaffold = std::move(scaffold);
		SURGSIM_LOG_INFO(m_scaffold->getLogger()) << "Device " << getName() << ": Initialized.";
		found = true;
	}
	return found;
}

bool LabJackDevice::finalize()
{
	SURGSIM_ASSERT(isInitialized()) << "LabJackDevice has not been initialized before finalize.";
	SURGSIM_LOG_INFO(m_scaffold->getLogger()) << "Device " << getName() << ": " << "Finalizing.";
	const bool ok = m_scaffold->unregisterDevice(this);
	m_scaffold.reset();
	return ok;
}

bool LabJackDevice::isInitialized() const
{
	return (m_scaffold != nullptr);
}

void LabJackDevice::setModel(LabJack::Model model)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's model cannot be set after it is initialized.";
	m_model = model;
}

LabJack::Model LabJackDevice::getModel() const
{
	return m_model;
}

void LabJackDevice::setConnection(LabJack::Connection connection)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's connection cannot be set after it is initialized.";
	m_connection = connection;
}

LabJack::Connection LabJackDevice::getConnection() const
{
	return m_connection;
}

void LabJackDevice::setAddress(std::string address)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's address cannot be set after it is initialized.";
	m_address = address;
}

const std::string& LabJackDevice::getAddress() const
{
	return m_address;
}

void LabJackDevice::enableDigitalInput(int channel)
{
	SURGSIM_ASSERT(!isInitialized()) << "Digital input cannot be enabled for a LabJackDevice after it is initialized.";
	m_digitalInputChannels.insert(channel);
}

const std::unordered_set<int>& LabJackDevice::getDigitalInputs() const
{
	return m_digitalInputChannels;
}

void LabJackDevice::enableDigitalOutput(int channel)
{
	SURGSIM_ASSERT(!isInitialized()) << "Digital output cannot be enabled for a LabJackDevice after it is initialized.";
	m_digitalOutputChannels.insert(channel);
}

const std::unordered_set<int>& LabJackDevice::getDigitalOutputs() const
{
	return m_digitalOutputChannels;
}

void LabJackDevice::setTimerBase(LabJack::TimerBase base)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's timer base cannot be set after it is initialized.";
	m_timerBase = base;
}

LabJack::TimerBase LabJackDevice::getTimerBase() const
{
	return m_timerBase;
}

void LabJackDevice::setTimerClockDivisor(int divisor)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's timer clock divisor cannot be set after it is initialized.";
	m_timerClockDivisor = divisor;
}

int LabJackDevice::getTimerClockDivisor() const
{
	return m_timerClockDivisor;
}

void LabJackDevice::setTimerCounterPinOffset(int offset)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"LabJackDevice's timer/counter pin offset cannot be set after it is initialized.";
	m_timerCounterPinOffset = offset;
}

int LabJackDevice::getTimerCounterPinOffset() const
{
	return m_timerCounterPinOffset;
}

void LabJackDevice::enableTimer(int index, LabJack::TimerMode mode)
{
	SURGSIM_ASSERT(!isInitialized()) << "Timers cannot be enabled for a LabJackDevice after it is initialized.";
	m_timers[index] = mode;
}

const std::unordered_map<int, LabJack::TimerMode>& LabJackDevice::getTimers() const
{
	return m_timers;
}

void LabJackDevice::setMaximumUpdateRate(double rate)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"LabJackDevice's maximum update rate cannot be set after it is initialized.";
	m_threadRate = rate;
}

double LabJackDevice::getMaximumUpdateRate() const
{
	return m_threadRate;
}

void LabJackDevice::enableAnalogInput(int positiveChannel, LabJack::Range range, int negativeChannel)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"Analog inputs cannot be enabled for a LabJackDevice after it is initialized.";
	LabJack::RangeAndOptionalNegativeChannel rangeAndOptionalNegativeChannel = {range,
		SurgSim::DataStructures::OptionalValue<int>(negativeChannel)};
	m_analogInputs[positiveChannel] = std::move(rangeAndOptionalNegativeChannel);
}

void LabJackDevice::enableAnalogInput(int channel, LabJack::Range range)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"Analog inputs cannot be enabled for a LabJackDevice after it is initialized.";
	LabJack::RangeAndOptionalNegativeChannel rangeAndOptionalNegativeChannel = {range,
		SurgSim::DataStructures::OptionalValue<int>()};
	m_analogInputs[channel] = std::move(rangeAndOptionalNegativeChannel);
}

const std::unordered_map<int, LabJack::RangeAndOptionalNegativeChannel>& LabJackDevice::getAnalogInputs() const
{
	return m_analogInputs;
}

void LabJackDevice::enableAnalogOutput(int channel)
{
	SURGSIM_ASSERT(!isInitialized()) << "Analog outputs cannot be enabled for a LabJackDevice after it is initialized.";
	m_analogOutputChannels.insert(channel);
}

const std::unordered_set<int>& LabJackDevice::getAnalogOutputs() const
{
	return m_analogOutputChannels;
}

void LabJackDevice::setAnalogInputResolution(int resolution)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"Analog input resolution cannot be set for a LabJackDevice after it is initialized.";
	m_analogInputResolution = resolution;
}

int LabJackDevice::getAnalogInputResolution() const
{
	return m_analogInputResolution;
}

void LabJackDevice::setAnalogInputSettling(int settling)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"Analog input settling time cannot be set for a LabJackDevice after it is initialized.";
	m_analogInputSettling = settling;
}

int LabJackDevice::getAnalogInputSettling() const
{
	return m_analogInputSettling;
}

};  // namespace Device
};  // namespace SurgSim
<commit_msg>LabJackDevice logs to Warning if it has outputs but no OutputProducer. Inputs will work fine, so it does not assert. No longer checks for timers, which can work without output data.<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Devices/LabJack/LabJackDevice.h"

#include "SurgSim/Devices/LabJack/LabJackScaffold.h"
#include "SurgSim/Framework/Log.h"

namespace SurgSim
{
namespace Device
{

LabJackDevice::LabJackDevice(const std::string& uniqueName) :
	SurgSim::Input::CommonDevice(uniqueName, LabJackScaffold::buildDeviceInputData()),
	m_model(LabJack::MODEL_SEARCH),
	m_connection(LabJack::CONNECTION_SEARCH),
	m_address(""),
	m_timerBase(LabJack::TIMERBASE_DEFAULT),
	m_timerClockDivisor(1),
	m_timerCounterPinOffset(0),
	m_threadRate(1000.0),
	m_analogInputResolution(0),
	m_analogInputSettling(0)
{
}

LabJackDevice::~LabJackDevice()
{
	if (isInitialized())
	{
		finalize();
	}
}

bool LabJackDevice::initialize()
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice already initialized.";

	std::shared_ptr<LabJackScaffold> scaffold = LabJackScaffold::getOrCreateSharedInstance();
	SURGSIM_ASSERT(scaffold) << "LabJackDevice failed to get a LabJackScaffold.";

	if (getDigitalOutputs().size() > 0)
	{
		SURGSIM_LOG_IF(!hasOutputProducer(), scaffold->getLogger(), WARNING) << "LabJackDevice named " << getName() <<
			" has digital output channels but no output producer to provide the output data. Call setOutputProducer.";
	}

	if (getAnalogOutputs().size() > 0)
	{
		SURGSIM_LOG_IF(!hasOutputProducer(), scaffold->getLogger(), WARNING) << "LabJackDevice named " << getName() <<
			" has analog output channels but no output producer to provide the output data. Call setOutputProducer.";
	}

	bool found = false;
	// registerDevice will set this object's type and/or connection, if they are currently set to SEARCH.
	if (scaffold->registerDevice(this))
	{
		m_scaffold = std::move(scaffold);
		SURGSIM_LOG_INFO(m_scaffold->getLogger()) << "Device " << getName() << ": Initialized.";
		found = true;
	}
	return found;
}

bool LabJackDevice::finalize()
{
	SURGSIM_ASSERT(isInitialized()) << "LabJackDevice has not been initialized before finalize.";
	SURGSIM_LOG_INFO(m_scaffold->getLogger()) << "Device " << getName() << ": " << "Finalizing.";
	const bool ok = m_scaffold->unregisterDevice(this);
	m_scaffold.reset();
	return ok;
}

bool LabJackDevice::isInitialized() const
{
	return (m_scaffold != nullptr);
}

void LabJackDevice::setModel(LabJack::Model model)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's model cannot be set after it is initialized.";
	m_model = model;
}

LabJack::Model LabJackDevice::getModel() const
{
	return m_model;
}

void LabJackDevice::setConnection(LabJack::Connection connection)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's connection cannot be set after it is initialized.";
	m_connection = connection;
}

LabJack::Connection LabJackDevice::getConnection() const
{
	return m_connection;
}

void LabJackDevice::setAddress(std::string address)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's address cannot be set after it is initialized.";
	m_address = address;
}

const std::string& LabJackDevice::getAddress() const
{
	return m_address;
}

void LabJackDevice::enableDigitalInput(int channel)
{
	SURGSIM_ASSERT(!isInitialized()) << "Digital input cannot be enabled for a LabJackDevice after it is initialized.";
	m_digitalInputChannels.insert(channel);
}

const std::unordered_set<int>& LabJackDevice::getDigitalInputs() const
{
	return m_digitalInputChannels;
}

void LabJackDevice::enableDigitalOutput(int channel)
{
	SURGSIM_ASSERT(!isInitialized()) << "Digital output cannot be enabled for a LabJackDevice after it is initialized.";
	m_digitalOutputChannels.insert(channel);
}

const std::unordered_set<int>& LabJackDevice::getDigitalOutputs() const
{
	return m_digitalOutputChannels;
}

void LabJackDevice::setTimerBase(LabJack::TimerBase base)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's timer base cannot be set after it is initialized.";
	m_timerBase = base;
}

LabJack::TimerBase LabJackDevice::getTimerBase() const
{
	return m_timerBase;
}

void LabJackDevice::setTimerClockDivisor(int divisor)
{
	SURGSIM_ASSERT(!isInitialized()) << "LabJackDevice's timer clock divisor cannot be set after it is initialized.";
	m_timerClockDivisor = divisor;
}

int LabJackDevice::getTimerClockDivisor() const
{
	return m_timerClockDivisor;
}

void LabJackDevice::setTimerCounterPinOffset(int offset)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"LabJackDevice's timer/counter pin offset cannot be set after it is initialized.";
	m_timerCounterPinOffset = offset;
}

int LabJackDevice::getTimerCounterPinOffset() const
{
	return m_timerCounterPinOffset;
}

void LabJackDevice::enableTimer(int index, LabJack::TimerMode mode)
{
	SURGSIM_ASSERT(!isInitialized()) << "Timers cannot be enabled for a LabJackDevice after it is initialized.";
	m_timers[index] = mode;
}

const std::unordered_map<int, LabJack::TimerMode>& LabJackDevice::getTimers() const
{
	return m_timers;
}

void LabJackDevice::setMaximumUpdateRate(double rate)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"LabJackDevice's maximum update rate cannot be set after it is initialized.";
	m_threadRate = rate;
}

double LabJackDevice::getMaximumUpdateRate() const
{
	return m_threadRate;
}

void LabJackDevice::enableAnalogInput(int positiveChannel, LabJack::Range range, int negativeChannel)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"Analog inputs cannot be enabled for a LabJackDevice after it is initialized.";
	LabJack::RangeAndOptionalNegativeChannel rangeAndOptionalNegativeChannel = {range,
		SurgSim::DataStructures::OptionalValue<int>(negativeChannel)};
	m_analogInputs[positiveChannel] = std::move(rangeAndOptionalNegativeChannel);
}

void LabJackDevice::enableAnalogInput(int channel, LabJack::Range range)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"Analog inputs cannot be enabled for a LabJackDevice after it is initialized.";
	LabJack::RangeAndOptionalNegativeChannel rangeAndOptionalNegativeChannel = {range,
		SurgSim::DataStructures::OptionalValue<int>()};
	m_analogInputs[channel] = std::move(rangeAndOptionalNegativeChannel);
}

const std::unordered_map<int, LabJack::RangeAndOptionalNegativeChannel>& LabJackDevice::getAnalogInputs() const
{
	return m_analogInputs;
}

void LabJackDevice::enableAnalogOutput(int channel)
{
	SURGSIM_ASSERT(!isInitialized()) << "Analog outputs cannot be enabled for a LabJackDevice after it is initialized.";
	m_analogOutputChannels.insert(channel);
}

const std::unordered_set<int>& LabJackDevice::getAnalogOutputs() const
{
	return m_analogOutputChannels;
}

void LabJackDevice::setAnalogInputResolution(int resolution)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"Analog input resolution cannot be set for a LabJackDevice after it is initialized.";
	m_analogInputResolution = resolution;
}

int LabJackDevice::getAnalogInputResolution() const
{
	return m_analogInputResolution;
}

void LabJackDevice::setAnalogInputSettling(int settling)
{
	SURGSIM_ASSERT(!isInitialized()) <<
		"Analog input settling time cannot be set for a LabJackDevice after it is initialized.";
	m_analogInputSettling = settling;
}

int LabJackDevice::getAnalogInputSettling() const
{
	return m_analogInputSettling;
}

};  // namespace Device
};  // namespace SurgSim
<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Devices/Phantom/PhantomDevice.h"

#include <iostream>
#include <iomanip>

#include <HD/hd.h>

#include <SurgSim/Math/Vector.h>
#include <SurgSim/Math/Matrix.h>
#include <SurgSim/Math/RigidTransform.h>
#include <SurgSim/Framework/Log.h>
#include <SurgSim/Devices/Phantom/PhantomManager.h>
#include <SurgSim/DataStructures/DataGroup.h>
#include <SurgSim/DataStructures/DataGroupBuilder.h>

using SurgSim::Math::Vector3d;
using SurgSim::Math::Matrix44d;
using SurgSim::Math::Matrix33d;
using SurgSim::Math::RigidTransform3d;

using SurgSim::DataStructures::DataGroup;
using SurgSim::DataStructures::DataGroupBuilder;

namespace SurgSim
{
namespace Device
{

struct PhantomDevice::State
{
	/// Initialize the state.
	State() : hHD(HD_INVALID_HANDLE)
	{
		for (int i = 0;  i < 3;  ++i)
		{
			positionBuffer[i] = 0;
		}
		for (int i = 0;  i < 16;  ++i)
		{
			transformBuffer[i] = (i % 5) ? 0 : 1;  // initialize to identity matrix
		}
		buttonsBuffer = 0;

		for (int i = 0;  i < 3;  ++i)
		{
			forceBuffer[i] = 0;
		}
	}

	/// The device handle.
	HHD hHD;

	/// The raw position read from the device.
	double positionBuffer[3];
	/// The raw pose transform read from the device.
	double transformBuffer[16];
	/// The raw button state read from the device.
	int buttonsBuffer;
	/// The raw force to be written to the device.
	double forceBuffer[3];
};

PhantomDevice::PhantomDevice(const PhantomManager& manager, const std::string& uniqueName,
                             const std::string& initializationName) :
	SurgSim::Input::CommonDevice(uniqueName, buildInputData()),
	m_logger(manager.getLogger()),
	m_initializationName(initializationName),
	m_messageLabel("Device " + uniqueName + ": "),
	m_state(new State)
{
}

PhantomDevice::~PhantomDevice()
{
	finalize();  // it's OK if we finalized already
}

bool PhantomDevice::initialize()
{
	HHD hHD = HD_INVALID_HANDLE;
	if (m_initializationName.length() > 0)
	{
		hHD = hdInitDevice(m_initializationName.c_str());
	}
	else
	{
		hHD = hdInitDevice(HD_DEFAULT_DEVICE);
	}

	if (checkForFatalError("Failed to initialize"))
	{
		// HDAPI error message already logged
		SURGSIM_LOG_INFO(m_logger) << std::endl <<
		                           "  OpenHaptics device name: '" << m_initializationName << "'" << std::endl;
		return false;
	}
	else if (hHD == HD_INVALID_HANDLE)
	{
		SURGSIM_LOG_SEVERE(m_logger) << m_messageLabel << "Failed to initialize" << std::endl <<
		                             "  Error details: unknown (HDAPI returned an invalid handle)" << std::endl <<
		                             "  OpenHaptics device name: '" << m_initializationName << "'" << std::endl;
		return false;
	}

	// Enable forces.
	hdMakeCurrentDevice(hHD);
	hdEnable(HD_FORCE_OUTPUT);
	checkForFatalError("Couldn't enable forces");

	m_state->hHD = hHD;

	SURGSIM_LOG_INFO(m_logger) << m_messageLabel << "Initialized." << std::endl <<
	                           "  OpenHaptics device name: '" << m_initializationName << "'" << std::endl;

	return true;
}

bool PhantomDevice::finalize()
{
	HHD hHD = m_state->hHD;
	if (hHD == HD_INVALID_HANDLE)
	{
		return false;
	}

	SURGSIM_LOG_DEBUG(m_logger) << m_messageLabel << "Finalizing.";
	hdDisableDevice(hHD);
	m_state->hHD = HD_INVALID_HANDLE;
	return true;
}

bool PhantomDevice::update()
{
	// TODO(bert): this code should cache the access indices.

	{
		// Use Eigen::Map to make the raw HDAPI output values look like Eigen data types
		Eigen::Map<Vector3d> force(m_state->forceBuffer);

		Vector3d forceValue;
		if (getOutputData().isValid() && getOutputData().vectors().get("force", forceValue))
		{
			force = forceValue;
		}
		else
		{
			force.setZero();
		}
	}

	hdBeginFrame(m_state->hHD);

	// Receive the current device position (in millimeters!), pose transform, and button state bitmap.
	hdGetDoublev(HD_CURRENT_POSITION, m_state->positionBuffer);
	hdGetDoublev(HD_CURRENT_TRANSFORM, m_state->transformBuffer);
	hdGetIntegerv(HD_CURRENT_BUTTONS, &(m_state->buttonsBuffer));

	// Set the force command (in newtons).
	hdSetDoublev(HD_CURRENT_FORCE, m_state->forceBuffer);
	//hdSetDoublev(HD_CURRENT_TORQUE, m_state->torqueBuffer);

	hdEndFrame(m_state->hHD);

	bool fatalError = checkForFatalError("Error in device update");

	{
		// Use Eigen::Map to make the raw HDAPI output values look like Eigen data types
		Eigen::Map<Vector3d> position(m_state->positionBuffer);
		Eigen::Map<Eigen::Matrix<double, 4, 4, Eigen::ColMajor>> transform(m_state->transformBuffer);

		RigidTransform3d pose;
		pose.linear() = transform.block<3,3>(0,0);
		pose.translation() = position * 0.001;  // convert from millimeters to meters!

		getInputData().poses().put("pose", pose);
		getInputData().booleans().put("button0", (m_state->buttonsBuffer & HD_DEVICE_BUTTON_1) != 0);
		getInputData().booleans().put("button1", (m_state->buttonsBuffer & HD_DEVICE_BUTTON_2) != 0);
		getInputData().booleans().put("button2", (m_state->buttonsBuffer & HD_DEVICE_BUTTON_3) != 0);
		getInputData().booleans().put("button3", (m_state->buttonsBuffer & HD_DEVICE_BUTTON_4) != 0);
	}

	return !fatalError;
}

DataGroup PhantomDevice::buildInputData()
{
	DataGroupBuilder builder;
	builder.addPose("pose");
	builder.addBoolean("button0");
	builder.addBoolean("button1");
	builder.addBoolean("button2");
	builder.addBoolean("button3");
	return builder.createData();
}

bool PhantomDevice::checkForFatalError(const char* message)
{
	return checkForFatalError(m_logger, m_messageLabel.c_str(), message);
}

bool PhantomDevice::checkForFatalError(const std::shared_ptr<SurgSim::Framework::Logger>& logger,
                                       const char* prefix, const char* message)
{
	HDErrorInfo error = hdGetError();
	if (error.errorCode == HD_SUCCESS)
	{
		return false;
	}

	// The HD API maintains an error stack, so in theory there could be more than one error pending.
	// We do head recursion to get them all in the correct order.
	bool anotherFatalError = checkForFatalError(logger, prefix, message);

	bool isFatal = ((error.errorCode != HD_WARM_MOTORS) &&
	                (error.errorCode != HD_EXCEEDED_MAX_FORCE) &&
	                (error.errorCode != HD_EXCEEDED_MAX_FORCE_IMPULSE) &&
	                (error.errorCode != HD_EXCEEDED_MAX_VELOCITY) &&
	                (error.errorCode != HD_FORCE_ERROR));

	SURGSIM_LOG_SEVERE(logger) << prefix << message << std::endl <<
	                           "  Error text: '" << hdGetErrorString(error.errorCode) << "'" << std::endl <<
	                           "  Error code: 0x" << std::hex << std::setw(4) << std::setfill('0') << error.errorCode <<
	                           " (internal: " << std::dec << error.internalErrorCode << ")" << std::endl;

	return (isFatal || anotherFatalError);
}

};  // namespace Device
};  // namespace SurgSim
<commit_msg>Fix the Phantom device build after get/set changes.<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "SurgSim/Devices/Phantom/PhantomDevice.h"

#include <iostream>
#include <iomanip>

#include <HD/hd.h>

#include <SurgSim/Math/Vector.h>
#include <SurgSim/Math/Matrix.h>
#include <SurgSim/Math/RigidTransform.h>
#include <SurgSim/Framework/Log.h>
#include <SurgSim/Devices/Phantom/PhantomManager.h>
#include <SurgSim/DataStructures/DataGroup.h>
#include <SurgSim/DataStructures/DataGroupBuilder.h>

using SurgSim::Math::Vector3d;
using SurgSim::Math::Matrix44d;
using SurgSim::Math::Matrix33d;
using SurgSim::Math::RigidTransform3d;

using SurgSim::DataStructures::DataGroup;
using SurgSim::DataStructures::DataGroupBuilder;

namespace SurgSim
{
namespace Device
{

struct PhantomDevice::State
{
	/// Initialize the state.
	State() : hHD(HD_INVALID_HANDLE)
	{
		for (int i = 0;  i < 3;  ++i)
		{
			positionBuffer[i] = 0;
		}
		for (int i = 0;  i < 16;  ++i)
		{
			transformBuffer[i] = (i % 5) ? 0 : 1;  // initialize to identity matrix
		}
		buttonsBuffer = 0;

		for (int i = 0;  i < 3;  ++i)
		{
			forceBuffer[i] = 0;
		}
	}

	/// The device handle.
	HHD hHD;

	/// The raw position read from the device.
	double positionBuffer[3];
	/// The raw pose transform read from the device.
	double transformBuffer[16];
	/// The raw button state read from the device.
	int buttonsBuffer;
	/// The raw force to be written to the device.
	double forceBuffer[3];
};

PhantomDevice::PhantomDevice(const PhantomManager& manager, const std::string& uniqueName,
                             const std::string& initializationName) :
	SurgSim::Input::CommonDevice(uniqueName, buildInputData()),
	m_logger(manager.getLogger()),
	m_initializationName(initializationName),
	m_messageLabel("Device " + uniqueName + ": "),
	m_state(new State)
{
}

PhantomDevice::~PhantomDevice()
{
	finalize();  // it's OK if we finalized already
}

bool PhantomDevice::initialize()
{
	HHD hHD = HD_INVALID_HANDLE;
	if (m_initializationName.length() > 0)
	{
		hHD = hdInitDevice(m_initializationName.c_str());
	}
	else
	{
		hHD = hdInitDevice(HD_DEFAULT_DEVICE);
	}

	if (checkForFatalError("Failed to initialize"))
	{
		// HDAPI error message already logged
		SURGSIM_LOG_INFO(m_logger) << std::endl <<
		                           "  OpenHaptics device name: '" << m_initializationName << "'" << std::endl;
		return false;
	}
	else if (hHD == HD_INVALID_HANDLE)
	{
		SURGSIM_LOG_SEVERE(m_logger) << m_messageLabel << "Failed to initialize" << std::endl <<
		                             "  Error details: unknown (HDAPI returned an invalid handle)" << std::endl <<
		                             "  OpenHaptics device name: '" << m_initializationName << "'" << std::endl;
		return false;
	}

	// Enable forces.
	hdMakeCurrentDevice(hHD);
	hdEnable(HD_FORCE_OUTPUT);
	checkForFatalError("Couldn't enable forces");

	m_state->hHD = hHD;

	SURGSIM_LOG_INFO(m_logger) << m_messageLabel << "Initialized." << std::endl <<
	                           "  OpenHaptics device name: '" << m_initializationName << "'" << std::endl;

	return true;
}

bool PhantomDevice::finalize()
{
	HHD hHD = m_state->hHD;
	if (hHD == HD_INVALID_HANDLE)
	{
		return false;
	}

	SURGSIM_LOG_DEBUG(m_logger) << m_messageLabel << "Finalizing.";
	hdDisableDevice(hHD);
	m_state->hHD = HD_INVALID_HANDLE;
	return true;
}

bool PhantomDevice::update()
{
	// TODO(bert): this code should cache the access indices.

	{
		// Use Eigen::Map to make the raw HDAPI output values look like Eigen data types
		Eigen::Map<Vector3d> force(m_state->forceBuffer);

		Vector3d forceValue;
		if (getOutputData().isValid() && getOutputData().vectors().get("force", &forceValue))
		{
			force = forceValue;
		}
		else
		{
			force.setZero();
		}
	}

	hdBeginFrame(m_state->hHD);

	// Receive the current device position (in millimeters!), pose transform, and button state bitmap.
	hdGetDoublev(HD_CURRENT_POSITION, m_state->positionBuffer);
	hdGetDoublev(HD_CURRENT_TRANSFORM, m_state->transformBuffer);
	hdGetIntegerv(HD_CURRENT_BUTTONS, &(m_state->buttonsBuffer));

	// Set the force command (in newtons).
	hdSetDoublev(HD_CURRENT_FORCE, m_state->forceBuffer);
	//hdSetDoublev(HD_CURRENT_TORQUE, m_state->torqueBuffer);

	hdEndFrame(m_state->hHD);

	bool fatalError = checkForFatalError("Error in device update");

	{
		// Use Eigen::Map to make the raw HDAPI output values look like Eigen data types
		Eigen::Map<Vector3d> position(m_state->positionBuffer);
		Eigen::Map<Eigen::Matrix<double, 4, 4, Eigen::ColMajor>> transform(m_state->transformBuffer);

		RigidTransform3d pose;
		pose.linear() = transform.block<3,3>(0,0);
		pose.translation() = position * 0.001;  // convert from millimeters to meters!

		getInputData().poses().set("pose", pose);
		getInputData().booleans().set("button0", (m_state->buttonsBuffer & HD_DEVICE_BUTTON_1) != 0);
		getInputData().booleans().set("button1", (m_state->buttonsBuffer & HD_DEVICE_BUTTON_2) != 0);
		getInputData().booleans().set("button2", (m_state->buttonsBuffer & HD_DEVICE_BUTTON_3) != 0);
		getInputData().booleans().set("button3", (m_state->buttonsBuffer & HD_DEVICE_BUTTON_4) != 0);
	}

	return !fatalError;
}

DataGroup PhantomDevice::buildInputData()
{
	DataGroupBuilder builder;
	builder.addPose("pose");
	builder.addBoolean("button0");
	builder.addBoolean("button1");
	builder.addBoolean("button2");
	builder.addBoolean("button3");
	return builder.createData();
}

bool PhantomDevice::checkForFatalError(const char* message)
{
	return checkForFatalError(m_logger, m_messageLabel.c_str(), message);
}

bool PhantomDevice::checkForFatalError(const std::shared_ptr<SurgSim::Framework::Logger>& logger,
                                       const char* prefix, const char* message)
{
	HDErrorInfo error = hdGetError();
	if (error.errorCode == HD_SUCCESS)
	{
		return false;
	}

	// The HD API maintains an error stack, so in theory there could be more than one error pending.
	// We do head recursion to get them all in the correct order.
	bool anotherFatalError = checkForFatalError(logger, prefix, message);

	bool isFatal = ((error.errorCode != HD_WARM_MOTORS) &&
	                (error.errorCode != HD_EXCEEDED_MAX_FORCE) &&
	                (error.errorCode != HD_EXCEEDED_MAX_FORCE_IMPULSE) &&
	                (error.errorCode != HD_EXCEEDED_MAX_VELOCITY) &&
	                (error.errorCode != HD_FORCE_ERROR));

	SURGSIM_LOG_SEVERE(logger) << prefix << message << std::endl <<
	                           "  Error text: '" << hdGetErrorString(error.errorCode) << "'" << std::endl <<
	                           "  Error code: 0x" << std::hex << std::setw(4) << std::setfill('0') << error.errorCode <<
	                           " (internal: " << std::dec << error.internalErrorCode << ")" << std::endl;

	return (isFatal || anotherFatalError);
}

};  // namespace Device
};  // namespace SurgSim
<|endoftext|>


<commit_before>#ifndef TESTLINEDETECTION_HPP
#define TESTLINEDETECTION_HPP

#include <QtTest>
#include <intelligence/linedetection/linedetector.h>
#include <iostream>
#ifdef _WIN32
    #include <direct.h>
    #define GetCurrentDir _getcwd
#else
    #include <unistd.h>
    #define GetCurrentDir getcwd
#endif

class TestLineDetection: public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void testCase1()
    {
        //char videoFile[] = "../igvc_cam_data/stills/img_left2.jpg";
        char videoFile[] = "../src/intelligence/igvc_cam_data/video/CompCourse_left0.mpeg";

         LineDetector ln(videoFile);
         bool success =true;
         while(success){

             ln.applyAlgorithm();
             success = ln.loadImage(videoFile);
         }
    }
};

#endif // TESTLINEDETECTION_HPP
<commit_msg>Added some more comments<commit_after>#ifndef TESTLINEDETECTION_HPP
#define TESTLINEDETECTION_HPP

#include <QtTest>
#include <intelligence/linedetection/linedetector.h>
#include <iostream>
#ifdef _WIN32
    #include <direct.h>
    #define GetCurrentDir _getcwd
#else
    #include <unistd.h>
    #define GetCurrentDir getcwd
#endif

class TestLineDetection: public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void testCase1()
    {
        //char videoFile[] = "../igvc_cam_data/stills/img_left2.jpg";
        ///Note: This may not be the correct directory on your computer
        char videoFile[] = "../src/intelligence/igvc_cam_data/video/CompCourse_left0.mpeg";

         LineDetector ln(videoFile);
         bool success =true;
         while(success){

             ln.applyAlgorithm();
             success = ln.loadImage(videoFile);
         }
    }
};

#endif // TESTLINEDETECTION_HPP
<|endoftext|>


<commit_before>#include <functional>

#include "arch/runtime/starter.hpp"
#include "serializer/config.hpp"
#include "unittest/mock_file.hpp"
#include "unittest/gtest.hpp"

namespace unittest {

// This test is completely vacuous, but should invite expansion in the future.

void run_CreateConstructDestroy() {
    // This serves more as a mock_file_t test than a serializer test.
    mock_file_opener_t file_opener;
    standard_serializer_t::create(&file_opener, standard_serializer_t::static_config_t());
    standard_serializer_t ser(standard_serializer_t::dynamic_config_t(),
                              &file_opener,
                              &get_global_perfmon_collection());
}

TEST(SerializerTest, CreateConstructDestroy) {
    run_in_thread_pool(run_CreateConstructDestroy, 4);
}

void run_AddDeleteRepeatedly(bool perform_index_write) {
    mock_file_opener_t file_opener;
    standard_serializer_t::create(&file_opener, standard_serializer_t::static_config_t());
    standard_serializer_t ser(standard_serializer_t::dynamic_config_t(),
                              &file_opener,
                              &get_global_perfmon_collection());

    scoped_malloc_t<ser_buffer_t> buf = ser.malloc();
    memset(buf->cache_data, 0, ser.get_block_size().value());

    scoped_ptr_t<file_account_t> account(ser.make_io_account(1));

    for (int i = 0; i < 200000; ++i) {
        const block_id_t block_id = i;
        std::vector<buf_write_info_t> infos;
        infos.push_back(buf_write_info_t(buf.get(), ser.get_block_size(), block_id));

        // Create the block
        struct : public iocallback_t, public cond_t {
            void on_io_complete() {
                pulse();
            }
        } cb;

        std::vector<counted_t<standard_block_token_t> > tokens
            = ser.block_writes(infos, account.get(), &cb);

        // Wait for it to be written (because we're nice).
        cb.wait();

        if (perform_index_write) {
            // Do an index write creating the block.
            {
                std::vector<index_write_op_t> write_ops;
                write_ops.push_back(index_write_op_t(block_id, tokens[0], repli_timestamp_t::distant_past));
                ser.index_write(write_ops, account.get());
            }
            // Now delete the only block token and delete the index reference.
            tokens.clear();
            {
                std::vector<index_write_op_t> write_ops;
                write_ops.push_back(index_write_op_t(block_id, counted_t<standard_block_token_t>()));
                ser.index_write(write_ops, account.get());
            }

        } else {
            // Now delete the only block token.
            tokens.clear();
        }
    }
}

TEST(SerializerTest, AddDeleteRepeatedly) {
    run_in_thread_pool(std::bind(run_AddDeleteRepeatedly, false), 4);
}

TEST(SerializerTest, AddDeleteRepeatedlyWithIndex) {
    run_in_thread_pool(std::bind(run_AddDeleteRepeatedly, true), 4);
}

}  // namespace unittest
<commit_msg>Added comments about the goals of run_AddDeleteRepeatedly with regard to what issue it is testing.<commit_after>#include <functional>

#include "arch/runtime/starter.hpp"
#include "serializer/config.hpp"
#include "unittest/mock_file.hpp"
#include "unittest/gtest.hpp"

namespace unittest {

// This test is completely vacuous, but should invite expansion in the future.

void run_CreateConstructDestroy() {
    // This serves more as a mock_file_t test than a serializer test.
    mock_file_opener_t file_opener;
    standard_serializer_t::create(&file_opener, standard_serializer_t::static_config_t());
    standard_serializer_t ser(standard_serializer_t::dynamic_config_t(),
                              &file_opener,
                              &get_global_perfmon_collection());
}

TEST(SerializerTest, CreateConstructDestroy) {
    run_in_thread_pool(run_CreateConstructDestroy, 4);
}

void run_AddDeleteRepeatedly(bool perform_index_write) {
    mock_file_opener_t file_opener;
    standard_serializer_t::create(&file_opener, standard_serializer_t::static_config_t());
    standard_serializer_t ser(standard_serializer_t::dynamic_config_t(),
                              &file_opener,
                              &get_global_perfmon_collection());

    scoped_malloc_t<ser_buffer_t> buf = ser.malloc();
    memset(buf->cache_data, 0, ser.get_block_size().value());

    scoped_ptr_t<file_account_t> account(ser.make_io_account(1));

    // We run enough create/delete operations to run ourselves through the young
    // extent queue and (with perform_index_write true) kick off a GC that reproduces
    // #1691.
    for (int i = 0; i < 200000; ++i) {
        const block_id_t block_id = i;
        std::vector<buf_write_info_t> infos;
        infos.push_back(buf_write_info_t(buf.get(), ser.get_block_size(), block_id));

        // Create the block
        struct : public iocallback_t, public cond_t {
            void on_io_complete() {
                pulse();
            }
        } cb;

        std::vector<counted_t<standard_block_token_t> > tokens
            = ser.block_writes(infos, account.get(), &cb);

        // Wait for it to be written (because we're nice).
        cb.wait();

        if (perform_index_write) {
            // Do an index write creating the block.
            {
                std::vector<index_write_op_t> write_ops;
                write_ops.push_back(index_write_op_t(block_id, tokens[0], repli_timestamp_t::distant_past));
                ser.index_write(write_ops, account.get());
            }
            // Now delete the only block token and delete the index reference.
            tokens.clear();
            {
                std::vector<index_write_op_t> write_ops;
                write_ops.push_back(index_write_op_t(block_id, counted_t<standard_block_token_t>()));
                ser.index_write(write_ops, account.get());
            }

        } else {
            // Now delete the only block token.
            tokens.clear();
        }
    }
}

TEST(SerializerTest, AddDeleteRepeatedly) {
    run_in_thread_pool(std::bind(run_AddDeleteRepeatedly, false), 4);
}

// This is a regression test for #1691.
TEST(SerializerTest, AddDeleteRepeatedlyWithIndex) {
    run_in_thread_pool(std::bind(run_AddDeleteRepeatedly, true), 4);
}

}  // namespace unittest
<|endoftext|>