<commit_before>/*
 * reactor.cc
 *
 *  Created on: Aug 1, 2014
 *      Author: avi
 */

#include "reactor.hh"
#include <cassert>
#include <unistd.h>
#include <fcntl.h>
#include <sys/eventfd.h>

template <typename T>
struct syscall_result {
    T result;
    int error;
    void throw_if_error() {
        if (long(result) == -1) {
            throw std::system_error(error, std::system_category());
        }
    }
};

template <typename T>
syscall_result<T>
wrap_syscall(T result) {
    syscall_result<T> sr;
    sr.result = result;
    sr.error = errno;
    return sr;
}

reactor::reactor()
    : _epollfd(epoll_create1(EPOLL_CLOEXEC))
    , _io_eventfd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK))
    , _io_eventfd_state(_io_eventfd)
    , _io_context_available(max_aio) {
    assert(_epollfd != -1);
    assert(_io_eventfd != -1);
    auto r = ::io_setup(max_aio, &_io_context);
    assert(r >= 0);
    readable(_io_eventfd_state).then([this] {
        process_io();
    });
}

reactor::~reactor() {
    ::close(_epollfd);
}

future<> reactor::get_epoll_future(pollable_fd_state& pfd,
        promise<> pollable_fd_state::*pr, int event) {
    if (pfd.events_known & event) {
        pfd.events_known &= ~event;
        return make_ready_future();
    }
    pfd.events_requested |= event;
    if (!(pfd.events_epoll & event)) {
        auto ctl = pfd.events_epoll ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
        pfd.events_epoll |= event;
        ::epoll_event eevt;
        eevt.events = pfd.events_epoll;
        eevt.data.ptr = &pfd;
        int r = ::epoll_ctl(_epollfd, ctl, pfd.fd, &eevt);
        assert(r == 0);
    }
    pfd.*pr = promise<>();
    return (pfd.*pr).get_future();
}

future<> reactor::readable(pollable_fd_state& fd) {
    return get_epoll_future(fd, &pollable_fd_state::pollin, EPOLLIN);
}

future<> reactor::writeable(pollable_fd_state& fd) {
    return get_epoll_future(fd, &pollable_fd_state::pollout, EPOLLOUT);
}

void reactor::forget(pollable_fd_state& fd) {
    if (fd.events_epoll) {
        ::epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd.fd, nullptr);
    }
}

pollable_fd
reactor::listen(socket_address sa, listen_options opts) {
    int fd = ::socket(sa.u.sa.sa_family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
    assert(fd != -1);
    if (opts.reuse_address) {
        int opt = 1;
        ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    }
    int r = ::bind(fd, &sa.u.sa, sizeof(sa.u.sas));
    throw_system_error_on(r == -1);
    ::listen(fd, 100);
    return pollable_fd(fd);
}

void reactor::complete_epoll_event(pollable_fd_state& pfd, promise<> pollable_fd_state::*pr,
        int events, int event) {
    if (pfd.events_requested & events & event) {
        pfd.events_requested &= ~EPOLLIN;
        pfd.events_known &= ~EPOLLIN;
        (pfd.*pr).set_value();
        pfd.*pr = promise<>();
    }
}

template <typename Func>
future<io_event>
reactor::submit_io(Func prepare_io) {
    return _io_context_available.wait(1).then([this, prepare_io = std::move(prepare_io)] () mutable {
        auto pr = std::make_unique<promise<io_event>>();
        iocb io;
        prepare_io(io);
        io.data = pr.get();
        io_set_eventfd(&io, _io_eventfd);
        iocb* p = &io;
        auto r = ::io_submit(_io_context, 1, &p);
        throw_kernel_error(r);
        return pr.release()->get_future();
    });
}

void reactor::process_io()
{
    uint64_t count;
    auto r = ::read(_io_eventfd, &count, sizeof(count));
    assert(r == 8);
    assert(count);
    io_event ev[max_aio];
    auto n = ::io_getevents(_io_context, count, count, ev, NULL);
    assert(n >= 0 && size_t(n) == count);
    for (size_t i = 0; i < size_t(n); ++i) {
        auto pr = reinterpret_cast<promise<io_event>*>(ev[i].data);
        pr->set_value(ev[i]);
        delete pr;
    }
    _io_context_available.signal(n);
    readable(_io_eventfd_state).then([this] {
        process_io();
    });
}

future<size_t>
reactor::write_dma(file& f, uint64_t pos, const void* buffer, size_t len) {
    return submit_io([&f, pos, buffer, len] (iocb& io) {
        io_prep_pwrite(&io, f._fd, const_cast<void*>(buffer), len, pos);
    }).then([] (io_event ev) {
        throw_kernel_error(long(ev.res));
        return make_ready_future<size_t>(size_t(ev.res));
    });
}

future<size_t>
reactor::write_dma(file& f, uint64_t pos, std::vector<iovec> iov) {
    return submit_io([&f, pos, iov = std::move(iov)] (iocb& io) {
        io_prep_pwritev(&io, f._fd, iov.data(), iov.size(), pos);
    }).then([] (io_event ev) {
        throw_kernel_error(long(ev.res));
        return make_ready_future<size_t>(size_t(ev.res));
    });
}

future<size_t>
reactor::read_dma(file& f, uint64_t pos, void* buffer, size_t len) {
    return submit_io([&f, pos, buffer, len] (iocb& io) {
        io_prep_pread(&io, f._fd, buffer, len, pos);
    }).then([] (io_event ev) {
        throw_kernel_error(long(ev.res));
        return make_ready_future<size_t>(size_t(ev.res));
    });
}

future<size_t>
reactor::read_dma(file& f, uint64_t pos, std::vector<iovec> iov) {
    return submit_io([&f, pos, iov = std::move(iov)] (iocb& io) {
        io_prep_preadv(&io, f._fd, iov.data(), iov.size(), pos);
    }).then([] (io_event ev) {
        throw_kernel_error(long(ev.res));
        return make_ready_future<size_t>(size_t(ev.res));
    });
}

future<file>
reactor::open_file_dma(sstring name) {
    return _thread_pool.submit<syscall_result<int>>([name] {
        return wrap_syscall<int>(::open(name.c_str(), O_DIRECT | O_CLOEXEC | O_CREAT | O_RDWR, S_IRWXU));
    }).then([] (syscall_result<int> sr) {
        sr.throw_if_error();
        return make_ready_future<file>(file(sr.result));
    });
}

future<>
reactor::flush(file& f) {
    return _thread_pool.submit<syscall_result<int>>([&f] {
        return wrap_syscall<int>(::fsync(f._fd));
    }).then([] (syscall_result<int> sr) {
        sr.throw_if_error();
        return make_ready_future<>();
    });
}

void reactor::run() {
    std::vector<std::unique_ptr<task>> current_tasks;
    while (true) {
        while (!_pending_tasks.empty()) {
            std::swap(_pending_tasks, current_tasks);
            for (auto&& tsk : current_tasks) {
                tsk->run();
                tsk.reset();
            }
            current_tasks.clear();
        }
        std::array<epoll_event, 128> eevt;
        int nr = ::epoll_wait(_epollfd, eevt.data(), eevt.size(), -1);
        assert(nr != -1);
        for (int i = 0; i < nr; ++i) {
            auto& evt = eevt[i];
            auto pfd = reinterpret_cast<pollable_fd_state*>(evt.data.ptr);
            auto events = evt.events & (EPOLLIN | EPOLLOUT);
            std::unique_ptr<task> t_in, t_out;
            pfd->events_known |= events;
            auto events_to_remove = events & ~pfd->events_requested;
            complete_epoll_event(*pfd, &pollable_fd_state::pollin, events, EPOLLIN);
            complete_epoll_event(*pfd, &pollable_fd_state::pollout, events, EPOLLOUT);
            if (events_to_remove) {
                pfd->events_epoll &= ~events_to_remove;
                evt.events = pfd->events_epoll;
                auto op = evt.events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
                ::epoll_ctl(_epollfd, op, pfd->fd, &evt);
            }
        }
    }
}

thread_pool::thread_pool()
    : _pending(queue_length)
    , _completed(queue_length)
    , _start_eventfd(0)
    , _complete_eventfd(0)
    , _worker_thread([this] { work(); }) {
    _worker_thread.detach();
    complete();
}

void thread_pool::work() {
    while (true) {
        uint64_t count;
        auto r = ::read(_start_eventfd.get_read_fd(), &count, sizeof(count));
        assert(r == sizeof(count));
        auto nr = _pending.consume_all([this] (work_item* wi) {
            wi->process();
            _completed.push(wi);
        });
        count = nr;
        r = ::write(_complete_eventfd.get_write_fd(), &count, sizeof(count));
        assert(r == sizeof(count));
    }
}

void thread_pool::submit_item(thread_pool::work_item* item) {
    _queue_has_room.wait().then([this, item] {
        _pending.push(item);
        _start_eventfd.signal(1);
    });
}

void thread_pool::complete() {
    _complete_eventfd.wait().then([this] (size_t count) {
        auto nr = _completed.consume_all([this] (work_item* wi) {
            wi->complete();
            delete wi;
        });
        _queue_has_room.signal(nr);
        complete();
    });
}

int writeable_eventfd::try_create_eventfd(size_t initial) {
    assert(size_t(int(initial)) == initial);
    int r = ::eventfd(initial, EFD_CLOEXEC);
    throw_system_error_on(r == -1);
    return r;
}

void writeable_eventfd::signal(size_t count) {
    uint64_t c = count;
    auto r = ::write(_fd, &c, sizeof(c));
    assert(r == sizeof(c));
}

int readable_eventfd::try_create_eventfd(size_t initial) {
    assert(size_t(int(initial)) == initial);
    int r = ::eventfd(initial, EFD_CLOEXEC | EFD_NONBLOCK);
    throw_system_error_on(r == -1);
    return r;
}

future<size_t> readable_eventfd::wait() {
    return the_reactor.readable(*_fd._s).then([this] {
        uint64_t count;
        int r = ::read(_fd.get_fd(), &count, sizeof(count));
        assert(r == sizeof(count));
        return make_ready_future<size_t>(count);
    });
}

socket_address make_ipv4_address(ipv4_addr addr) {
    socket_address sa;
    sa.u.in.sin_family = AF_INET;
    sa.u.in.sin_port = htons(addr.port);
    std::memcpy(&sa.u.in.sin_addr, addr.host, 4);
    return sa;
}

reactor the_reactor;
<commit_msg>reactor: fix io_setup() failure<commit_after>/*
 * reactor.cc
 *
 *  Created on: Aug 1, 2014
 *      Author: avi
 */

#include "reactor.hh"
#include <cassert>
#include <unistd.h>
#include <fcntl.h>
#include <sys/eventfd.h>

template <typename T>
struct syscall_result {
    T result;
    int error;
    void throw_if_error() {
        if (long(result) == -1) {
            throw std::system_error(error, std::system_category());
        }
    }
};

template <typename T>
syscall_result<T>
wrap_syscall(T result) {
    syscall_result<T> sr;
    sr.result = result;
    sr.error = errno;
    return sr;
}

reactor::reactor()
    : _epollfd(epoll_create1(EPOLL_CLOEXEC))
    , _io_eventfd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK))
    , _io_eventfd_state(_io_eventfd)
    , _io_context(0)
    , _io_context_available(max_aio) {
    assert(_epollfd != -1);
    assert(_io_eventfd != -1);
    auto r = ::io_setup(max_aio, &_io_context);
    assert(r >= 0);
    readable(_io_eventfd_state).then([this] {
        process_io();
    });
}

reactor::~reactor() {
    ::close(_epollfd);
}

future<> reactor::get_epoll_future(pollable_fd_state& pfd,
        promise<> pollable_fd_state::*pr, int event) {
    if (pfd.events_known & event) {
        pfd.events_known &= ~event;
        return make_ready_future();
    }
    pfd.events_requested |= event;
    if (!(pfd.events_epoll & event)) {
        auto ctl = pfd.events_epoll ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
        pfd.events_epoll |= event;
        ::epoll_event eevt;
        eevt.events = pfd.events_epoll;
        eevt.data.ptr = &pfd;
        int r = ::epoll_ctl(_epollfd, ctl, pfd.fd, &eevt);
        assert(r == 0);
    }
    pfd.*pr = promise<>();
    return (pfd.*pr).get_future();
}

future<> reactor::readable(pollable_fd_state& fd) {
    return get_epoll_future(fd, &pollable_fd_state::pollin, EPOLLIN);
}

future<> reactor::writeable(pollable_fd_state& fd) {
    return get_epoll_future(fd, &pollable_fd_state::pollout, EPOLLOUT);
}

void reactor::forget(pollable_fd_state& fd) {
    if (fd.events_epoll) {
        ::epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd.fd, nullptr);
    }
}

pollable_fd
reactor::listen(socket_address sa, listen_options opts) {
    int fd = ::socket(sa.u.sa.sa_family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
    assert(fd != -1);
    if (opts.reuse_address) {
        int opt = 1;
        ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    }
    int r = ::bind(fd, &sa.u.sa, sizeof(sa.u.sas));
    throw_system_error_on(r == -1);
    ::listen(fd, 100);
    return pollable_fd(fd);
}

void reactor::complete_epoll_event(pollable_fd_state& pfd, promise<> pollable_fd_state::*pr,
        int events, int event) {
    if (pfd.events_requested & events & event) {
        pfd.events_requested &= ~EPOLLIN;
        pfd.events_known &= ~EPOLLIN;
        (pfd.*pr).set_value();
        pfd.*pr = promise<>();
    }
}

template <typename Func>
future<io_event>
reactor::submit_io(Func prepare_io) {
    return _io_context_available.wait(1).then([this, prepare_io = std::move(prepare_io)] () mutable {
        auto pr = std::make_unique<promise<io_event>>();
        iocb io;
        prepare_io(io);
        io.data = pr.get();
        io_set_eventfd(&io, _io_eventfd);
        iocb* p = &io;
        auto r = ::io_submit(_io_context, 1, &p);
        throw_kernel_error(r);
        return pr.release()->get_future();
    });
}

void reactor::process_io()
{
    uint64_t count;
    auto r = ::read(_io_eventfd, &count, sizeof(count));
    assert(r == 8);
    assert(count);
    io_event ev[max_aio];
    auto n = ::io_getevents(_io_context, count, count, ev, NULL);
    assert(n >= 0 && size_t(n) == count);
    for (size_t i = 0; i < size_t(n); ++i) {
        auto pr = reinterpret_cast<promise<io_event>*>(ev[i].data);
        pr->set_value(ev[i]);
        delete pr;
    }
    _io_context_available.signal(n);
    readable(_io_eventfd_state).then([this] {
        process_io();
    });
}

future<size_t>
reactor::write_dma(file& f, uint64_t pos, const void* buffer, size_t len) {
    return submit_io([&f, pos, buffer, len] (iocb& io) {
        io_prep_pwrite(&io, f._fd, const_cast<void*>(buffer), len, pos);
    }).then([] (io_event ev) {
        throw_kernel_error(long(ev.res));
        return make_ready_future<size_t>(size_t(ev.res));
    });
}

future<size_t>
reactor::write_dma(file& f, uint64_t pos, std::vector<iovec> iov) {
    return submit_io([&f, pos, iov = std::move(iov)] (iocb& io) {
        io_prep_pwritev(&io, f._fd, iov.data(), iov.size(), pos);
    }).then([] (io_event ev) {
        throw_kernel_error(long(ev.res));
        return make_ready_future<size_t>(size_t(ev.res));
    });
}

future<size_t>
reactor::read_dma(file& f, uint64_t pos, void* buffer, size_t len) {
    return submit_io([&f, pos, buffer, len] (iocb& io) {
        io_prep_pread(&io, f._fd, buffer, len, pos);
    }).then([] (io_event ev) {
        throw_kernel_error(long(ev.res));
        return make_ready_future<size_t>(size_t(ev.res));
    });
}

future<size_t>
reactor::read_dma(file& f, uint64_t pos, std::vector<iovec> iov) {
    return submit_io([&f, pos, iov = std::move(iov)] (iocb& io) {
        io_prep_preadv(&io, f._fd, iov.data(), iov.size(), pos);
    }).then([] (io_event ev) {
        throw_kernel_error(long(ev.res));
        return make_ready_future<size_t>(size_t(ev.res));
    });
}

future<file>
reactor::open_file_dma(sstring name) {
    return _thread_pool.submit<syscall_result<int>>([name] {
        return wrap_syscall<int>(::open(name.c_str(), O_DIRECT | O_CLOEXEC | O_CREAT | O_RDWR, S_IRWXU));
    }).then([] (syscall_result<int> sr) {
        sr.throw_if_error();
        return make_ready_future<file>(file(sr.result));
    });
}

future<>
reactor::flush(file& f) {
    return _thread_pool.submit<syscall_result<int>>([&f] {
        return wrap_syscall<int>(::fsync(f._fd));
    }).then([] (syscall_result<int> sr) {
        sr.throw_if_error();
        return make_ready_future<>();
    });
}

void reactor::run() {
    std::vector<std::unique_ptr<task>> current_tasks;
    while (true) {
        while (!_pending_tasks.empty()) {
            std::swap(_pending_tasks, current_tasks);
            for (auto&& tsk : current_tasks) {
                tsk->run();
                tsk.reset();
            }
            current_tasks.clear();
        }
        std::array<epoll_event, 128> eevt;
        int nr = ::epoll_wait(_epollfd, eevt.data(), eevt.size(), -1);
        assert(nr != -1);
        for (int i = 0; i < nr; ++i) {
            auto& evt = eevt[i];
            auto pfd = reinterpret_cast<pollable_fd_state*>(evt.data.ptr);
            auto events = evt.events & (EPOLLIN | EPOLLOUT);
            std::unique_ptr<task> t_in, t_out;
            pfd->events_known |= events;
            auto events_to_remove = events & ~pfd->events_requested;
            complete_epoll_event(*pfd, &pollable_fd_state::pollin, events, EPOLLIN);
            complete_epoll_event(*pfd, &pollable_fd_state::pollout, events, EPOLLOUT);
            if (events_to_remove) {
                pfd->events_epoll &= ~events_to_remove;
                evt.events = pfd->events_epoll;
                auto op = evt.events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
                ::epoll_ctl(_epollfd, op, pfd->fd, &evt);
            }
        }
    }
}

thread_pool::thread_pool()
    : _pending(queue_length)
    , _completed(queue_length)
    , _start_eventfd(0)
    , _complete_eventfd(0)
    , _worker_thread([this] { work(); }) {
    _worker_thread.detach();
    complete();
}

void thread_pool::work() {
    while (true) {
        uint64_t count;
        auto r = ::read(_start_eventfd.get_read_fd(), &count, sizeof(count));
        assert(r == sizeof(count));
        auto nr = _pending.consume_all([this] (work_item* wi) {
            wi->process();
            _completed.push(wi);
        });
        count = nr;
        r = ::write(_complete_eventfd.get_write_fd(), &count, sizeof(count));
        assert(r == sizeof(count));
    }
}

void thread_pool::submit_item(thread_pool::work_item* item) {
    _queue_has_room.wait().then([this, item] {
        _pending.push(item);
        _start_eventfd.signal(1);
    });
}

void thread_pool::complete() {
    _complete_eventfd.wait().then([this] (size_t count) {
        auto nr = _completed.consume_all([this] (work_item* wi) {
            wi->complete();
            delete wi;
        });
        _queue_has_room.signal(nr);
        complete();
    });
}

int writeable_eventfd::try_create_eventfd(size_t initial) {
    assert(size_t(int(initial)) == initial);
    int r = ::eventfd(initial, EFD_CLOEXEC);
    throw_system_error_on(r == -1);
    return r;
}

void writeable_eventfd::signal(size_t count) {
    uint64_t c = count;
    auto r = ::write(_fd, &c, sizeof(c));
    assert(r == sizeof(c));
}

int readable_eventfd::try_create_eventfd(size_t initial) {
    assert(size_t(int(initial)) == initial);
    int r = ::eventfd(initial, EFD_CLOEXEC | EFD_NONBLOCK);
    throw_system_error_on(r == -1);
    return r;
}

future<size_t> readable_eventfd::wait() {
    return the_reactor.readable(*_fd._s).then([this] {
        uint64_t count;
        int r = ::read(_fd.get_fd(), &count, sizeof(count));
        assert(r == sizeof(count));
        return make_ready_future<size_t>(count);
    });
}

socket_address make_ipv4_address(ipv4_addr addr) {
    socket_address sa;
    sa.u.in.sin_family = AF_INET;
    sa.u.in.sin_port = htons(addr.port);
    std::memcpy(&sa.u.in.sin_addr, addr.host, 4);
    return sa;
}

reactor the_reactor;
<|endoftext|>


<commit_before>#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "libcomparator.hpp"
#include "dataprocess.hpp"
#include "clustering.hpp"
#include <iostream>

void save_result(char* source_path, char const postFix[], char const outputFormat[], cv::Mat& image)
{
    char* destination_path = (char*)calloc( strlen(source_path) + strlen(postFix) + strlen(outputFormat), sizeof(char) );

    char* lastSlash = strrchr ( source_path, '.' );
    int lastSlashPos = lastSlash - source_path;

    strncpy( destination_path, source_path, lastSlashPos );

    int len = strlen( destination_path );
    strcpy( destination_path + len, postFix );

    len += strlen( postFix );
    strcpy( destination_path + len, source_path + lastSlashPos );

    len = strlen( destination_path );
    strcpy( destination_path + len, outputFormat );

    cv::imwrite( destination_path, image);
}

void p_around(unsigned char* data, int before, int after)
{
    for(int i = -before; i < after; ++i )
    {
        if(i == 0)
        {
            std::cout << "MARKER";
        }
        std::cout << data[i];
    }
}

void draw_clusterNumber(cv::Mat& image, std::vector<IndexTransitionCluster> const & result)
{
    std::vector<IndexTransitionCluster> textPoint(result);
    std::stable_sort( textPoint.begin(), textPoint.end(), [](auto el1, auto el2){
        if(el1.getClusterNumber() < el2.getClusterNumber())
        {
            return true;
        }
        else
        {
            return false;
        }
    } );
    textPoint.erase( unique( textPoint.begin(), textPoint.end(), [](auto el1, auto el2){
        if(el1.getClusterNumber() == el2.getClusterNumber())
        {
            return true;
        }
        else
        {
            return false;
        }
    } ), textPoint.end() );
    std::for_each(textPoint.begin(), textPoint.end(), [&image](auto el){
        cv::putText(image, std::to_string(el.getClusterNumber()), cv::Point(el.col, el.row ), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.4, cv::Scalar(200,20,250));//, 1, 8, false);
        std::cout<<el.getClusterNumber()<<" "<<el.row<<" "<<el.col<<"\n";
    });
    std::cout<< result.size()<< "\n";
    std::cout<< textPoint.size()<< "\n";
}

cv::Mat show_result(cv::Mat image, std::vector<IndexTransitionCluster> const & result )
{
    cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );
    cv::imshow( "Display window", image );
    cv::waitKey(0);

    if(image.isContinuous())
    {
        for_each(result.begin(), result.end(), [&image](auto el){
            image.data[el.index( image )] = 255;
            image.data[el.index( image ) + 1] = 0;
            image.data[el.index( image ) + 2] = 255;
        });
        draw_clusterNumber(image, result);
        cv::imshow( "Display window", image );
    }
    else
    {
        std::cout<<"notcontionuous\n";
        return image;
    }
    cv::waitKey(0);

    cv::Mat blackImage(image.rows, image.cols, CV_8UC3, cv::Scalar(0,0,0));
    for_each(result.begin(), result.end(), [&blackImage](auto el){
        blackImage.data[el.index( blackImage )] = 255;
        blackImage.data[el.index( blackImage ) + 1] = 0;
        blackImage.data[el.index( blackImage ) + 2] = 255;
    });
    draw_clusterNumber(blackImage, result);
    cv::imshow( "Display window", blackImage );
    cv::waitKey(0);
    return blackImage;
}

int test_on_image(char path[], double factor, double eps, uint minPts)
{
    cv::Mat image;
    image = cv::imread(path, CV_LOAD_IMAGE_COLOR);
    if(! image.data )
    {
        std::cout<<"\nwrong path\n";
        return -1;
    }

    cv::resize(image, image, cv::Size(), factor, factor, cv::INTER_NEAREST);
    cv::Mat imageCpy = image.clone();
    cv::Mat imageCpy2 = image.clone();
    cv::Mat blackImage;

    TYPE acceptanceLevel = 90;
    ColorStruct entryBalance{ 0.82, 1.05, 1.14 };
    double lightThreshold = 0.3;
    double colorThreshold = 0.2;
    IterateProcess<TYPE> entryProcess(image, acceptanceLevel, lightThreshold, colorThreshold, entryBalance);
    auto result = entryProcess.iterate_HV();
    std::cout << result.size() << '\n';
    DataProcess::concatenate_HV(result);
    DataProcess::remove_noise_matches(result);
    ColorBalance cba( image, 5u, 6 );
    ColorStruct secondBalance = cba.balance( result );

    blackImage = show_result( image, std::vector<IndexTransitionCluster>( result.begin(), result.end() ) );
    result.resize( 0 );
    save_result(path, "_detect1", ".png", blackImage);

    lightThreshold = 0.5;
    colorThreshold = 0.2;
    IterateProcess<TYPE> secondProcess(imageCpy2, acceptanceLevel, lightThreshold, colorThreshold, secondBalance);
    result = secondProcess.iterate_HV();
    DataProcess::concatenate_HV(result);
    DataProcess::remove_noise_matches(result);

    blackImage = show_result(imageCpy2, std::vector<IndexTransitionCluster>( result.begin(), result.end() ));
    save_result(path, "_detect3", ".png", blackImage);

    Clustering clustering( result, Distance::distance_fast, eps, minPts);
    clustering.points_clustering(&Clustering::check_point_zone_linear);
    auto clusters = clustering.getRefVIndexTransitionCluster();
    blackImage = show_result(imageCpy, clusters);
    save_result(path, "_detect2", ".png", blackImage);

    return 0;
}

int broad_HUE(char* path)
{
    cv::Mat image;
    image = cv::imread(path, CV_LOAD_IMAGE_COLOR);
    if(! image.data )
    {
        std::cout<<"\nwrong path\n";
        return -1;
    }

    cvtColor(image, image, CV_BGR2HSV);
    for(int i =2; i < image.rows * image.cols * 3; i+=3)
    {
        image.data[i] = 255;
    }
    cvtColor(image, image, CV_HSV2BGR);
    cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );
    cv::imshow( "Display window", image );
    save_result(path, "_OUT1", ".png", image);

    cv::Mat cpyImage = image.clone();
    cvtColor(cpyImage, cpyImage, CV_BGR2HSV);
    for(int i =2; i < cpyImage.rows * cpyImage.cols * 3; i+=3)
    {
        cpyImage.data[i] = cpyImage.data[i-1];
    }
    cvtColor(cpyImage, cpyImage, CV_HSV2BGR);
    cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );
    cv::imshow( "Display window", cpyImage );
    save_result(path, "_OUT3", ".png", cpyImage);

    cvtColor(image, image, CV_BGR2HSV);
    for(int i =2; i < image.rows * image.cols * 3; i+=3)
    {
        image.data[i] = 255;
    }
    for(int i = 1; i < image.rows * image.cols * 3; i+=3)
    {
        image.data[i] = 255;
    }
    cvtColor(image, image, CV_HSV2BGR);
    cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );
    cv::imshow( "Display window", image );
    save_result(path, "_OUT2", ".png", image);

    return 0;
}

int main( int argc, char** argv )
{
//    test_on_image("/home/szozda/Downloads/refImg/girRef.jpg", 0.25, 4.0, 20);
//    test_on_image("/home/szozda/Downloads/refImg/linThin.png", 1, 6.0, 2);
//    test_on_image("/home/szozda/Downloads/refImg/linThick.png", 1, 6.0, 2);
//    test_on_image("/home/szozda/Downloads/refImg/appRef.jpg", 1, 6.0, 2);
//    test_on_image("/home/szozda/Downloads/refImg/roof.png", 1, 6.0, 2);
//    test_on_image("/home/szozda/Downloads/refImg/cirRef.png", 1, 6.0, 2);
//    test_on_image("/home/szozda/Downloads/refImg/cirRef2.png", 1, 6.0, 2);
//    test_on_image("/home/szozda/Downloads/refImg/cirRef3.png", 1, 6.0, 2);
    test_on_image("/home/szozda/Downloads/refImg/cirRef4.png", 1, 1.0, 2);
//   test_on_image("/home/szozda/Downloads/refImg/cirRef5.png", 1, 6.0, 2);

//    broad_HUE("/home/szozda/Downloads/refImg/palma.jpg");
//    broad_HUE("/home/szozda/Downloads/refImg/table.jpg");
//    broad_HUE("/home/szozda/Downloads/refImg/palma_linear.png");
//    broad_HUE("/home/szozda/Downloads/refImg/roof_black.png");
//    broad_HUE("/home/szozda/Downloads/refImg/roof_invariant.png");
//    broad_HUE("/home/szozda/Downloads/refImg/roof_finlay_invariant.png");

    return 0;
}
<commit_msg>manual execute<commit_after>#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "libcomparator.hpp"
#include "dataprocess.hpp"
#include "clustering.hpp"
#include <iostream>

void save_result(char* source_path, char const postFix[], char const outputFormat[], cv::Mat& image)
{
    char* destination_path = (char*)calloc( strlen(source_path) + strlen(postFix) + strlen(outputFormat), sizeof(char) );

    char* lastSlash = strrchr ( source_path, '.' );
    int lastSlashPos = lastSlash - source_path;

    strncpy( destination_path, source_path, lastSlashPos );

    int len = strlen( destination_path );
    strcpy( destination_path + len, postFix );

    len += strlen( postFix );
    strcpy( destination_path + len, source_path + lastSlashPos );

    len = strlen( destination_path );
    strcpy( destination_path + len, outputFormat );

    cv::imwrite( destination_path, image);
}

void p_around(unsigned char* data, int before, int after)
{
    for(int i = -before; i < after; ++i )
    {
        if(i == 0)
        {
            std::cout << "MARKER";
        }
        std::cout << data[i];
    }
}

void draw_clusterNumber(cv::Mat& image, std::vector<IndexTransitionCluster> const & result)
{
    std::vector<IndexTransitionCluster> textPoint(result);
    std::stable_sort( textPoint.begin(), textPoint.end(), [](auto el1, auto el2){
        if(el1.getClusterNumber() < el2.getClusterNumber())
        {
            return true;
        }
        else
        {
            return false;
        }
    } );
    textPoint.erase( unique( textPoint.begin(), textPoint.end(), [](auto el1, auto el2){
        if(el1.getClusterNumber() == el2.getClusterNumber())
        {
            return true;
        }
        else
        {
            return false;
        }
    } ), textPoint.end() );
    std::for_each(textPoint.begin(), textPoint.end(), [&image](auto el){
        cv::putText(image, std::to_string(el.getClusterNumber()), cv::Point(el.col, el.row ), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.4, cv::Scalar(200,20,250));//, 1, 8, false);
        std::cout<<el.getClusterNumber()<<" "<<el.row<<" "<<el.col<<"\n";
    });
    std::cout<< result.size()<< "\n";
    std::cout<< textPoint.size()<< "\n";
}

cv::Mat show_result(cv::Mat img, std::vector<IndexTransitionCluster> const & result )
{
    cv::Mat image = img.clone();
    cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );
    cv::imshow( "Display window", image );
    cv::waitKey(0);

    if(image.isContinuous())
    {
        for_each(result.begin(), result.end(), [&image](auto el){
            image.data[el.index( image )] = 255;
            image.data[el.index( image ) + 1] = 0;
            image.data[el.index( image ) + 2] = 255;
        });
        draw_clusterNumber(image, result);
        cv::imshow( "Display window", image );
    }
    else
    {
        std::cout<<"notcontionuous\n";
        return image;
    }
//    cv::waitKey(0);

    cv::Mat blackImage(image.rows, image.cols, CV_8UC3, cv::Scalar(0,0,0));
    for_each(result.begin(), result.end(), [&blackImage](auto el){
        blackImage.data[el.index( blackImage )] = 255;
        blackImage.data[el.index( blackImage ) + 1] = 0;
        blackImage.data[el.index( blackImage ) + 2] = 255;
    });
    draw_clusterNumber(blackImage, result);
    cv::imshow( "Display window", blackImage );
    cv::waitKey(0);
    return blackImage;
}

int test_on_image(char path[], double factor, double eps, uint minPts)
{
    cv::Mat image;
    image = cv::imread(path, CV_LOAD_IMAGE_COLOR);
    if(! image.data )
    {
        std::cout<<"\nwrong path\n";
        return -1;
    }

    cv::resize(image, image, cv::Size(), factor, factor, cv::INTER_NEAREST);
    cv::Mat imageCpy = image.clone();
    cv::Mat imageCpy2 = image.clone();
    cv::Mat blackImage;

    TYPE acceptanceLevel = 90;
    ColorStruct entryBalance{ 1.0, 1.0, 1.0 };
    double lightThreshold = 0.3;
    double colorThreshold = 0.2;
    IterateProcess<TYPE> entryProcess(image, acceptanceLevel, lightThreshold, colorThreshold, entryBalance);
    auto result = entryProcess.iterate_HV();
    std::cout << result.size() << '\n';
    DataProcess::concatenate_HV(result);
    blackImage = show_result( image, std::vector<IndexTransitionCluster>( result.begin(), result.end() ) );
    save_result(path, "_noisy", ".png", blackImage);
    DataProcess::remove_noise_matches(result);
    ColorBalance cba( image, 5u, 6 );
    ColorStruct secondBalance = cba.balance( result );

    blackImage = show_result( image, std::vector<IndexTransitionCluster>( result.begin(), result.end() ) );
    save_result(path, "_detect1", ".png", blackImage);
    result.resize( 0 );

    lightThreshold = 0.3;
    colorThreshold = 0.2;
    IterateProcess<TYPE> secondProcess(imageCpy2, acceptanceLevel, lightThreshold, colorThreshold, ColorStruct{ 0.82, 1.05, 1.14 });//secondBalance);
    result = secondProcess.iterate_HV();
    DataProcess::concatenate_HV(result);
    DataProcess::remove_noise_matches(result);

    blackImage = show_result(imageCpy2, std::vector<IndexTransitionCluster>( result.begin(), result.end() ));
    save_result(path, "_detect_balanced", ".png", blackImage);

    Clustering clustering( result, Distance::distance_fast, eps, minPts);
    clustering.points_clustering(&Clustering::check_point_zone_linear);
    auto clusters = clustering.getRefVIndexTransitionCluster();
    blackImage = show_result(imageCpy, clusters);
    save_result(path, "_detect_cluster", ".png", blackImage);

    return 0;
}

int broad_HUE(char* path)
{
    cv::Mat image;
    image = cv::imread(path, CV_LOAD_IMAGE_COLOR);
    if(! image.data )
    {
        std::cout<<"\nwrong path\n";
        return -1;
    }

    cvtColor(image, image, CV_BGR2HSV);
    for(int i =2; i < image.rows * image.cols * 3; i+=3)
    {
        image.data[i] = 255;
    }
    cvtColor(image, image, CV_HSV2BGR);
    cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );
    cv::imshow( "Display window", image );
    save_result(path, "_OUT1", ".png", image);

    cv::Mat cpyImage = image.clone();
    cvtColor(cpyImage, cpyImage, CV_BGR2HSV);
    for(int i =2; i < cpyImage.rows * cpyImage.cols * 3; i+=3)
    {
        cpyImage.data[i] = cpyImage.data[i-1];
    }
    cvtColor(cpyImage, cpyImage, CV_HSV2BGR);
    cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );
    cv::imshow( "Display window", cpyImage );
    save_result(path, "_OUT3", ".png", cpyImage);

    cvtColor(image, image, CV_BGR2HSV);
    for(int i =2; i < image.rows * image.cols * 3; i+=3)
    {
        image.data[i] = 255;
    }
    for(int i = 1; i < image.rows * image.cols * 3; i+=3)
    {
        image.data[i] = 255;
    }
    cvtColor(image, image, CV_HSV2BGR);
    cv::namedWindow( "Display window", cv::WINDOW_AUTOSIZE );
    cv::imshow( "Display window", image );
    save_result(path, "_OUT2", ".png", image);

    return 0;
}

int main( int argc, char** argv )
{
    test_on_image("/home/szozda/Downloads/refImg/girRef.jpg", 0.25, 3.0, 10);
    // test_on_image("/home/szozda/Downloads/refImg/linThin.png", 1, 6.0, 2);
    test_on_image("/home/szozda/Downloads/refImg/linThick.png", 1, 6.0, 2);
    // test_on_image("/home/szozda/Downloads/refImg/appRef.jpg", 1, 6.0, 2);
    // test_on_image("/home/szozda/Downloads/refImg/roof.png", 0.25, 6.0, 2);
    // test_on_image("/home/szozda/Downloads/refImg/cirRef.png", 1, 2.0, 100);
    // test_on_image("/home/szozda/Downloads/refImg/cirRef2.png", 1, 6.0, 2);
    // test_on_image("/home/szozda/Downloads/refImg/cirRef3.png", 1, 6.0, 2);
    // test_on_image("/home/szozda/Downloads/refImg/cirRef4.png", 1, 2.0, 2);
    // test_on_image("/home/szozda/Downloads/refImg/cirRef5.png", 1, 6.0, 2);

   broad_HUE("/home/szozda/Downloads/refImg/girRef.jpg");
//    broad_HUE("/home/szozda/Downloads/refImg/palma.jpg");
//    broad_HUE("/home/szozda/Downloads/refImg/table.jpg");
//    broad_HUE("/home/szozda/Downloads/refImg/palma_linear.png");
//    broad_HUE("/home/szozda/Downloads/refImg/roof_black.png");
//    broad_HUE("/home/szozda/Downloads/refImg/roof_invariant.png");
//    broad_HUE("/home/szozda/Downloads/refImg/roof_finlay_invariant.png");

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Red Hat, Inc.
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "../utils/bgettext/bgettext-lib.h"

#include "TransactionItem.hpp"

// TODO: translations
static const std::map< TransactionItemAction, std::string > transactionItemActionName = {
    {TransactionItemAction::INSTALL, "Install"},
    {TransactionItemAction::DOWNGRADE, "Downgrade"},
    {TransactionItemAction::DOWNGRADED, "Downgraded"},
    {TransactionItemAction::OBSOLETE, "Obsolete"},
    {TransactionItemAction::OBSOLETED, "Obsoleted"},
    {TransactionItemAction::UPGRADE, "Upgrade"},
    {TransactionItemAction::UPGRADED, "Upgraded"},
    {TransactionItemAction::REMOVE, "Removed"},
    {TransactionItemAction::REINSTALL, "Reinstall"},
    {TransactionItemAction::REINSTALLED, "Reinstalled"},
    {TransactionItemAction::REASON_CHANGE, "Reason Change"},
};

static const std::map< TransactionItemAction, std::string > transactionItemActionShort = {
    {TransactionItemAction::INSTALL, "I"},
    {TransactionItemAction::DOWNGRADE, "D"},
    {TransactionItemAction::DOWNGRADED, "D"},
    {TransactionItemAction::OBSOLETE, "O"},
    {TransactionItemAction::OBSOLETED, "O"},
    {TransactionItemAction::UPGRADE, "U"},
    {TransactionItemAction::UPGRADED, "U"},
    // "R" is for Reinstall, therefore use "E" for rEmove (or Erase)
    {TransactionItemAction::REMOVE, "E"},
    {TransactionItemAction::REINSTALL, "R"},
    {TransactionItemAction::REINSTALLED, "R"},
    // TODO: replace "?" with something better
    {TransactionItemAction::REASON_CHANGE, "?"},
};

/*
static const std::map<std::string, TransactionItemReason> nameTransactionItemReason = {
    {, "I"},
    {TransactionItemAction::DOWNGRADE, "D"},
    {TransactionItemAction::DOWNGRADED, "D"},
    {TransactionItemAction::OBSOLETE, "O"},
    {TransactionItemAction::OBSOLETED, "O"},
    {TransactionItemAction::UPGRADE, "U"},
    {TransactionItemAction::UPGRADED, "U"},
    // "R" is for Reinstall, therefore use "E" for rEmove (or Erase)
    {TransactionItemAction::REMOVE, "E"},
    {TransactionItemAction::REINSTALL, "R"},
};
TransactionItemReason to_TransactionItemReason(const std::string & s) {
    return
*/

const std::string &
TransactionItemBase::getActionName()
{
    return transactionItemActionName.at(getAction());
}

const std::string &
TransactionItemBase::getActionShort()
{
    return transactionItemActionShort.at(getAction());
}

TransactionItem::TransactionItem(libdnf::Transaction *trans)
  : trans(trans)
  , transID(0)
  , conn(trans->conn)
{
}

TransactionItem::TransactionItem(SQLite3Ptr conn, int64_t transID)
  : trans(nullptr)
  , transID(transID)
  , conn(conn)
{
}

void
TransactionItem::save()
{
    getItem()->save();
    if (getId() == 0) {
        dbInsert();
    } else {
        dbUpdate();
    }
}

void
TransactionItem::dbInsert()
{
    if (trans == nullptr) {
        throw std::runtime_error(
            _("Attempt to insert transaction item into completed transaction"));
    }

    const char *sql = R"**(
        INSERT INTO
          trans_item (
            id,
            trans_id,
            item_id,
            repo_id,
            action,
            reason,
            state
          )
        VALUES
          (null, ?, ?, ?, ?, ?, ?)
    )**";

    // save the transaction item
    SQLite3::Statement query(*(conn.get()), sql);
    query.bindv(trans->getId(),
                getItem()->getId(),
                libdnf::swdb_private::Repo::getCached(conn, getRepoid())->getId(),
                static_cast< int >(getAction()),
                static_cast< int >(getReason()),
                static_cast< int >(getState()));
    query.step();
    setId(conn->lastInsertRowID());
}

void
TransactionItem::saveReplacedBy()
{
    if (replacedBy.empty()) {
        return;
    }
    const char *sql = "INSERT INTO item_replaced_by VALUES (?, ?)";
    SQLite3::Statement replacedByQuery(*(conn.get()), sql);
    bool first = true;
    for (const auto &newItem : replacedBy) {
        if (!first) {
            // reset the prepared statement, so it can be executed again
            replacedByQuery.reset();
        }
        replacedByQuery.bindv(getId(), newItem->getId());
        replacedByQuery.step();
        first = false;
    }
}

void
TransactionItem::saveState()
{
    const char *sql = R"**(
        UPDATE
          trans_item
        SET
          state = ?
        WHERE
          id = ?
    )**";

    SQLite3::Statement query(*conn, sql);
    query.bindv(static_cast< int >(getState()), getId());
    query.step();
}

void
TransactionItem::dbUpdate()
{
    if (trans == nullptr) {
        throw std::runtime_error(_("Attempt to update transaction item in completed transaction"));
    }

    const char *sql = R"**(
        UPDATE
          trans_item
        SET
          trans_id=?,
          item_id=?,
          repo_id=?,
          action=?,
          reason=?,
          state=?
        WHERE
          id = ?
    )**";

    SQLite3::Statement query(*(conn.get()), sql);
    query.bindv(trans->getId(),
                getItem()->getId(),
                libdnf::swdb_private::Repo::getCached(trans->conn, getRepoid())->getId(),
                static_cast< int >(getAction()),
                static_cast< int >(getReason()),
                static_cast< int >(getState()),
                getId());
    query.step();
}
<commit_msg>[history] Handle duplicate replaced_by records.<commit_after>/*
 * Copyright (C) 2017-2018 Red Hat, Inc.
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "../utils/bgettext/bgettext-lib.h"

#include "TransactionItem.hpp"

// TODO: translations
static const std::map< TransactionItemAction, std::string > transactionItemActionName = {
    {TransactionItemAction::INSTALL, "Install"},
    {TransactionItemAction::DOWNGRADE, "Downgrade"},
    {TransactionItemAction::DOWNGRADED, "Downgraded"},
    {TransactionItemAction::OBSOLETE, "Obsolete"},
    {TransactionItemAction::OBSOLETED, "Obsoleted"},
    {TransactionItemAction::UPGRADE, "Upgrade"},
    {TransactionItemAction::UPGRADED, "Upgraded"},
    {TransactionItemAction::REMOVE, "Removed"},
    {TransactionItemAction::REINSTALL, "Reinstall"},
    {TransactionItemAction::REINSTALLED, "Reinstalled"},
    {TransactionItemAction::REASON_CHANGE, "Reason Change"},
};

static const std::map< TransactionItemAction, std::string > transactionItemActionShort = {
    {TransactionItemAction::INSTALL, "I"},
    {TransactionItemAction::DOWNGRADE, "D"},
    {TransactionItemAction::DOWNGRADED, "D"},
    {TransactionItemAction::OBSOLETE, "O"},
    {TransactionItemAction::OBSOLETED, "O"},
    {TransactionItemAction::UPGRADE, "U"},
    {TransactionItemAction::UPGRADED, "U"},
    // "R" is for Reinstall, therefore use "E" for rEmove (or Erase)
    {TransactionItemAction::REMOVE, "E"},
    {TransactionItemAction::REINSTALL, "R"},
    {TransactionItemAction::REINSTALLED, "R"},
    // TODO: replace "?" with something better
    {TransactionItemAction::REASON_CHANGE, "?"},
};

/*
static const std::map<std::string, TransactionItemReason> nameTransactionItemReason = {
    {, "I"},
    {TransactionItemAction::DOWNGRADE, "D"},
    {TransactionItemAction::DOWNGRADED, "D"},
    {TransactionItemAction::OBSOLETE, "O"},
    {TransactionItemAction::OBSOLETED, "O"},
    {TransactionItemAction::UPGRADE, "U"},
    {TransactionItemAction::UPGRADED, "U"},
    // "R" is for Reinstall, therefore use "E" for rEmove (or Erase)
    {TransactionItemAction::REMOVE, "E"},
    {TransactionItemAction::REINSTALL, "R"},
};
TransactionItemReason to_TransactionItemReason(const std::string & s) {
    return
*/

const std::string &
TransactionItemBase::getActionName()
{
    return transactionItemActionName.at(getAction());
}

const std::string &
TransactionItemBase::getActionShort()
{
    return transactionItemActionShort.at(getAction());
}

TransactionItem::TransactionItem(libdnf::Transaction *trans)
  : trans(trans)
  , transID(0)
  , conn(trans->conn)
{
}

TransactionItem::TransactionItem(SQLite3Ptr conn, int64_t transID)
  : trans(nullptr)
  , transID(transID)
  , conn(conn)
{
}

void
TransactionItem::save()
{
    getItem()->save();
    if (getId() == 0) {
        dbInsert();
    } else {
        dbUpdate();
    }
}

void
TransactionItem::dbInsert()
{
    if (trans == nullptr) {
        throw std::runtime_error(
            _("Attempt to insert transaction item into completed transaction"));
    }

    const char *sql = R"**(
        INSERT INTO
          trans_item (
            id,
            trans_id,
            item_id,
            repo_id,
            action,
            reason,
            state
          )
        VALUES
          (null, ?, ?, ?, ?, ?, ?)
    )**";

    // save the transaction item
    SQLite3::Statement query(*(conn.get()), sql);
    query.bindv(trans->getId(),
                getItem()->getId(),
                libdnf::swdb_private::Repo::getCached(conn, getRepoid())->getId(),
                static_cast< int >(getAction()),
                static_cast< int >(getReason()),
                static_cast< int >(getState()));
    query.step();
    setId(conn->lastInsertRowID());
}

void
TransactionItem::saveReplacedBy()
{
    if (replacedBy.empty()) {
        return;
    }
    const char *sql = "INSERT OR REPLACE INTO item_replaced_by VALUES (?, ?)";
    SQLite3::Statement replacedByQuery(*(conn.get()), sql);
    bool first = true;
    for (const auto &newItem : replacedBy) {
        if (!first) {
            // reset the prepared statement, so it can be executed again
            replacedByQuery.reset();
        }
        replacedByQuery.bindv(getId(), newItem->getId());
        replacedByQuery.step();
        first = false;
    }
}

void
TransactionItem::saveState()
{
    const char *sql = R"**(
        UPDATE
          trans_item
        SET
          state = ?
        WHERE
          id = ?
    )**";

    SQLite3::Statement query(*conn, sql);
    query.bindv(static_cast< int >(getState()), getId());
    query.step();
}

void
TransactionItem::dbUpdate()
{
    if (trans == nullptr) {
        throw std::runtime_error(_("Attempt to update transaction item in completed transaction"));
    }

    const char *sql = R"**(
        UPDATE
          trans_item
        SET
          trans_id=?,
          item_id=?,
          repo_id=?,
          action=?,
          reason=?,
          state=?
        WHERE
          id = ?
    )**";

    SQLite3::Statement query(*(conn.get()), sql);
    query.bindv(trans->getId(),
                getItem()->getId(),
                libdnf::swdb_private::Repo::getCached(trans->conn, getRepoid())->getId(),
                static_cast< int >(getAction()),
                static_cast< int >(getReason()),
                static_cast< int >(getState()),
                getId());
    query.step();
}
<|endoftext|>


<commit_before>// ------------------------------------------------------------------------
// eca-control-interface.cpp: C++ implementation of the Ecasound
//                            Control Interface
// Copyright (C) 2000,2002 Kai Vehmanen (kai.vehmanen@wakkanet.fi)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
// ------------------------------------------------------------------------

#include <iostream>
#include <ecasoundc.h>

#include "eca-control-interface.h"

using std::string;
using std::vector;

/**
 * Class constructor.
 */
ECA_CONTROL_INTERFACE::ECA_CONTROL_INTERFACE (void)
{
  eci_repp = eci_init_r();
}

/**
 * Desctructor.
 */
ECA_CONTROL_INTERFACE::~ECA_CONTROL_INTERFACE (void)
{
  eci_cleanup_r(eci_repp);
}

/**
 * Parse string mode command and act accordingly.
 */
void ECA_CONTROL_INTERFACE::command(const string& cmd)
{
  eci_command_r(eci_repp, cmd.c_str());
}

void ECA_CONTROL_INTERFACE::command_float_arg(const string& cmd, double arg)
{
  eci_command_float_arg_r(eci_repp, cmd.c_str(), arg);
}

const vector<string>& ECA_CONTROL_INTERFACE::last_string_list(void) const
{
  strlist_rep.clear();
  int count = eci_last_string_list_count_r(eci_repp);
  for(int n = 0; n < count; n++) {
    const char* next = eci_last_string_list_item_r(eci_repp, n);
    assert(next != NULL);
    strlist_rep.push_back(string(next));
  }

  return(strlist_rep);
}

const string& ECA_CONTROL_INTERFACE::last_string(void) const
{
  str_rep = string(eci_last_string_r(eci_repp));
  return(str_rep);
}

double ECA_CONTROL_INTERFACE::last_float(void) const
{
  return(eci_last_float_r(eci_repp));
}

int ECA_CONTROL_INTERFACE::last_integer(void) const
{
  return(eci_last_integer_r(eci_repp));
}

long int ECA_CONTROL_INTERFACE::last_long_integer(void) const
{
  return(eci_last_long_integer_r(eci_repp));
}

const string& ECA_CONTROL_INTERFACE::last_error(void) const
{
  str_rep = string(eci_last_error_r(eci_repp));
  return(str_rep);
}

const string& ECA_CONTROL_INTERFACE::last_type(void) const
{
  str_rep = string(eci_last_type_r(eci_repp));
  return(str_rep);
}

bool ECA_CONTROL_INTERFACE::error(void) const
{
  return((eci_error_r(eci_repp) != 0) ? true : false);
}

bool ECA_CONTROL_INTERFACE::events_available(void)
{
  return(false);
}

void ECA_CONTROL_INTERFACE::next_event(void)
{
}

const string& ECA_CONTROL_INTERFACE::current_event(void)
{
  str_rep = "";
  return(str_rep);
}
<commit_msg>Compile fix for solaris.<commit_after>// ------------------------------------------------------------------------
// eca-control-interface.cpp: C++ implementation of the Ecasound
//                            Control Interface
// Copyright (C) 2000,2002 Kai Vehmanen (kai.vehmanen@wakkanet.fi)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
// ------------------------------------------------------------------------

#include <iostream>
#include <cassert>

#include <ecasoundc.h>

#include "eca-control-interface.h"

using std::string;
using std::vector;

/**
 * Class constructor.
 */
ECA_CONTROL_INTERFACE::ECA_CONTROL_INTERFACE (void)
{
  eci_repp = eci_init_r();
}

/**
 * Desctructor.
 */
ECA_CONTROL_INTERFACE::~ECA_CONTROL_INTERFACE (void)
{
  eci_cleanup_r(eci_repp);
}

/**
 * Parse string mode command and act accordingly.
 */
void ECA_CONTROL_INTERFACE::command(const string& cmd)
{
  eci_command_r(eci_repp, cmd.c_str());
}

void ECA_CONTROL_INTERFACE::command_float_arg(const string& cmd, double arg)
{
  eci_command_float_arg_r(eci_repp, cmd.c_str(), arg);
}

const vector<string>& ECA_CONTROL_INTERFACE::last_string_list(void) const
{
  strlist_rep.clear();
  int count = eci_last_string_list_count_r(eci_repp);
  for(int n = 0; n < count; n++) {
    const char* next = eci_last_string_list_item_r(eci_repp, n);
    assert(next != NULL);
    strlist_rep.push_back(string(next));
  }

  return(strlist_rep);
}

const string& ECA_CONTROL_INTERFACE::last_string(void) const
{
  str_rep = string(eci_last_string_r(eci_repp));
  return(str_rep);
}

double ECA_CONTROL_INTERFACE::last_float(void) const
{
  return(eci_last_float_r(eci_repp));
}

int ECA_CONTROL_INTERFACE::last_integer(void) const
{
  return(eci_last_integer_r(eci_repp));
}

long int ECA_CONTROL_INTERFACE::last_long_integer(void) const
{
  return(eci_last_long_integer_r(eci_repp));
}

const string& ECA_CONTROL_INTERFACE::last_error(void) const
{
  str_rep = string(eci_last_error_r(eci_repp));
  return(str_rep);
}

const string& ECA_CONTROL_INTERFACE::last_type(void) const
{
  str_rep = string(eci_last_type_r(eci_repp));
  return(str_rep);
}

bool ECA_CONTROL_INTERFACE::error(void) const
{
  return((eci_error_r(eci_repp) != 0) ? true : false);
}

bool ECA_CONTROL_INTERFACE::events_available(void)
{
  return(false);
}

void ECA_CONTROL_INTERFACE::next_event(void)
{
}

const string& ECA_CONTROL_INTERFACE::current_event(void)
{
  str_rep = "";
  return(str_rep);
}
<|endoftext|>


<commit_before>/*=============================================================================
	Copyright (c) 2012-2013 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

#include "libgibbs/include/libgibbs_pch.hpp"
#include "libgibbs/include/models.hpp"
#include "libtdb/include/logging.hpp"
#include <string>
#include <map>
#include <algorithm>
#include <sstream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/tuple/tuple.hpp>

using boost::spirit::utree;
typedef boost::spirit::utree_type utree_type;
using boost::multi_index_container;
using namespace boost::multi_index;

// count the total number of "mixing" sites in a sublattice set
// non-mixing sites are sublattices with only vacancies in them
double EnergyModel::count_mixing_sites(const sublattice_set_view &ssv) {
	int curindex = 0;
	int sitecount = 0;
	boost::multi_index::index<sublattice_set_view,myindex>::type::iterator ic0,ic1;
	ic0 = get<myindex>(ssv).lower_bound(curindex);
	ic1 = get<myindex>(ssv).upper_bound(curindex);

	// build subview to only "real" sublattices (exclude fake -1 index)
	while (ic0 != ic1) {
		int speccount = std::distance(ic0,ic1);
		if (!(speccount == 1 && (*ic0)->species == "VA")) {
			// only count non-pure vacancy sites
			sitecount += (*ic0)->num_sites;
		}
		++curindex;
		ic0 = get<myindex>(ssv).lower_bound(curindex);
		ic1 = get<myindex>(ssv).upper_bound(curindex);
	}
	return sitecount;
}

// helper function to add multiplicative factors of (y_i - y_j)**k
utree EnergyModel::add_interaction_factor(const std::string &lhs_varname, const std::string &rhs_varname, const double &degree, const utree &input_tree) {
	if (degree == 0) return input_tree;
	utree temp_tree, power_tree, ret_tree;
	temp_tree.push_back("-");
	temp_tree.push_back(lhs_varname);
	temp_tree.push_back(rhs_varname);
	power_tree.push_back("**");
	power_tree.push_back(temp_tree);
	power_tree.push_back(degree);
	if (degree == 1) power_tree = temp_tree;
	ret_tree.push_back("*");
	ret_tree.push_back(power_tree);
	ret_tree.push_back(input_tree);
	return ret_tree;
}

// Normalize by the total number of mixing sites
void EnergyModel::normalize_utree(utree &input_tree, const sublattice_set_view &ssv) {
	utree temp;
	temp.push_back("/");
	temp.push_back(input_tree);
	temp.push_back(count_mixing_sites(ssv));
	input_tree.swap(temp);
}

utree EnergyModel::find_parameter_ast(const sublattice_set_view &subl_view, const parameter_set_view &param_view) {
	BOOST_LOG_NAMED_SCOPE("EnergyModel::find_parameter_ast");
	logger model_log(journal::keywords::channel = "optimizer");
	BOOST_LOG_SEV(model_log, debug) << "enter";
	std::vector<const Parameter*> matches;
	journal::src::severity_channel_logger<severity_level> opt_log(journal::keywords::channel = "optimizer");
	int sublcount = 0;
	std::vector<std::vector<std::string>> search_config;
	auto subl_start = get<myindex>(subl_view).begin();
	auto subl_end = get<myindex>(subl_view).end();
	// TODO: parameter search would be better with a new index that was a derived key of the sublattice count
	// By the time we get here, we've already been filtered to the correct phase and parameter type
	auto param_iter = get<phase_index>(param_view).begin();
	auto param_end = get<phase_index>(param_view).end();

	// Build search configuration
	while (subl_start != subl_end) {
		int index = (*subl_start)->index;

		if (index < 0) {
			++subl_start;
			continue; // skip "fake" negative indices
		}

		// check if the current index exceeds the known sublattice count
		// expand the size of the vector of vectors by an amount equal to the difference
		// NOTE: if we don't do this, we will crash when we attempt to push_back()
		for (auto i = sublcount; i < (index+1); ++i) {
			std::vector<std::string> tempvec;
			search_config.push_back(tempvec);
			sublcount = index+1;
		}

		// Add species to the parameter search configuration
		search_config[(*subl_start)->index].push_back((*subl_start)->species);

		// Sort the sublattice with the newly added element
		//std::sort(search_config[(*subl_start)->index].begin(), search_config[(*subl_start)->index].end());

		++subl_start;
	}

	// Now that we have a search configuration, search through the parameters in param_view

	while (param_iter != param_end) {
		if (search_config.size() != (*param_iter)->constituent_array.size()) {
			// skip if sublattice counts do not match
			std::cout << "paramskip for sublattice mismatch: " << search_config.size() << " != " << (*param_iter)->constituent_array.size() << std::endl;
			std::cout << "search_config: ";
			for (auto i = search_config.begin(); i != search_config.end(); ++i) {
				for (auto j = (*i).begin(); j != (*i).end(); ++j) {
					std::cout << (*j) << ",";
				}
				std::cout << ":";
			}
			std::cout << std::endl;
			++param_iter;
			continue;
		}
		// We cannot do a direct comparison of the nested vectors because
		//    we must check the case where the wildcard '*' is used in some sublattices in the parameter
		bool isvalid = true;
		auto array_begin = (*param_iter)->constituent_array.begin();
		auto array_iter = array_begin;
		auto array_end = (*param_iter)->constituent_array.end();

		// Now perform a sublattice comparison
		while (array_iter != array_end) {
			const std::string firstelement = *(*array_iter).cbegin();
			// if the parameter sublattices don't match, or the parameter isn't using a wildcard, do not match
			// NOTE: A wildcard will not match if we are looking for a 2+ species interaction in that sublattice
			// The interaction must be explicitly stated to match
			if (!(
				(*array_iter) == search_config[std::distance(array_begin,array_iter)])
				|| (firstelement == "*" && search_config[std::distance(array_begin,array_iter)].size() == 1)
				) {
				isvalid = false;
				break;
			}
			++array_iter;
		}
		if (isvalid) {
			// We found a valid parameter, save it
			matches.push_back(*param_iter);
		}

		++param_iter;
	}

	if (matches.size() >= 1) {
		//if (matches.size() == 1) return matches[0]->ast; // exactly one parameter found
		// one or more matching parameters found
		// first, we need to figure out if these are interaction parameters of different polynomial degrees
		// if they are, then all of them are allowed to match
		// if not, match the one with the fewest wildcards
		// TODO: if some have equal numbers of wildcards, choose the first one and warn the user
		std::map<double,const Parameter*> minwilds; // map polynomial degrees to parameters
		bool interactionparam = false;
		bool returnall = true;
		for (auto i = matches.begin(); i != matches.end(); ++i) {
			int wildcount = 0;
			const double curdegree = (*i)->degree;
			const auto array_begin = (*i)->constituent_array.begin();
			const auto array_end = (*i)->constituent_array.end();
			for (auto j = array_begin; j != array_end; ++j) {
				if ((*j)[0] == "*") ++wildcount;
				if ((*j).size() == 2) interactionparam = true; // Binary interaction parameter
				if ((*j).size() == 3) interactionparam = true; // Ternary interaction parameter
			}
			if (minwilds.find(curdegree) == minwilds.end() || wildcount < minwilds[curdegree]->wildcount()) {
				minwilds[curdegree] = (*i);
			}
		}

		// We're fine to return minparam's AST if all polynomial degrees are the same
		// TODO: It seems like it's possible to construct corner cases with duplicate
		// parameters with varying degrees that would confuse this matching.

		//if (minwilds.size() == 1) return minwilds.cbegin()->second->ast;

		if (minwilds.size() > 1 && (!interactionparam)) {
			BOOST_THROW_EXCEPTION(internal_error() << specific_errinfo("Multiple polynomial degrees specified for non-interaction parameters") << ast_errinfo(minwilds.cbegin()->second->ast));
		}

		//if (minwilds.size() > 1 && interactionparam) {
			utree ret_tree;
			if (minwilds.size() != matches.size()) {
				// not all polynomial degrees here are unique
				// it shouldn't be a problem, it should just mean we matched some based on wildcards
				// (this is just here as a note)
			}
			for (auto param = minwilds.begin(); param != minwilds.end(); ++param) {
				const auto array_begin = param->second->constituent_array.begin();
				const auto array_end = param->second->constituent_array.end();
				for (auto j = array_begin; j != array_end; ++j) {
					utree next_term;
					if ((*j).size() == 1) { // Unary parameter (non-interaction)
						next_term = param->second->ast;
					}
					if ((*j).size() == 2) { // Binary interactions
						// get the names of the variables that are interacting
						std::string lhs_var, rhs_var;
						std::stringstream varname1, varname2;
						varname1 << param->second->phasename() << "_" << std::distance(array_begin,j) << "_" << (*j)[0];
						varname2 << param->second->phasename() << "_" << std::distance(array_begin,j) << "_" << (*j)[1];
						lhs_var = varname1.str();
						rhs_var = varname2.str();
						// add to the parameter tree a factor of (y_i - y_j)**k, where k is the degree and i,j are interacting
						next_term = add_interaction_factor(lhs_var, rhs_var, param->second->degree, param->second->ast);
					}
					if ((*j).size() == 3) { // Ternary interactions
						// the order the parameter corresponds to the index of the relevant component in the constituent array
						// should be an integer quantity; left auto here to let other data structures choose type
						auto order = param->second->degree;
						if (order > ((*j).size() - 1)) {
							BOOST_THROW_EXCEPTION(internal_error() << specific_errinfo("Order of ternary interaction parameter is out of bounds"));
						}
						std::stringstream varname;
						varname << param->second->phasename() << "_" << std::distance(array_begin,j) << "_" << (*j)[order];
						std::string varstr(varname.str());
						next_term.push_back("*");
						// TODO: should actually be varstr + Muggianu correction terms for higher-order systems
						next_term.push_back(std::move(varstr));
						next_term.push_back(param->second->ast);
					}
					if (next_term.which() != utree_type::invalid_type) {
						// add next_term to the sum (or make ret_tree equal to first term)
						if (ret_tree.which() != utree_type::invalid_type) {
							utree temp_tree;
							temp_tree.push_back("+");
							temp_tree.push_back(ret_tree);
							temp_tree.push_back(next_term);
							ret_tree.swap(temp_tree);
						}
						else ret_tree = std::move(next_term);
					}
				}
			//}
			BOOST_LOG_SEV(model_log, debug) << "returning: " << ret_tree;
			return ret_tree; // return the parameter tree
		}

		if (minwilds.size() == 0) {
			BOOST_THROW_EXCEPTION(internal_error() << specific_errinfo("Failed to match parameter, but the parameter had already been found"));
		}
	}
	BOOST_LOG_SEV(model_log, debug) << "no parameter found";
	return 0; // no parameter found
}
<commit_msg>Fix regression caused by ternary parameter support<commit_after>/*=============================================================================
	Copyright (c) 2012-2013 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

#include "libgibbs/include/libgibbs_pch.hpp"
#include "libgibbs/include/models.hpp"
#include "libtdb/include/logging.hpp"
#include <string>
#include <map>
#include <algorithm>
#include <sstream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/tuple/tuple.hpp>

using boost::spirit::utree;
typedef boost::spirit::utree_type utree_type;
using boost::multi_index_container;
using namespace boost::multi_index;

// count the total number of "mixing" sites in a sublattice set
// non-mixing sites are sublattices with only vacancies in them
double EnergyModel::count_mixing_sites(const sublattice_set_view &ssv) {
	int curindex = 0;
	int sitecount = 0;
	boost::multi_index::index<sublattice_set_view,myindex>::type::iterator ic0,ic1;
	ic0 = get<myindex>(ssv).lower_bound(curindex);
	ic1 = get<myindex>(ssv).upper_bound(curindex);

	// build subview to only "real" sublattices (exclude fake -1 index)
	while (ic0 != ic1) {
		int speccount = std::distance(ic0,ic1);
		if (!(speccount == 1 && (*ic0)->species == "VA")) {
			// only count non-pure vacancy sites
			sitecount += (*ic0)->num_sites;
		}
		++curindex;
		ic0 = get<myindex>(ssv).lower_bound(curindex);
		ic1 = get<myindex>(ssv).upper_bound(curindex);
	}
	return sitecount;
}

// helper function to add multiplicative factors of (y_i - y_j)**k
utree EnergyModel::add_interaction_factor(const std::string &lhs_varname, const std::string &rhs_varname, const double &degree, const utree &input_tree) {
	if (degree == 0) return input_tree;
	utree temp_tree, power_tree, ret_tree;
	temp_tree.push_back("-");
	temp_tree.push_back(lhs_varname);
	temp_tree.push_back(rhs_varname);
	power_tree.push_back("**");
	power_tree.push_back(temp_tree);
	power_tree.push_back(degree);
	if (degree == 1) power_tree = temp_tree;
	ret_tree.push_back("*");
	ret_tree.push_back(power_tree);
	ret_tree.push_back(input_tree);
	return ret_tree;
}

// Normalize by the total number of mixing sites
void EnergyModel::normalize_utree(utree &input_tree, const sublattice_set_view &ssv) {
	utree temp;
	temp.push_back("/");
	temp.push_back(input_tree);
	temp.push_back(count_mixing_sites(ssv));
	input_tree.swap(temp);
}

utree EnergyModel::find_parameter_ast(const sublattice_set_view &subl_view, const parameter_set_view &param_view) {
	BOOST_LOG_NAMED_SCOPE("EnergyModel::find_parameter_ast");
	logger model_log(journal::keywords::channel = "optimizer");
	BOOST_LOG_SEV(model_log, debug) << "enter";
	std::vector<const Parameter*> matches;
	journal::src::severity_channel_logger<severity_level> opt_log(journal::keywords::channel = "optimizer");
	int sublcount = 0;
	std::vector<std::vector<std::string>> search_config;
	auto subl_start = get<myindex>(subl_view).begin();
	auto subl_end = get<myindex>(subl_view).end();
	// TODO: parameter search would be better with a new index that was a derived key of the sublattice count
	// By the time we get here, we've already been filtered to the correct phase and parameter type
	auto param_iter = get<phase_index>(param_view).begin();
	auto param_end = get<phase_index>(param_view).end();

	// Build search configuration
	while (subl_start != subl_end) {
		int index = (*subl_start)->index;

		if (index < 0) {
			++subl_start;
			continue; // skip "fake" negative indices
		}

		// check if the current index exceeds the known sublattice count
		// expand the size of the vector of vectors by an amount equal to the difference
		// NOTE: if we don't do this, we will crash when we attempt to push_back()
		for (auto i = sublcount; i < (index+1); ++i) {
			std::vector<std::string> tempvec;
			search_config.push_back(tempvec);
			sublcount = index+1;
		}

		// Add species to the parameter search configuration
		search_config[(*subl_start)->index].push_back((*subl_start)->species);

		// Sort the sublattice with the newly added element
		//std::sort(search_config[(*subl_start)->index].begin(), search_config[(*subl_start)->index].end());

		++subl_start;
	}

	// Now that we have a search configuration, search through the parameters in param_view

	while (param_iter != param_end) {
		if (search_config.size() != (*param_iter)->constituent_array.size()) {
			// skip if sublattice counts do not match
			std::cout << "paramskip for sublattice mismatch: " << search_config.size() << " != " << (*param_iter)->constituent_array.size() << std::endl;
			std::cout << "search_config: ";
			for (auto i = search_config.begin(); i != search_config.end(); ++i) {
				for (auto j = (*i).begin(); j != (*i).end(); ++j) {
					std::cout << (*j) << ",";
				}
				std::cout << ":";
			}
			std::cout << std::endl;
			++param_iter;
			continue;
		}
		// We cannot do a direct comparison of the nested vectors because
		//    we must check the case where the wildcard '*' is used in some sublattices in the parameter
		bool isvalid = true;
		auto array_begin = (*param_iter)->constituent_array.begin();
		auto array_iter = array_begin;
		auto array_end = (*param_iter)->constituent_array.end();

		// Now perform a sublattice comparison
		while (array_iter != array_end) {
			const std::string firstelement = *(*array_iter).cbegin();
			// if the parameter sublattices don't match, or the parameter isn't using a wildcard, do not match
			// NOTE: A wildcard will not match if we are looking for a 2+ species interaction in that sublattice
			// The interaction must be explicitly stated to match
			if (!(
				(*array_iter) == search_config[std::distance(array_begin,array_iter)])
				|| (firstelement == "*" && search_config[std::distance(array_begin,array_iter)].size() == 1)
				) {
				isvalid = false;
				break;
			}
			++array_iter;
		}
		if (isvalid) {
			// We found a valid parameter, save it
			matches.push_back(*param_iter);
		}

		++param_iter;
	}

	if (matches.size() >= 1) {
		// one or more matching parameters found
		// first, we need to figure out if these are interaction parameters of different polynomial degrees
		// if they are, then all of them are allowed to match
		// if not, match the one with the fewest wildcards
		// TODO: if some have equal numbers of wildcards, choose the first one and warn the user
		std::map<double,const Parameter*> minwilds; // map polynomial degrees to parameters
		bool interactionparam = false;
		utree ret_tree;
		for (auto i = matches.begin(); i != matches.end(); ++i) {
			int wildcount = 0;
			const double curdegree = (*i)->degree;
			const auto array_begin = (*i)->constituent_array.begin();
			const auto array_end = (*i)->constituent_array.end();
			for (auto j = array_begin; j != array_end; ++j) {
				if ((*j)[0] == "*") ++wildcount;
				if ((*j).size() == 2) interactionparam = true; // Binary interaction parameter
				if ((*j).size() == 3) interactionparam = true; // Ternary interaction parameter
			}
			if (minwilds.find(curdegree) == minwilds.end() || wildcount < minwilds[curdegree]->wildcount()) {
				minwilds[curdegree] = (*i);
				BOOST_LOG_SEV(model_log, debug) << "added minwilds[" << curdegree << "] = " << (*i)->ast;
			}
		}

		// Note: It seems like it's possible to construct corner cases with duplicate
		// parameters with varying degrees that would confuse this matching.

		if (minwilds.size() > 1 && (!interactionparam)) {
			BOOST_THROW_EXCEPTION(internal_error() << specific_errinfo("Multiple polynomial degrees specified for non-interaction parameters") << ast_errinfo(minwilds.cbegin()->second->ast));
		}

		if (minwilds.size() != matches.size()) {
			// not all polynomial degrees here are unique
			// it shouldn't be a problem, it should just mean we matched some based on wildcards
			// (this is just here as a note)
		}
		for (auto param = minwilds.begin(); param != minwilds.end(); ++param) {
			BOOST_LOG_SEV(model_log,  debug) << "looping minwilds " << std::distance(minwilds.begin(),param);
			const auto array_begin = param->second->constituent_array.begin();
			const auto array_end = param->second->constituent_array.end();
			for (auto j = array_begin; j != array_end; ++j) {
				utree next_term;
				if ((*j).size() == 1 && (!interactionparam)) { // Unary parameter (non-interaction)
					next_term = param->second->ast;
					BOOST_LOG_SEV(model_log, debug) << "Unary next_term = " << next_term;
				}
				if ((*j).size() == 2) { // Binary interactions
					// get the names of the variables that are interacting
					std::string lhs_var, rhs_var;
					std::stringstream varname1, varname2;
					varname1 << param->second->phasename() << "_" << std::distance(array_begin,j) << "_" << (*j)[0];
					varname2 << param->second->phasename() << "_" << std::distance(array_begin,j) << "_" << (*j)[1];
					lhs_var = varname1.str();
					rhs_var = varname2.str();
					// add to the parameter tree a factor of (y_i - y_j)**k, where k is the degree and i,j are interacting
					next_term = add_interaction_factor(lhs_var, rhs_var, param->second->degree, param->second->ast);
					BOOST_LOG_SEV(model_log, debug) << "Binary next_term = " << next_term;
				}
				if ((*j).size() == 3) { // Ternary interactions
					// the order the parameter corresponds to the index of the relevant component in the constituent array
					// should be an integer quantity; left auto here to let other data structures choose type
					auto order = param->second->degree;
					if (order > ((*j).size() - 1)) {
						BOOST_THROW_EXCEPTION(internal_error() << specific_errinfo("Order of ternary interaction parameter is out of bounds"));
					}
					std::stringstream varname;
					varname << param->second->phasename() << "_" << std::distance(array_begin,j) << "_" << (*j)[order];
					std::string varstr(varname.str());
					next_term.push_back("*");
					// TODO: should actually be varstr + Muggianu correction terms for higher-order systems
					next_term.push_back(std::move(varstr));
					next_term.push_back(param->second->ast);
					BOOST_LOG_SEV(model_log, debug) << "Ternary next_term = " << next_term;
				}
				if (next_term.which() != utree_type::invalid_type) {
					// add next_term to the sum (or make ret_tree equal to first term)
					if (ret_tree.which() != utree_type::invalid_type) {
						utree temp_tree;
						temp_tree.push_back("+");
						temp_tree.push_back(ret_tree);
						temp_tree.push_back(next_term);
						ret_tree.swap(temp_tree);
					}
					else ret_tree = std::move(next_term);
					break;
				}
			}
		}

		if (minwilds.size() == 0) {
			BOOST_THROW_EXCEPTION(internal_error() << specific_errinfo("Failed to match parameter, but the parameter had already been found"));
		}

		BOOST_LOG_SEV(model_log, debug) << "returning: " << ret_tree;
		return ret_tree; // return the parameter tree
	}
	BOOST_LOG_SEV(model_log, debug) << "no parameter found";
	return 0; // no parameter found
}
<|endoftext|>


<commit_before>//
//  TestScene.cpp
//  ee_x_test
//
//  Created by eps on 1/25/21.
//

#include "MainScene.hpp"

#include <cocos2d.h>
#include <ui/CocosGUI.h>

#include <ee/Cpp.hpp>

#include "BannerAdScene.hpp"
#include "FullScreenAdScene.hpp"

namespace eetest {
using Self = MainScene;

cocos2d::Scene* Self::openScene() {
    auto scene = cocos2d::Scene::create();
    auto node = new Self();
    node->autorelease();
    node->init();
    scene->addChild(node);
    return scene;
}

bool Self::init() {
    if (not Super::init()) {
        return false;
    }
    auto fileUtils = cocos2d::FileUtils::getInstance();
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
    auto&& fileName = "ads_config_ios.json";
#else  // CC_TARGET_PLATFORM == CC_PLATFORM_IOS
    auto&& fileName = "ads_config_android.json";
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_IOS
    auto adsConfig = fileUtils->getStringFromFile(fileName);
    auto adsManager = std::make_shared<ee::DefaultAdsManager>(adsConfig);
    ee::noAwait(adsManager->initialize());

    auto&& winSize = _director->getWinSize();
    setContentSize(winSize);

    auto testBannerAdButton = cocos2d::ui::Button::create();
    testBannerAdButton->setContentSize(cocos2d::Size(200, 60));
    testBannerAdButton->setPosition(
        cocos2d::Point(winSize.width / 2, winSize.height / 2 + 25));
    testBannerAdButton->setTitleText("Test Banner Ad");
    testBannerAdButton->addClickEventListener(std::bind([this, adsManager] {
        auto scene = BannerAdScene::openScene(adsManager);
        _director->replaceScene(scene);
    }));

    auto testFullScreenAdButton = cocos2d::ui::Button::create();
    testFullScreenAdButton->setContentSize(cocos2d::Size(200, 60));
    testFullScreenAdButton->setPosition(
        cocos2d::Point(winSize.width / 2, winSize.height / 2 - 25));
    testFullScreenAdButton->setTitleText("Test Full-screen Ad");
    testFullScreenAdButton->addClickEventListener(std::bind([this, adsManager] {
        auto scene = FullScreenAdScene::openScene(adsManager);
        _director->replaceScene(scene);
    }));

    addChild(testBannerAdButton);
    addChild(testFullScreenAdButton);
    return true;
}
} // namespace eetest
<commit_msg>Fix config path (android).<commit_after>//
//  TestScene.cpp
//  ee_x_test
//
//  Created by eps on 1/25/21.
//

#include "MainScene.hpp"

#include <cocos2d.h>
#include <ui/CocosGUI.h>

#include <ee/Cpp.hpp>

#include "BannerAdScene.hpp"
#include "FullScreenAdScene.hpp"

namespace eetest {
using Self = MainScene;

cocos2d::Scene* Self::openScene() {
    auto scene = cocos2d::Scene::create();
    auto node = new Self();
    node->autorelease();
    node->init();
    scene->addChild(node);
    return scene;
}

bool Self::init() {
    if (not Super::init()) {
        return false;
    }
    auto fileUtils = cocos2d::FileUtils::getInstance();
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
    auto&& fileName = "ads_config_ios.json";
#else  // CC_TARGET_PLATFORM == CC_PLATFORM_IOS
    auto&& fileName = "config/ads_config_android.json";
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_IOS
    auto adsConfig = fileUtils->getStringFromFile(fileName);
    auto adsManager = std::make_shared<ee::DefaultAdsManager>(adsConfig);
    ee::noAwait(adsManager->initialize());

    auto&& winSize = _director->getWinSize();
    setContentSize(winSize);

    auto testBannerAdButton = cocos2d::ui::Button::create();
    testBannerAdButton->setContentSize(cocos2d::Size(200, 60));
    testBannerAdButton->setPosition(
        cocos2d::Point(winSize.width / 2, winSize.height / 2 + 25));
    testBannerAdButton->setTitleText("Test Banner Ad");
    testBannerAdButton->addClickEventListener(std::bind([this, adsManager] {
        auto scene = BannerAdScene::openScene(adsManager);
        _director->replaceScene(scene);
    }));

    auto testFullScreenAdButton = cocos2d::ui::Button::create();
    testFullScreenAdButton->setContentSize(cocos2d::Size(200, 60));
    testFullScreenAdButton->setPosition(
        cocos2d::Point(winSize.width / 2, winSize.height / 2 - 25));
    testFullScreenAdButton->setTitleText("Test Full-screen Ad");
    testFullScreenAdButton->addClickEventListener(std::bind([this, adsManager] {
        auto scene = FullScreenAdScene::openScene(adsManager);
        _director->replaceScene(scene);
    }));

    addChild(testBannerAdButton);
    addChild(testFullScreenAdButton);
    return true;
}
} // namespace eetest
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void adjoint(const MatrixType& m)
{
  /* this test covers the following files:
     Transpose.h Conjugate.h Dot.h
  */

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
  int rows = m.rows();
  int cols = m.cols();

  RealScalar largerEps = test_precision<RealScalar>();
  if (ei_is_same_type<RealScalar,float>::ret)
    largerEps = RealScalar(1e-3f);

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols),
             mzero = MatrixType::Zero(rows, cols),
             identity = SquareMatrixType::Identity(rows, rows),
             square = SquareMatrixType::Random(rows, rows);
  VectorType v1 = VectorType::Random(rows),
             v2 = VectorType::Random(rows),
             v3 = VectorType::Random(rows),
             vzero = VectorType::Zero(rows);

  Scalar s1 = ei_random<Scalar>(),
         s2 = ei_random<Scalar>();

  // check basic compatibility of adjoint, transpose, conjugate
  VERIFY_IS_APPROX(m1.transpose().conjugate().adjoint(),    m1);
  VERIFY_IS_APPROX(m1.adjoint().conjugate().transpose(),    m1);

  // check multiplicative behavior
  VERIFY_IS_APPROX((m1.adjoint() * m2).adjoint(),           m2.adjoint() * m1);
  VERIFY_IS_APPROX((s1 * m1).adjoint(),                     ei_conj(s1) * m1.adjoint());

  // check basic properties of dot, norm, norm2
  typedef typename NumTraits<Scalar>::Real RealScalar;
  VERIFY(ei_isApprox((s1 * v1 + s2 * v2).eigen2_dot(v3),   s1 * v1.eigen2_dot(v3) + s2 * v2.eigen2_dot(v3), largerEps));
  VERIFY(ei_isApprox(v3.eigen2_dot(s1 * v1 + s2 * v2),     ei_conj(s1)*v3.eigen2_dot(v1)+ei_conj(s2)*v3.eigen2_dot(v2), largerEps));
  VERIFY_IS_APPROX(ei_conj(v1.eigen2_dot(v2)),               v2.eigen2_dot(v1));
  VERIFY_IS_APPROX(ei_abs(v1.eigen2_dot(v1)),                v1.squaredNorm());
  if(NumTraits<Scalar>::HasFloatingPoint)
    VERIFY_IS_APPROX(v1.squaredNorm(),                      v1.norm() * v1.norm());
  VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(vzero.eigen2_dot(v1)),  static_cast<RealScalar>(1));
  if(NumTraits<Scalar>::HasFloatingPoint)
    VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(),         static_cast<RealScalar>(1));

  // check compatibility of dot and adjoint
  VERIFY(ei_isApprox(v1.eigen2_dot(square * v2), (square.adjoint() * v1).eigen2_dot(v2), largerEps));

  // like in testBasicStuff, test operator() to check const-qualification
  int r = ei_random<int>(0, rows-1),
      c = ei_random<int>(0, cols-1);
  VERIFY_IS_APPROX(m1.conjugate()(r,c), ei_conj(m1(r,c)));
  VERIFY_IS_APPROX(m1.adjoint()(c,r), ei_conj(m1(r,c)));

  if(NumTraits<Scalar>::HasFloatingPoint)
  {
    // check that Random().normalized() works: tricky as the random xpr must be evaluated by
    // normalized() in order to produce a consistent result.
    VERIFY_IS_APPROX(VectorType::Random(rows).normalized().norm(), RealScalar(1));
  }

  // check inplace transpose
  m3 = m1;
  m3.transposeInPlace();
  VERIFY_IS_APPROX(m3,m1.transpose());
  m3.transposeInPlace();
  VERIFY_IS_APPROX(m3,m1);

}

void test_eigen2_adjoint()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( adjoint(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( adjoint(Matrix3d()) );
    CALL_SUBTEST_3( adjoint(Matrix4f()) );
    CALL_SUBTEST_4( adjoint(MatrixXcf(4, 4)) );
    CALL_SUBTEST_5( adjoint(MatrixXi(8, 12)) );
    CALL_SUBTEST_6( adjoint(MatrixXf(21, 21)) );
  }
  // test a large matrix only once
  CALL_SUBTEST_7( adjoint(Matrix<float, 100, 100>()) );
}

<commit_msg>Fix bug 205: eigen2_adjoint_5 test fails.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void adjoint(const MatrixType& m)
{
  /* this test covers the following files:
     Transpose.h Conjugate.h Dot.h
  */

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
  int rows = m.rows();
  int cols = m.cols();

  RealScalar largerEps = test_precision<RealScalar>();
  if (ei_is_same_type<RealScalar,float>::ret)
    largerEps = RealScalar(1e-3f);

  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols),
             mzero = MatrixType::Zero(rows, cols),
             identity = SquareMatrixType::Identity(rows, rows),
             square = SquareMatrixType::Random(rows, rows);
  VectorType v1 = VectorType::Random(rows),
             v2 = VectorType::Random(rows),
             v3 = VectorType::Random(rows),
             vzero = VectorType::Zero(rows);

  Scalar s1 = ei_random<Scalar>(),
         s2 = ei_random<Scalar>();

  // check basic compatibility of adjoint, transpose, conjugate
  VERIFY_IS_APPROX(m1.transpose().conjugate().adjoint(),    m1);
  VERIFY_IS_APPROX(m1.adjoint().conjugate().transpose(),    m1);

  // check multiplicative behavior
  VERIFY_IS_APPROX((m1.adjoint() * m2).adjoint(),           m2.adjoint() * m1);
  VERIFY_IS_APPROX((s1 * m1).adjoint(),                     ei_conj(s1) * m1.adjoint());

  // check basic properties of dot, norm, norm2
  typedef typename NumTraits<Scalar>::Real RealScalar;
  VERIFY(ei_isApprox((s1 * v1 + s2 * v2).eigen2_dot(v3),   s1 * v1.eigen2_dot(v3) + s2 * v2.eigen2_dot(v3), largerEps));
  VERIFY(ei_isApprox(v3.eigen2_dot(s1 * v1 + s2 * v2),     ei_conj(s1)*v3.eigen2_dot(v1)+ei_conj(s2)*v3.eigen2_dot(v2), largerEps));
  VERIFY_IS_APPROX(ei_conj(v1.eigen2_dot(v2)),               v2.eigen2_dot(v1));
  VERIFY_IS_APPROX(ei_real(v1.eigen2_dot(v1)),               v1.squaredNorm());
  if(NumTraits<Scalar>::HasFloatingPoint)
    VERIFY_IS_APPROX(v1.squaredNorm(),                      v1.norm() * v1.norm());
  VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(vzero.eigen2_dot(v1)),  static_cast<RealScalar>(1));
  if(NumTraits<Scalar>::HasFloatingPoint)
    VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(),         static_cast<RealScalar>(1));

  // check compatibility of dot and adjoint
  VERIFY(ei_isApprox(v1.eigen2_dot(square * v2), (square.adjoint() * v1).eigen2_dot(v2), largerEps));

  // like in testBasicStuff, test operator() to check const-qualification
  int r = ei_random<int>(0, rows-1),
      c = ei_random<int>(0, cols-1);
  VERIFY_IS_APPROX(m1.conjugate()(r,c), ei_conj(m1(r,c)));
  VERIFY_IS_APPROX(m1.adjoint()(c,r), ei_conj(m1(r,c)));

  if(NumTraits<Scalar>::HasFloatingPoint)
  {
    // check that Random().normalized() works: tricky as the random xpr must be evaluated by
    // normalized() in order to produce a consistent result.
    VERIFY_IS_APPROX(VectorType::Random(rows).normalized().norm(), RealScalar(1));
  }

  // check inplace transpose
  m3 = m1;
  m3.transposeInPlace();
  VERIFY_IS_APPROX(m3,m1.transpose());
  m3.transposeInPlace();
  VERIFY_IS_APPROX(m3,m1);

}

void test_eigen2_adjoint()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( adjoint(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_2( adjoint(Matrix3d()) );
    CALL_SUBTEST_3( adjoint(Matrix4f()) );
    CALL_SUBTEST_4( adjoint(MatrixXcf(4, 4)) );
    CALL_SUBTEST_5( adjoint(MatrixXi(8, 12)) );
    CALL_SUBTEST_6( adjoint(MatrixXf(21, 21)) );
  }
  // test a large matrix only once
  CALL_SUBTEST_7( adjoint(Matrix<float, 100, 100>()) );
}

<|endoftext|>


<commit_before>#include "corrcheck.h"

int create_database(const std::string& directory)
{
    std::vector<File> file_list = get_file_list(directory);

    // checksum all given files
    SHA256_CTX sha;
    unsigned char* const buffer = new unsigned char[BUFFER_SIZE];
    for(unsigned int i = 0; i < file_list.size(); i++)
    {
	SHA256_Init(&sha);
	FILE* file = fopen(std::string(directory + "/" + file_list[i].name).c_str(), "r");
	while(!feof(file))
	{
	    const unsigned int bytes_read = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, file);
	    SHA256_Update(&sha, buffer, bytes_read);
	}
	unsigned char hash[SHA256_DIGEST_LENGTH];
	SHA256_Final(hash, &sha);
	std::cout << file_list[i].name << " -> ";
	for(unsigned int b = 0; b < SHA256_DIGEST_LENGTH; b++)
	{
	    std::cout << std::hex << (unsigned int)hash[b];
	    file_list[i].checksum[b] = hash[b];
	}
	std::cout << std::endl;
	fclose(file);
    }
    delete[] buffer;

    return write_database(directory, file_list);
}

std::vector<File> get_file_list(const std::string& directory)
{
    std::vector<File> file_list;
    DIR* dir = opendir(directory.c_str());
    if(dir == nullptr)
    {
	std::cout << "\'" << directory << "\' is not readable." << std::endl;
	return file_list;
    }

    struct stat st;
    struct dirent* entry = readdir(dir);
    while(entry != nullptr)
    {
	// only add the file to the list if it is not a directory
	lstat(entry->d_name, &st);
	if(!S_ISDIR(st.st_mode) && std::string(entry->d_name).compare(".corrcheckdb") != 0)
	    file_list.push_back(File(std::string(entry->d_name)));
	entry = readdir(dir);
    }
    closedir(dir);

    return file_list;
}

int write_database(const std::string& directory, const std::vector<File>& file_list)
{
    // write the file names and checksums out
    // format: <checksum> <null-terminated string of name>
    FILE* file = fopen(std::string(directory + "/.corrcheckdb").c_str(), "w");
    if(file == NULL) return FAILURE;

    for(unsigned int i = 0; i < file_list.size(); i++)
    {
	fwrite(file_list[i].checksum, sizeof(unsigned char), SHA256_DIGEST_LENGTH, file);
	fwrite(file_list[i].name.c_str(), sizeof(char), file_list[i].name.length() + 1, file);
    }
    fclose(file);

    return SUCCESS;
}
<commit_msg>Return if no files to checksum.<commit_after>#include "corrcheck.h"

int create_database(const std::string& directory)
{
    std::vector<File> file_list = get_file_list(directory);
    if(file_list.size() == 0)
    {
	std::cout << "No files to checksum." << std::endl;
	return FAILURE;
    }

    // checksum all given files
    SHA256_CTX sha;
    unsigned char* const buffer = new unsigned char[BUFFER_SIZE];
    for(unsigned int i = 0; i < file_list.size(); i++)
    {
	SHA256_Init(&sha);
	FILE* file = fopen(std::string(directory + "/" + file_list[i].name).c_str(), "r");
	while(!feof(file))
	{
	    const unsigned int bytes_read = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, file);
	    SHA256_Update(&sha, buffer, bytes_read);
	}
	unsigned char hash[SHA256_DIGEST_LENGTH];
	SHA256_Final(hash, &sha);
	std::cout << file_list[i].name << " -> ";
	for(unsigned int b = 0; b < SHA256_DIGEST_LENGTH; b++)
	{
	    std::cout << std::hex << (unsigned int)hash[b];
	    file_list[i].checksum[b] = hash[b];
	}
	std::cout << std::endl;
	fclose(file);
    }
    delete[] buffer;

    return write_database(directory, file_list);
}

std::vector<File> get_file_list(const std::string& directory)
{
    std::vector<File> file_list;
    DIR* dir = opendir(directory.c_str());
    if(dir == nullptr)
    {
	std::cout << "\'" << directory << "\' is not readable." << std::endl;
	return file_list;
    }

    struct stat st;
    struct dirent* entry = readdir(dir);
    while(entry != nullptr)
    {
	// only add the file to the list if it is not a directory
	lstat(entry->d_name, &st);
	if(!S_ISDIR(st.st_mode) && std::string(entry->d_name).compare(".corrcheckdb") != 0)
	    file_list.push_back(File(std::string(entry->d_name)));
	entry = readdir(dir);
    }
    closedir(dir);

    return file_list;
}

int write_database(const std::string& directory, const std::vector<File>& file_list)
{
    // write the file names and checksums out
    // format: <checksum> <null-terminated string of name>
    FILE* file = fopen(std::string(directory + "/.corrcheckdb").c_str(), "w");
    if(file == NULL) return FAILURE;

    for(unsigned int i = 0; i < file_list.size(); i++)
    {
	fwrite(file_list[i].checksum, sizeof(unsigned char), SHA256_DIGEST_LENGTH, file);
	fwrite(file_list[i].name.c_str(), sizeof(char), file_list[i].name.length() + 1, file);
    }
    fclose(file);

    return SUCCESS;
}
<|endoftext|>