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

#pragma warning(disable : 4996)

#ifdef _WIN32
    #include <windows.h>
    #include "CompleteInject/CompleteInject.h"
#endif

#include <cstdlib>
#include <stdexcept>
#include <string>
#include <vector>
#include <sstream>
#include <cstdio>
#include <stdint.h>

#pragma warning(push)
#pragma warning(disable:4512)//'boost::program_options::options_description' : assignment operator could not be generated
#include <boost/program_options/options_description.hpp>
#pragma warning(pop)
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>

#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/named_semaphore.hpp>

#include <DGLCommon/os.h>
#include <DGLCommon/wa.h>
#include <DGLCommon/ipc.h>

#ifdef __ANDROID__
#include <dlfcn.h>
#endif

#pragma warning(disable:4503)

#ifdef _WIN32
bool isProcess64Bit(HANDLE hProcess) {
    //get IsWow64Process function
    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
    LPFN_ISWOW64PROCESS fnIsWow64Process =
        fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
    BOOL isWow;

    //check if windows is 64-bit
    bool isWindows64bit = false;

#ifdef _WIN64
    //if we are a 64 bit app, windows is definitely 64 bit
    isWindows64bit = true;
#else
    //we are 32-bit application. Check if we are in Wow64 mode
    if (fnIsWow64Process && fnIsWow64Process(GetCurrentProcess(),&isWow) && isWow) {
        //if we are in Wow64 mode, windows is 64 bit
        isWindows64bit = true;
    }
#endif

    //check if process is 64 bit
    if (isWindows64bit && fnIsWow64Process && fnIsWow64Process(hProcess, &isWow) && !isWow) {
        //windows is 64 bit, process is not in Wow64 mode, so process is 64 bit. This implies usage of 64 bit wrapper
        return true;
    }
    return false;
}
#endif

struct IPCMessage {
    IPCMessage(uint32_t s):status(s) { message[0] = 0; };
    uint32_t status;
    char message[1000];
};

std::string getWrapperPath() {
#ifdef _WIN32
#ifdef _WIN64
    std::string ret = "DGLWrapper64\\DGLWrapper.dll";
#else
    std::string ret = "DGLWrapper\\DGLWrapper.dll";
#endif

    char fileName[MAX_PATH];
    if (!GetModuleFileName(NULL, fileName, MAX_PATH)) {
        return ret;
    }
    std::string tmp = fileName;
    size_t splitPoint=tmp.find_last_of("/\\");
    return tmp.substr(0, splitPoint) + "\\" + ret;
#elif __ANDROID__
    return "/data/local/tmp/libdglwrapper.so";
#else
    return "libdglwrapper.so";
#endif
}

std::string getCurrentDirectory() {
#ifndef _WIN32
    #define MAX_PATH PATH_MAX
#endif
     char path[MAX_PATH];

#ifdef _WIN32
     if (!GetCurrentDirectory(MAX_PATH, path)) {
#else
     if (!getcwd(path, MAX_PATH)) {
#endif
        throw std::runtime_error("GetCurrentDirectory failed");
     }
     return path;
}

namespace po = boost::program_options;
using namespace std;

int main(int argc, char** argv) {

    IPCMessage message(EXIT_SUCCESS);
    IPCMessage* ipcMessage = &message;

    try {

        po::options_description desc("Allowed options");
        desc.add_options()
            ("help,h", "produce help message")
            ("egl", "use egl mode");

        desc.add_options()
            ("port", po::value< vector<string> >(), "Debugger TCP port number.");

        po::options_description mandatory("Mandatory options");
        mandatory.add_options()
            ("execute", po::value< vector<string> >()->composing(), "command to execute. Use -- top supply additional args.");

        po::positional_options_description p;
        p.add("execute", -1);

        po::options_description all;
        all.add(desc).add(mandatory);

        po::variables_map vm;
        po::store(po::command_line_parser(argc, argv).
            options(all).positional(p).run(), vm);
        po::notify(vm);

        if (vm.count("help")) {
            std::ostringstream out;
            out << desc << "\n" << mandatory << "\n";
            throw std::runtime_error(out.str());
        }

        if (!vm.count("execute")) {
            std::ostringstream out;
            out << "Nothing to execute.\n" << desc << "\n" << mandatory << "\n";
            throw std::runtime_error(out.str());
        }

        std::string executable = vm["execute"].as< vector<string> >()[0];
        std::vector<std::string> arguments;
        std::string argumentString;
        for (size_t i = 0; i < vm["execute"].as< vector<string> >().size(); i++) {
            arguments.push_back(vm["execute"].as< vector<string> >()[i]);
            argumentString += (i > 0?" ":"") + arguments[i];
        }

        std::string wrapperPath = getWrapperPath();
        std::string path = getCurrentDirectory();

        Os::info("Executable: %s\nPath: %s\nArguments: %s\nWrapper: %s\n\n\n", executable.c_str(), path.c_str(), argumentString.c_str(), wrapperPath.c_str());

        boost::shared_ptr<DGLIPC> dglIPC = DGLIPC::Create();
        Os::setEnv("dgl_uuid", dglIPC->getUUID().c_str());

        if (vm.count("egl")) {
            dglIPC->setDebuggerMode(DGLIPC::DebuggerMode::EGL);
        }

        if (vm.count("port")) {
            std::istringstream portStr(vm["port"].as< vector<string> >()[0]);
            int port;
            portStr >> port;
            dglIPC->setDebuggerPort(port);
        }

#ifdef _WIN32
        //prepare some structures for CreateProcess output
        STARTUPINFOA startupInfo;
        memset(&startupInfo, 0, sizeof(startupInfo));
        startupInfo.cb = sizeof(startupInfo);
        PROCESS_INFORMATION processInformation;
        memset(&processInformation, 0, sizeof(processInformation));

        //try run process (suspended - will not run user thread)

        if (CreateProcessA(
            executable.c_str(),
            (LPSTR)argumentString.c_str(),
            NULL,
            NULL,
            FALSE,
            CREATE_SUSPENDED,
            NULL,
            path.c_str(),
            &startupInfo,
            &processInformation) == 0 ) {

                throw std::runtime_error("Cannot create process");
        }
#else
        pid_t pid = fork();
        if (pid == -1) {
            throw std::runtime_error("Cannot fork process");
        }
        if (pid == 0) {
            std::vector<std::vector<char> > argvs(arguments.size());
            std::vector<char*> argv(arguments.size());
            for (size_t i = 0; i < arguments.size(); i++) {
                std::copy(arguments[i].begin(), arguments[i].end(), std::back_inserter<std::vector<char> >(argvs[i]));
                argvs[i].push_back('\0');
                argv[i] = &argvs[i][0];
            }
            argv.push_back(NULL);

            Os::setEnv("LD_PRELOAD", wrapperPath.c_str());

#ifdef __ANDROID__
           {
               int addr = reinterpret_cast<char*>(&dlopen) - reinterpret_cast<char*>(&dlclose);
               std::ostringstream str; str << addr;
               Os::setEnv("dlopen_addr", str.str().c_str());
           }
           {
               int addr = reinterpret_cast<char*>(&dlsym) - reinterpret_cast<char*>(&dlclose);
               std::ostringstream str; str << addr;
               Os::setEnv("dlsym_addr", str.str().c_str());
           }
#endif

            execvp(executable.c_str(), &argv[0]);
            throw std::runtime_error("Cannot execute process");
        }
#endif

#ifdef _WIN32
#ifdef _WIN64
        if (!isProcess64Bit(processInformation.hProcess)) {
            throw std::runtime_error("Incompatible loader version: used 64bit, but process is not 64bit");
        }
#else
        if (isProcess64Bit(processInformation.hProcess)) {
            throw std::runtime_error("Incompatible loader version: used 32bit, but process is not 32bit");
        }
#endif

        //process is running, but is suspended (user thread not started, some DLLMain-s may be run by now)

        //inject thread with wrapper library loading code, run through DLLMain and InitializeThread() function

#ifdef WA_ARM_MALI_EMU_LOADERTHREAD_KEEP
        Inject(processInformation.hProcess, wrapperPath.c_str(), "LoaderThread");
        dglIPC->waitForRemoteThreadSemaphore();
#else
        HANDLE thread = Inject(processInformation.hProcess, wrapperPath.c_str(), "LoaderThread");
        //wait for loader thread to finish dll inject
        WaitForSingleObject(thread, INFINITE);
#endif

        //resume process - now user thread is running
        //whole OpenGL should be wrapped by now

        if (ResumeThread(processInformation.hThread) == -1) {
            throw std::runtime_error("Cannot resume process");
        }
#endif

    } catch (const std::exception& e) {

        ipcMessage->status = EXIT_FAILURE;

#ifdef _WIN32
        //generic, GetLastError() aware error printer

        if ( DWORD lastError = GetLastError()) {

            char* errorText;
            FormatMessageA(
                FORMAT_MESSAGE_FROM_SYSTEM
                |FORMAT_MESSAGE_ALLOCATE_BUFFER
                |FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                GetLastError(),
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPSTR)&errorText,
                0,
                NULL);

            _snprintf(ipcMessage->message, 1000, "%s: %s\n", e.what(), errorText);

            LocalFree(errorText);

        } else {
            _snprintf(ipcMessage->message, 1000, "%s\n", e.what());
        }
#else
        if (errno) {
            snprintf(ipcMessage->message, 1000, "%s: %s\n", e.what(), strerror(errno));
        } else {
            snprintf(ipcMessage->message, 1000, "%s\n", e.what());
        }
#endif
    }

    Os::info("%s", ipcMessage->message);

    std::string shmemName = Os::getEnv("dgl_loader_shmem");
    if (shmemName.length()) {
        boost::interprocess::shared_memory_object shobj(boost::interprocess::open_only, shmemName.c_str(), boost::interprocess::read_write);
        boost::interprocess::mapped_region region(shobj, boost::interprocess::read_write);
        std::memset(region.get_address(), 0, region.get_size());
        memcpy(region.get_address(), ipcMessage, sizeof(IPCMessage));
    }

    std::string semaphore = Os::getEnv("dgl_loader_semaphore");
    if (semaphore.length()) {
        boost::interprocess::named_semaphore sem(boost::interprocess::open_only, semaphore.c_str());
        sem.post();
    }

    return ipcMessage->status;
}
<commit_msg>Do not fork() in dglloader in Android.<commit_after>/* Copyright (C) 2013 Slawomir Cygan <slawomir.cygan@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma warning(disable : 4996)

#ifdef _WIN32
    #include <windows.h>
    #include "CompleteInject/CompleteInject.h"
#endif

#include <cstdlib>
#include <stdexcept>
#include <string>
#include <vector>
#include <sstream>
#include <cstdio>
#include <stdint.h>

#pragma warning(push)
#pragma warning(disable:4512)//'boost::program_options::options_description' : assignment operator could not be generated
#include <boost/program_options/options_description.hpp>
#pragma warning(pop)
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>

#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/sync/named_semaphore.hpp>

#include <DGLCommon/os.h>
#include <DGLCommon/wa.h>
#include <DGLCommon/ipc.h>

#ifdef __ANDROID__
#include <dlfcn.h>
#endif

#pragma warning(disable:4503)

#ifdef _WIN32
bool isProcess64Bit(HANDLE hProcess) {
    //get IsWow64Process function
    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
    LPFN_ISWOW64PROCESS fnIsWow64Process =
        fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
    BOOL isWow;

    //check if windows is 64-bit
    bool isWindows64bit = false;

#ifdef _WIN64
    //if we are a 64 bit app, windows is definitely 64 bit
    isWindows64bit = true;
#else
    //we are 32-bit application. Check if we are in Wow64 mode
    if (fnIsWow64Process && fnIsWow64Process(GetCurrentProcess(),&isWow) && isWow) {
        //if we are in Wow64 mode, windows is 64 bit
        isWindows64bit = true;
    }
#endif

    //check if process is 64 bit
    if (isWindows64bit && fnIsWow64Process && fnIsWow64Process(hProcess, &isWow) && !isWow) {
        //windows is 64 bit, process is not in Wow64 mode, so process is 64 bit. This implies usage of 64 bit wrapper
        return true;
    }
    return false;
}
#endif

struct IPCMessage {
    IPCMessage(uint32_t s):status(s) { message[0] = 0; };
    uint32_t status;
    char message[1000];
};

std::string getWrapperPath() {
#ifdef _WIN32
#ifdef _WIN64
    std::string ret = "DGLWrapper64\\DGLWrapper.dll";
#else
    std::string ret = "DGLWrapper\\DGLWrapper.dll";
#endif

    char fileName[MAX_PATH];
    if (!GetModuleFileName(NULL, fileName, MAX_PATH)) {
        return ret;
    }
    std::string tmp = fileName;
    size_t splitPoint=tmp.find_last_of("/\\");
    return tmp.substr(0, splitPoint) + "\\" + ret;
#elif __ANDROID__
    return "/data/local/tmp/libdglwrapper.so";
#else
    return "libdglwrapper.so";
#endif
}

std::string getCurrentDirectory() {
#ifndef _WIN32
    #define MAX_PATH PATH_MAX
#endif
     char path[MAX_PATH];

#ifdef _WIN32
     if (!GetCurrentDirectory(MAX_PATH, path)) {
#else
     if (!getcwd(path, MAX_PATH)) {
#endif
        throw std::runtime_error("GetCurrentDirectory failed");
     }
     return path;
}

namespace po = boost::program_options;
using namespace std;

int main(int argc, char** argv) {

    IPCMessage message(EXIT_SUCCESS);
    IPCMessage* ipcMessage = &message;

    try {

        po::options_description desc("Allowed options");
        desc.add_options()
            ("help,h", "produce help message")
            ("egl", "use egl mode");

        desc.add_options()
            ("port", po::value< vector<string> >(), "Debugger TCP port number.");

        po::options_description mandatory("Mandatory options");
        mandatory.add_options()
            ("execute", po::value< vector<string> >()->composing(), "command to execute. Use -- top supply additional args.");

        po::positional_options_description p;
        p.add("execute", -1);

        po::options_description all;
        all.add(desc).add(mandatory);

        po::variables_map vm;
        po::store(po::command_line_parser(argc, argv).
            options(all).positional(p).run(), vm);
        po::notify(vm);

        if (vm.count("help")) {
            std::ostringstream out;
            out << desc << "\n" << mandatory << "\n";
            throw std::runtime_error(out.str());
        }

        if (!vm.count("execute")) {
            std::ostringstream out;
            out << "Nothing to execute.\n" << desc << "\n" << mandatory << "\n";
            throw std::runtime_error(out.str());
        }

        std::string executable = vm["execute"].as< vector<string> >()[0];
        std::vector<std::string> arguments;
        std::string argumentString;
        for (size_t i = 0; i < vm["execute"].as< vector<string> >().size(); i++) {
            arguments.push_back(vm["execute"].as< vector<string> >()[i]);
            argumentString += (i > 0?" ":"") + arguments[i];
        }

        std::string wrapperPath = getWrapperPath();
        std::string path = getCurrentDirectory();

        Os::info("Executable: %s\nPath: %s\nArguments: %s\nWrapper: %s\n\n\n", executable.c_str(), path.c_str(), argumentString.c_str(), wrapperPath.c_str());

        boost::shared_ptr<DGLIPC> dglIPC = DGLIPC::Create();
        Os::setEnv("dgl_uuid", dglIPC->getUUID().c_str());

        if (vm.count("egl")) {
            dglIPC->setDebuggerMode(DGLIPC::DebuggerMode::EGL);
        }

        if (vm.count("port")) {
            std::istringstream portStr(vm["port"].as< vector<string> >()[0]);
            int port;
            portStr >> port;
            dglIPC->setDebuggerPort(port);
        }

#ifdef _WIN32
        //prepare some structures for CreateProcess output
        STARTUPINFOA startupInfo;
        memset(&startupInfo, 0, sizeof(startupInfo));
        startupInfo.cb = sizeof(startupInfo);
        PROCESS_INFORMATION processInformation;
        memset(&processInformation, 0, sizeof(processInformation));

        //try run process (suspended - will not run user thread)

        if (CreateProcessA(
            executable.c_str(),
            (LPSTR)argumentString.c_str(),
            NULL,
            NULL,
            FALSE,
            CREATE_SUSPENDED,
            NULL,
            path.c_str(),
            &startupInfo,
            &processInformation) == 0 ) {

                throw std::runtime_error("Cannot create process");
        }
#else

#ifndef __ANDROID__
        pid_t pid = fork();
        if (pid == -1) {
            throw std::runtime_error("Cannot fork process");
        }
#else
        // on Android loader process is not forker - just replaced by debugee
        pid_t pid = 0;
#endif
        if (pid == 0) {
            std::vector<std::vector<char> > argvs(arguments.size());
            std::vector<char*> argv(arguments.size());
            for (size_t i = 0; i < arguments.size(); i++) {
                std::copy(arguments[i].begin(), arguments[i].end(), std::back_inserter<std::vector<char> >(argvs[i]));
                argvs[i].push_back('\0');
                argv[i] = &argvs[i][0];
            }
            argv.push_back(NULL);

            Os::setEnv("LD_PRELOAD", wrapperPath.c_str());

#ifdef __ANDROID__
           {
               int addr = reinterpret_cast<char*>(&dlopen) - reinterpret_cast<char*>(&dlclose);
               std::ostringstream str; str << addr;
               Os::setEnv("dlopen_addr", str.str().c_str());
           }
           {
               int addr = reinterpret_cast<char*>(&dlsym) - reinterpret_cast<char*>(&dlclose);
               std::ostringstream str; str << addr;
               Os::setEnv("dlsym_addr", str.str().c_str());
           }
#endif

            execvp(executable.c_str(), &argv[0]);
            throw std::runtime_error("Cannot execute process");
        }
#endif

#ifdef _WIN32
#ifdef _WIN64
        if (!isProcess64Bit(processInformation.hProcess)) {
            throw std::runtime_error("Incompatible loader version: used 64bit, but process is not 64bit");
        }
#else
        if (isProcess64Bit(processInformation.hProcess)) {
            throw std::runtime_error("Incompatible loader version: used 32bit, but process is not 32bit");
        }
#endif

        //process is running, but is suspended (user thread not started, some DLLMain-s may be run by now)

        //inject thread with wrapper library loading code, run through DLLMain and InitializeThread() function

#ifdef WA_ARM_MALI_EMU_LOADERTHREAD_KEEP
        Inject(processInformation.hProcess, wrapperPath.c_str(), "LoaderThread");
        dglIPC->waitForRemoteThreadSemaphore();
#else
        HANDLE thread = Inject(processInformation.hProcess, wrapperPath.c_str(), "LoaderThread");
        //wait for loader thread to finish dll inject
        WaitForSingleObject(thread, INFINITE);
#endif

        //resume process - now user thread is running
        //whole OpenGL should be wrapped by now

        if (ResumeThread(processInformation.hThread) == -1) {
            throw std::runtime_error("Cannot resume process");
        }
#endif

    } catch (const std::exception& e) {

        ipcMessage->status = EXIT_FAILURE;

#ifdef _WIN32
        //generic, GetLastError() aware error printer

        if ( DWORD lastError = GetLastError()) {

            char* errorText;
            FormatMessageA(
                FORMAT_MESSAGE_FROM_SYSTEM
                |FORMAT_MESSAGE_ALLOCATE_BUFFER
                |FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                GetLastError(),
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPSTR)&errorText,
                0,
                NULL);

            _snprintf(ipcMessage->message, 1000, "%s: %s\n", e.what(), errorText);

            LocalFree(errorText);

        } else {
            _snprintf(ipcMessage->message, 1000, "%s\n", e.what());
        }
#else
        if (errno) {
            snprintf(ipcMessage->message, 1000, "%s: %s\n", e.what(), strerror(errno));
        } else {
            snprintf(ipcMessage->message, 1000, "%s\n", e.what());
        }
#endif
    }

    Os::info("%s", ipcMessage->message);

    std::string shmemName = Os::getEnv("dgl_loader_shmem");
    if (shmemName.length()) {
        boost::interprocess::shared_memory_object shobj(boost::interprocess::open_only, shmemName.c_str(), boost::interprocess::read_write);
        boost::interprocess::mapped_region region(shobj, boost::interprocess::read_write);
        std::memset(region.get_address(), 0, region.get_size());
        memcpy(region.get_address(), ipcMessage, sizeof(IPCMessage));
    }

    std::string semaphore = Os::getEnv("dgl_loader_semaphore");
    if (semaphore.length()) {
        boost::interprocess::named_semaphore sem(boost::interprocess::open_only, semaphore.c_str());
        sem.post();
    }

    return ipcMessage->status;
}
<|endoftext|>


<commit_before>#include <AlpinoCorpus/DbCorpusReader.hh>
#include <AlpinoCorpus/Error.hh>

#include <QString>
#include <sstream>
#include <stdexcept>
#include <string>
#include <typeinfo>

namespace db = DbXml;

namespace {
    QString toQString(std::string const &s)
    {
        return QString::fromUtf8(s.c_str());
    }
}

namespace alpinocorpus {

/* begin() */
DbCorpusReader::DbIter::DbIter(db::XmlContainer &container)
{
    try {
        r = container.getAllDocuments( db::DBXML_LAZY_DOCS
                                     | db::DBXML_WELL_FORMED_ONLY
                                     );
    } catch (db::XmlException const &e) {
        throw alpinocorpus::Error(e.what());
    }
}

/* end() */
DbCorpusReader::DbIter::DbIter(db::XmlManager &mgr)
 : r(mgr.createResults())   // builds empty XmlResults
{
}

/* operator* */
QString DbCorpusReader::DbIter::current() const
{
    db::XmlDocument doc;
    const_cast<db::XmlResults &>(r).peek(doc);
    return toQString(doc.getName());
}

/* operator== */
bool DbCorpusReader::DbIter::equals(IterImpl const *that) const
{
    try {
        // The const_casts are needed because hasNext() is not const.
        // XXX should be safe.
        DbIter *other = const_cast<DbIter*>(dynamic_cast<DbIter const *>(that));
        DbIter &self  = const_cast<DbIter&>(*this);
        if (!self.r.hasNext() && !other->r.hasNext())
            return true;        // both at end()
        return self.r == other->r;
    } catch (std::bad_cast const &e) {
        return false;
    }
}

/* operator++ */
void DbCorpusReader::DbIter::next()
{
    try {
        db::XmlDocument doc;
        r.next(doc);
    } catch (db::XmlException const &e) {
        throw alpinocorpus::Error(e.what());
    }
}

DbCorpusReader::DbCorpusReader(QString const &qpath)
 : mgr(), container()
{
    std::string path(qpath.toLocal8Bit().data());

    try {
        db::XmlContainerConfig config;
        config.setReadOnly(true);
        container = mgr.openContainer(path, config);
        setName(toQString(container.getName()));
    } catch (db::XmlException const &e) {
        throw OpenError(qpath, QString::fromUtf8(e.what()));
    }
}

DbCorpusReader::~DbCorpusReader()
{
}

CorpusReader::EntryIterator DbCorpusReader::getBegin() const
{
    return EntryIterator(new DbIter(container));
}

CorpusReader::EntryIterator DbCorpusReader::getEnd() const
{
    return EntryIterator(new DbIter(mgr));
}

QString DbCorpusReader::readEntry(QString const &filename) const
{
    std::string name(filename.toUtf8().data());

    try {
        db::XmlDocument doc(container.getDocument(name, db::DBXML_LAZY_DOCS));
        std::string content;
        return toQString(doc.getContent(content));

    } catch (db::XmlException const &e) {
        std::ostringstream msg;
        msg << "entry \""                  << name
            << "\" cannot be read from \"" << container.getName()
            << "\" ("                      << e.what()
            << ")";
        throw Error(msg.str());
    }
}

}   // namespace alpinocorpus
<commit_msg>Document DbCorpusReader<commit_after>/*
 * Oracle Berkeley DB XML-based treebank reader.
 * Written by Lars Buitinck.
 *
 * The basic format is explained in the header. An additional notes:
 *  - We use DBML_WELL_FORMED_ONLY to prevent having to read the DTD.
 *    This only works because the DTD does not define entities.
 */

#include <AlpinoCorpus/DbCorpusReader.hh>
#include <AlpinoCorpus/Error.hh>

#include <QString>
#include <sstream>
#include <stdexcept>
#include <string>
#include <typeinfo>

namespace db = DbXml;

namespace {
    QString toQString(std::string const &s)
    {
        return QString::fromUtf8(s.c_str());
    }
}

namespace alpinocorpus {

/* begin() */
DbCorpusReader::DbIter::DbIter(db::XmlContainer &container)
{
    try {
        r = container.getAllDocuments( db::DBXML_LAZY_DOCS
                                     | db::DBXML_WELL_FORMED_ONLY
                                     );
    } catch (db::XmlException const &e) {
        throw alpinocorpus::Error(e.what());
    }
}

/* end() */
DbCorpusReader::DbIter::DbIter(db::XmlManager &mgr)
 : r(mgr.createResults())   // builds empty XmlResults
{
}

/* operator* */
QString DbCorpusReader::DbIter::current() const
{
    db::XmlDocument doc;
    const_cast<db::XmlResults &>(r).peek(doc);
    return toQString(doc.getName());
}

/* operator== */
bool DbCorpusReader::DbIter::equals(IterImpl const *that) const
{
    try {
        // The const_casts are needed because hasNext() is not const.
        // XXX should be safe.
        DbIter *other = const_cast<DbIter*>(dynamic_cast<DbIter const *>(that));
        DbIter &self  = const_cast<DbIter&>(*this);
        if (!self.r.hasNext() && !other->r.hasNext())
            return true;        // both at end()
        return self.r == other->r;
    } catch (std::bad_cast const &e) {
        return false;
    }
}

/* operator++ */
void DbCorpusReader::DbIter::next()
{
    try {
        db::XmlDocument doc;
        r.next(doc);
    } catch (db::XmlException const &e) {
        throw alpinocorpus::Error(e.what());
    }
}

DbCorpusReader::DbCorpusReader(QString const &qpath)
 : mgr(), container()
{
    std::string path(qpath.toLocal8Bit().data());

    try {
        db::XmlContainerConfig config;
        config.setReadOnly(true);
        container = mgr.openContainer(path, config);
        setName(toQString(container.getName()));
    } catch (db::XmlException const &e) {
        throw OpenError(qpath, QString::fromUtf8(e.what()));
    }
}

DbCorpusReader::~DbCorpusReader()
{
}

CorpusReader::EntryIterator DbCorpusReader::getBegin() const
{
    return EntryIterator(new DbIter(container));
}

CorpusReader::EntryIterator DbCorpusReader::getEnd() const
{
    return EntryIterator(new DbIter(mgr));
}

QString DbCorpusReader::readEntry(QString const &filename) const
{
    std::string name(filename.toUtf8().data());

    try {
        db::XmlDocument doc(container.getDocument(name, db::DBXML_LAZY_DOCS));
        std::string content;
        return toQString(doc.getContent(content));

    } catch (db::XmlException const &e) {
        std::ostringstream msg;
        msg << "entry \""                  << name
            << "\" cannot be read from \"" << container.getName()
            << "\" ("                      << e.what()
            << ")";
        throw Error(msg.str());
    }
}

}   // namespace alpinocorpus
<|endoftext|>


<commit_before>// Copyright (c) 2017 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "netpp_internal.h"
#include "buffer.h"
#include "primitive.h"
#include "address.h"
#include "socket_service.h"

namespace netpp {

struct AcceptOperation : public BaseOperation {
  BaseSocket& peer;
  Address& peer_addr;
  AcceptHandler handler{};

  AcceptOperation(int e, BaseSocket& s, Address& addr, const AcceptHandler& h)
    : BaseOperation(OPER_ACCEPT, e), peer(s), peer_addr(addr), handler(h) {
  }

  AcceptOperation(int e, BaseSocket& s, Address& addr, AcceptHandler&& h)
    : BaseOperation(OPER_ACCEPT, e)
    , peer(s), peer_addr(addr), handler(std::move(h)) {
  }
};

struct ConnectOperation : public BaseOperation {
  ConnectHandler handler{};

  ConnectOperation(int e, const ConnectHandler& h)
    : BaseOperation(OPER_CONNECT, e), handler(h) {
  }

  ConnectOperation(int e, ConnectHandler&& h)
    : BaseOperation(OPER_CONNECT, e), handler(std::move(h)) {
  }
};

struct ReadOperation : public BaseOperation {
  const MutableBuffer& mbuf;
  ReadHandler handler{};

  ReadOperation(int e, const MutableBuffer& buf, const ReadHandler& h)
    : BaseOperation(OPER_READ, e), mbuf(buf), handler(h) {
  }

  ReadOperation(int e, const MutableBuffer& buf, ReadHandler&& h)
    : BaseOperation(OPER_READ, e), mbuf(buf), handler(std::move(h)) {
  }
};

struct WriteOperation : public BaseOperation {
  const ConstBuffer& cbuf;
  WriteHandler handler{};

  WriteOperation(int e, const ConstBuffer& buf, const ReadHandler& h)
    : BaseOperation(OPER_WRITE, e), cbuf(buf), handler(h) {
  }

  WriteOperation(int e, const ConstBuffer& buf, ReadHandler&& h)
    : BaseOperation(OPER_WRITE, e), cbuf(buf), handler(std::move(h)) {
  }
};

struct ReadFromOperation : public BaseOperation {
  const MutableBuffer& mbuf;
  const Address& peer_addr;
  ReadHandler handler{};

  ReadFromOperation(int e,
      const MutableBuffer& buf, const Address& addr, const ReadHandler& h)
    : BaseOperation(OPER_READFROM, e), mbuf(buf), peer_addr(addr), handler(h) {
  }

  ReadFromOperation(int e,
      const MutableBuffer& buf, const Address& addr, ReadHandler&& h)
    : BaseOperation(OPER_READFROM, e)
    , mbuf(buf), peer_addr(addr), handler(std::move(h)) {
  }
};

struct WriteToOperation : public BaseOperation {
  const ConstBuffer& cbuf;
  const Address& peer_addr;
  WriteHandler handler{};

  WriteToOperation(int e,
      const ConstBuffer& buf, const Address& addr, const WriteHandler& h)
    : BaseOperation(OPER_WRITETO, e), cbuf(buf), peer_addr(addr), handler(h) {
  }

  WriteToOperation(int e,
      const ConstBuffer& buf, const Address& addr, WriteHandler&& h)
    : BaseOperation(OPER_WRITETO, e)
    , cbuf(buf), peer_addr(addr), handler(std::move(h)) {
  }
};

bool SocketService::add_operation(int sockfd, BaseOperation* oper) {
  if (operations_.find(sockfd) == operations_.end())
    operations_[sockfd] = OperationDict();

  auto event = oper->get_events();
  if (operations_[sockfd].find(event) == operations_[sockfd].end()) {
    pollfds_.push_back(PollFd(sockfd, event));
    operations_[sockfd][event] = oper;
    return true;
  }

  return false;
}

bool SocketService::set_non_blocking(
    socket_t sockfd, bool mode, std::error_code& ec) {
  return socket::set_non_blocking(sockfd, mode, ec);
}

int SocketService::set_option(socket_t sockfd, int level, int optname,
      const void* optval, std::size_t optlen, std::error_code& ec) {
  return socket::set_option(sockfd, level, optname, optval, optlen, ec);
}

int SocketService::get_option(socket_t sockfd, int level, int optname,
      void* optval, std::size_t* optlen, std::error_code& ec) {
  return socket::get_option(sockfd, level, optname, optval, optlen, ec);
}

socket_t SocketService::open(
    int family, int socket_type, int protocol, std::error_code& ec) {
  return socket::open(family, socket_type, protocol, ec);
}

void SocketService::close(socket_t sockfd, std::error_code& ec) {
  socket::close(sockfd, ec);
}

void SocketService::shutdown(socket_t sockfd, int how, std::error_code& ec) {
  socket::shutdown(sockfd, how, ec);
}

void SocketService::bind(
    socket_t sockfd, const Address& addr, std::error_code& ec) {
  socket::bind(sockfd, addr.get_address(), ec);
}

void SocketService::listen(socket_t sockfd, std::error_code& ec) {
  socket::listen(sockfd, ec);
}

socket_t SocketService::accept(socket_t sockfd,
    Address* peer_addr, bool non_blocking, std::error_code& ec) {
  return socket::sync_accept(sockfd,
      peer_addr ? peer_addr->get_address() : nullptr, non_blocking, ec);
}

void SocketService::async_accept(socket_t sockfd,
    BaseSocket& peer, Address& peer_addr, const AcceptHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new AcceptOperation(POLLIN, peer, peer_addr, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_accept(socket_t sockfd,
    BaseSocket& peer, Address& peer_addr, AcceptHandler&& handler) {
  // sockfd should be non-blocking
  auto* oper = new AcceptOperation(POLLIN, peer, peer_addr, std::move(handler));
  add_operation(sockfd, oper);
}

void SocketService::connect(
    socket_t sockfd, const Address& addr, std::error_code& ec) {
  socket::sync_connect(sockfd, addr.get_address(), ec);
}

void SocketService::async_connect(
    socket_t sockfd, const Address& addr, const ConnectHandler& handler) {
  // sockfd should be non-blocking
  std::error_code ec;
  socket::connect(sockfd, addr.get_address(), ec);
  if (!ec) {
    handler(ec);
  }
  else {
    if (ec.value() != error::IN_PROGRESS && ec.value() != error::WOULD_BLOCK) {
      handler(ec);
    }
    else {
      auto* oper = new ConnectOperation(POLLIN, handler);
      add_operation(sockfd, oper);
    }
  }
}

void SocketService::async_connect(
    socket_t sockfd, const Address& addr, ConnectHandler&& handler) {
  // sockfd should be non-blocking
  std::error_code ec;
  socket::connect(sockfd, addr.get_address(), ec);
  if (!ec) {
    handler(ec);
  }
  else {
    if (ec.value() != error::IN_PROGRESS && ec.value() != error::WOULD_BLOCK) {
      handler(ec);
    }
    else {
      auto* oper = new ConnectOperation(POLLIN, std::move(handler));
      add_operation(sockfd, oper);
    }
  }
}

std::size_t SocketService::read(socket_t sockfd,
    const MutableBuffer& buf, bool non_blocking, std::error_code& ec) {
  auto all_empty = buf.size() == 0;
  return socket::sync_read(sockfd,
      buf.size(), buf.data(), non_blocking, all_empty, ec);
}

std::size_t SocketService::read(socket_t sockfd,
    const NullBuffer&, bool non_blocking, std::error_code& ec) {
  return socket::poll_read(sockfd, non_blocking, -1, ec);
}

void SocketService::async_read(
    socket_t sockfd, const MutableBuffer& buf, const ReadHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new ReadOperation(POLLIN, buf, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_read(
    socket_t sockfd, const MutableBuffer& buf, ReadHandler&& handler) {
  // sockfd should be non-blocking
  auto* oper = new ReadOperation(POLLIN, buf, std::move(handler));
  add_operation(sockfd, oper);
}

std::size_t SocketService::write(socket_t sockfd,
    const ConstBuffer& buf, bool non_blocking, std::error_code& ec) {
  auto all_empty = buf.size() == 0;
  return socket::sync_write(sockfd,
      buf.data(), buf.size(), non_blocking, all_empty, ec);
}

std::size_t SocketService::write(socket_t sockfd,
      const NullBuffer&, bool non_blocking, std::error_code& ec) {
  return socket::poll_write(sockfd, non_blocking, -1, ec);
}

void SocketService::async_write(
    socket_t sockfd, const ConstBuffer& buf, const WriteHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new WriteOperation(POLLOUT, buf, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_write(
    socket_t sockfd, const ConstBuffer& buf, WriteHandler&& handler) {
  // sockfd should be non-blocking
  auto* oper = new WriteOperation(POLLOUT, buf, handler);
  add_operation(sockfd, oper);
}

std::size_t SocketService::read_from(socket_t sockfd, const MutableBuffer& buf,
    Address& peer_addr, bool non_blocking, std::error_code& ec) {
  return socket::sync_read_from(sockfd,
      buf.size(), buf.data(), peer_addr.get_address(), non_blocking, ec);
}

std::size_t SocketService::read_from(socket_t sockfd,
      const NullBuffer&, Address&, bool non_blocking, std::error_code& ec) {
  socket::poll_read(sockfd, non_blocking, -1, ec);
  return 0;
}

void SocketService::async_read_from(socket_t sockfd,
    const MutableBuffer& buf, Address& peer_addr, const ReadHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new ReadFromOperation(POLLIN, buf, peer_addr, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_read_from(socket_t sockfd,
    const MutableBuffer& buf, Address& peer_addr, ReadHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new ReadFromOperation(
      POLLIN, buf, peer_addr, std::move(handler));
  add_operation(sockfd, oper);
}

std::size_t SocketService::write_to(socket_t sockfd, const ConstBuffer& buf,
    const Address& peer_addr, bool non_blocking, std::error_code& ec) {
  return socket::sync_write_to(sockfd,
      buf.data(), buf.size(), peer_addr.get_address(), non_blocking, ec);
}

std::size_t SocketService::write_to(socket_t sockfd,
    const NullBuffer&, const Address&, bool non_blocking, std::error_code& ec) {
  socket::poll_write(sockfd, non_blocking, -1, ec);
  return 0;
}

void SocketService::async_write_to(socket_t sockfd, const ConstBuffer& buf,
    const Address& peer_addr, const WriteHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new WriteToOperation(POLLOUT, buf, peer_addr, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_write_to(socket_t sockfd,
    const ConstBuffer& buf, const Address& peer_addr, WriteHandler&& handler) {
  // sockfd should be non-blocking
  auto* oper = new WriteToOperation(
      POLLOUT, buf, peer_addr, std::move(handler));
  add_operation(sockfd, oper);
}

void SocketService::run(void) {
  while (running_) {
    auto n = netpp::poll(&pollfds_[0], pollfds_.size(), kPollTimeout);
    if (n <= 0)
      continue;

    for (auto i = 0; i < n; ++i) {
      // TODO:
    }
  }
}

void SocketService::stop(void) {
  running_ = false;
}

}
<commit_msg>:construction: chore(netpp): updated the poll of service<commit_after>// Copyright (c) 2017 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "netpp_internal.h"
#include "buffer.h"
#include "primitive.h"
#include "address.h"
#include "socket_service.h"

namespace netpp {

struct AcceptOperation : public BaseOperation {
  BaseSocket& peer;
  Address& peer_addr;
  AcceptHandler handler{};

  AcceptOperation(int e, BaseSocket& s, Address& addr, const AcceptHandler& h)
    : BaseOperation(OPER_ACCEPT, e), peer(s), peer_addr(addr), handler(h) {
  }

  AcceptOperation(int e, BaseSocket& s, Address& addr, AcceptHandler&& h)
    : BaseOperation(OPER_ACCEPT, e)
    , peer(s), peer_addr(addr), handler(std::move(h)) {
  }
};

struct ConnectOperation : public BaseOperation {
  ConnectHandler handler{};

  ConnectOperation(int e, const ConnectHandler& h)
    : BaseOperation(OPER_CONNECT, e), handler(h) {
  }

  ConnectOperation(int e, ConnectHandler&& h)
    : BaseOperation(OPER_CONNECT, e), handler(std::move(h)) {
  }
};

struct ReadOperation : public BaseOperation {
  const MutableBuffer& mbuf;
  ReadHandler handler{};

  ReadOperation(int e, const MutableBuffer& buf, const ReadHandler& h)
    : BaseOperation(OPER_READ, e), mbuf(buf), handler(h) {
  }

  ReadOperation(int e, const MutableBuffer& buf, ReadHandler&& h)
    : BaseOperation(OPER_READ, e), mbuf(buf), handler(std::move(h)) {
  }
};

struct WriteOperation : public BaseOperation {
  const ConstBuffer& cbuf;
  WriteHandler handler{};

  WriteOperation(int e, const ConstBuffer& buf, const ReadHandler& h)
    : BaseOperation(OPER_WRITE, e), cbuf(buf), handler(h) {
  }

  WriteOperation(int e, const ConstBuffer& buf, ReadHandler&& h)
    : BaseOperation(OPER_WRITE, e), cbuf(buf), handler(std::move(h)) {
  }
};

struct ReadFromOperation : public BaseOperation {
  const MutableBuffer& mbuf;
  const Address& peer_addr;
  ReadHandler handler{};

  ReadFromOperation(int e,
      const MutableBuffer& buf, const Address& addr, const ReadHandler& h)
    : BaseOperation(OPER_READFROM, e), mbuf(buf), peer_addr(addr), handler(h) {
  }

  ReadFromOperation(int e,
      const MutableBuffer& buf, const Address& addr, ReadHandler&& h)
    : BaseOperation(OPER_READFROM, e)
    , mbuf(buf), peer_addr(addr), handler(std::move(h)) {
  }
};

struct WriteToOperation : public BaseOperation {
  const ConstBuffer& cbuf;
  const Address& peer_addr;
  WriteHandler handler{};

  WriteToOperation(int e,
      const ConstBuffer& buf, const Address& addr, const WriteHandler& h)
    : BaseOperation(OPER_WRITETO, e), cbuf(buf), peer_addr(addr), handler(h) {
  }

  WriteToOperation(int e,
      const ConstBuffer& buf, const Address& addr, WriteHandler&& h)
    : BaseOperation(OPER_WRITETO, e)
    , cbuf(buf), peer_addr(addr), handler(std::move(h)) {
  }
};

bool SocketService::add_operation(int sockfd, BaseOperation* oper) {
  if (operations_.find(sockfd) == operations_.end())
    operations_[sockfd] = OperationDict();

  auto event = oper->get_events();
  if (operations_[sockfd].find(event) == operations_[sockfd].end()) {
    pollfds_.push_back(PollFd(sockfd, event));
    operations_[sockfd][event] = oper;
    return true;
  }

  return false;
}

bool SocketService::set_non_blocking(
    socket_t sockfd, bool mode, std::error_code& ec) {
  return socket::set_non_blocking(sockfd, mode, ec);
}

int SocketService::set_option(socket_t sockfd, int level, int optname,
      const void* optval, std::size_t optlen, std::error_code& ec) {
  return socket::set_option(sockfd, level, optname, optval, optlen, ec);
}

int SocketService::get_option(socket_t sockfd, int level, int optname,
      void* optval, std::size_t* optlen, std::error_code& ec) {
  return socket::get_option(sockfd, level, optname, optval, optlen, ec);
}

socket_t SocketService::open(
    int family, int socket_type, int protocol, std::error_code& ec) {
  return socket::open(family, socket_type, protocol, ec);
}

void SocketService::close(socket_t sockfd, std::error_code& ec) {
  socket::close(sockfd, ec);
}

void SocketService::shutdown(socket_t sockfd, int how, std::error_code& ec) {
  socket::shutdown(sockfd, how, ec);
}

void SocketService::bind(
    socket_t sockfd, const Address& addr, std::error_code& ec) {
  socket::bind(sockfd, addr.get_address(), ec);
}

void SocketService::listen(socket_t sockfd, std::error_code& ec) {
  socket::listen(sockfd, ec);
}

socket_t SocketService::accept(socket_t sockfd,
    Address* peer_addr, bool non_blocking, std::error_code& ec) {
  return socket::sync_accept(sockfd,
      peer_addr ? peer_addr->get_address() : nullptr, non_blocking, ec);
}

void SocketService::async_accept(socket_t sockfd,
    BaseSocket& peer, Address& peer_addr, const AcceptHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new AcceptOperation(POLLIN, peer, peer_addr, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_accept(socket_t sockfd,
    BaseSocket& peer, Address& peer_addr, AcceptHandler&& handler) {
  // sockfd should be non-blocking
  auto* oper = new AcceptOperation(POLLIN, peer, peer_addr, std::move(handler));
  add_operation(sockfd, oper);
}

void SocketService::connect(
    socket_t sockfd, const Address& addr, std::error_code& ec) {
  socket::sync_connect(sockfd, addr.get_address(), ec);
}

void SocketService::async_connect(
    socket_t sockfd, const Address& addr, const ConnectHandler& handler) {
  // sockfd should be non-blocking
  std::error_code ec;
  socket::connect(sockfd, addr.get_address(), ec);
  if (!ec) {
    handler(ec);
  }
  else {
    if (ec.value() != error::IN_PROGRESS && ec.value() != error::WOULD_BLOCK) {
      handler(ec);
    }
    else {
      auto* oper = new ConnectOperation(POLLIN, handler);
      add_operation(sockfd, oper);
    }
  }
}

void SocketService::async_connect(
    socket_t sockfd, const Address& addr, ConnectHandler&& handler) {
  // sockfd should be non-blocking
  std::error_code ec;
  socket::connect(sockfd, addr.get_address(), ec);
  if (!ec) {
    handler(ec);
  }
  else {
    if (ec.value() != error::IN_PROGRESS && ec.value() != error::WOULD_BLOCK) {
      handler(ec);
    }
    else {
      auto* oper = new ConnectOperation(POLLIN, std::move(handler));
      add_operation(sockfd, oper);
    }
  }
}

std::size_t SocketService::read(socket_t sockfd,
    const MutableBuffer& buf, bool non_blocking, std::error_code& ec) {
  auto all_empty = buf.size() == 0;
  return socket::sync_read(sockfd,
      buf.size(), buf.data(), non_blocking, all_empty, ec);
}

std::size_t SocketService::read(socket_t sockfd,
    const NullBuffer&, bool non_blocking, std::error_code& ec) {
  return socket::poll_read(sockfd, non_blocking, -1, ec);
}

void SocketService::async_read(
    socket_t sockfd, const MutableBuffer& buf, const ReadHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new ReadOperation(POLLIN, buf, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_read(
    socket_t sockfd, const MutableBuffer& buf, ReadHandler&& handler) {
  // sockfd should be non-blocking
  auto* oper = new ReadOperation(POLLIN, buf, std::move(handler));
  add_operation(sockfd, oper);
}

std::size_t SocketService::write(socket_t sockfd,
    const ConstBuffer& buf, bool non_blocking, std::error_code& ec) {
  auto all_empty = buf.size() == 0;
  return socket::sync_write(sockfd,
      buf.data(), buf.size(), non_blocking, all_empty, ec);
}

std::size_t SocketService::write(socket_t sockfd,
      const NullBuffer&, bool non_blocking, std::error_code& ec) {
  return socket::poll_write(sockfd, non_blocking, -1, ec);
}

void SocketService::async_write(
    socket_t sockfd, const ConstBuffer& buf, const WriteHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new WriteOperation(POLLOUT, buf, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_write(
    socket_t sockfd, const ConstBuffer& buf, WriteHandler&& handler) {
  // sockfd should be non-blocking
  auto* oper = new WriteOperation(POLLOUT, buf, handler);
  add_operation(sockfd, oper);
}

std::size_t SocketService::read_from(socket_t sockfd, const MutableBuffer& buf,
    Address& peer_addr, bool non_blocking, std::error_code& ec) {
  return socket::sync_read_from(sockfd,
      buf.size(), buf.data(), peer_addr.get_address(), non_blocking, ec);
}

std::size_t SocketService::read_from(socket_t sockfd,
      const NullBuffer&, Address&, bool non_blocking, std::error_code& ec) {
  socket::poll_read(sockfd, non_blocking, -1, ec);
  return 0;
}

void SocketService::async_read_from(socket_t sockfd,
    const MutableBuffer& buf, Address& peer_addr, const ReadHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new ReadFromOperation(POLLIN, buf, peer_addr, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_read_from(socket_t sockfd,
    const MutableBuffer& buf, Address& peer_addr, ReadHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new ReadFromOperation(
      POLLIN, buf, peer_addr, std::move(handler));
  add_operation(sockfd, oper);
}

std::size_t SocketService::write_to(socket_t sockfd, const ConstBuffer& buf,
    const Address& peer_addr, bool non_blocking, std::error_code& ec) {
  return socket::sync_write_to(sockfd,
      buf.data(), buf.size(), peer_addr.get_address(), non_blocking, ec);
}

std::size_t SocketService::write_to(socket_t sockfd,
    const NullBuffer&, const Address&, bool non_blocking, std::error_code& ec) {
  socket::poll_write(sockfd, non_blocking, -1, ec);
  return 0;
}

void SocketService::async_write_to(socket_t sockfd, const ConstBuffer& buf,
    const Address& peer_addr, const WriteHandler& handler) {
  // sockfd should be non-blocking
  auto* oper = new WriteToOperation(POLLOUT, buf, peer_addr, handler);
  add_operation(sockfd, oper);
}

void SocketService::async_write_to(socket_t sockfd,
    const ConstBuffer& buf, const Address& peer_addr, WriteHandler&& handler) {
  // sockfd should be non-blocking
  auto* oper = new WriteToOperation(
      POLLOUT, buf, peer_addr, std::move(handler));
  add_operation(sockfd, oper);
}

void SocketService::run(void) {
  while (running_) {
    auto n = netpp::poll(&*pollfds_.begin(), pollfds_.size(), kPollTimeout);
    if (n <= 0)
      continue;

    for (auto it = pollfds_.begin(); it != pollfds_.end();) {
      if (n-- <= 0)
        break;

      auto revents = it->revents;
      if (revents > 0) {
        auto oper_dict = operations_.find(it->fd);
        if (oper_dict != operations_.end()) {
          if ((revents & POLLHUP) && !(revents & POLLIN))  {
            // TODO: need solve close-functor
          }
          if (revents & (POLLERR | POLLNVAL)) {
            // TODO: need solve error-functor
          }
          if (revents & (POLLIN | POLLPRI | POLLHUP)) {
            // TODO: need solve read-functor
          }
          if (revents & POLLOUT) {
            // TODO: need solve write-functor
          }
        }
        pollfds_.erase(it++);
      }
      else {
        ++it;
      }
    }
  }
}

void SocketService::stop(void) {
  running_ = false;
}

}
<|endoftext|>


<commit_before>//
// Multicopter mission test.
//
// Author: Julian Oes <julian@oes.ch>

#include <mavsdk/mavsdk.h>
#include <mavsdk/plugins/action/action.h>
#include <mavsdk/plugins/telemetry/telemetry.h>
#include <iostream>
#include <string>
#include "autopilot_tester.h"

TEST_CASE("Takeoff and land (Plane)", "[plane]")
{
    AutopilotTester tester;
    tester.connect(connection_url);
    tester.wait_until_ready();
    tester.arm();
    tester.takeoff();
    tester.wait_until_hovering();
    tester.land();
    tester.wait_until_disarmed();
}
<commit_msg>Plane tester: Complement test Prepare wider plane test.<commit_after>//
// Plane mission test.
//
// Author: Lorenz Meier <lorenz@px4.io>, Julian Oes <julian@oes.ch>

#include <mavsdk/mavsdk.h>
#include <mavsdk/plugins/action/action.h>
#include <mavsdk/plugins/telemetry/telemetry.h>
#include <iostream>
#include <string>
#include "autopilot_tester.h"

TEST_CASE("Takeoff and land (plane)", "[plane]")
{
    AutopilotTester tester;
    tester.connect(connection_url);
    tester.wait_until_ready();
    tester.arm();
    tester.takeoff();
    tester.wait_until_hovering();
    tester.land();
    tester.wait_until_disarmed();
}

// TODO: Add land pattern

// TEST_CASE("Fly square missions (plane)", "[plane]")
// {
//     AutopilotTester tester;
//     tester.connect(connection_url);
//     tester.wait_until_ready();

//     SECTION("Mission including RTL (plane)") {
//         AutopilotTester::MissionOptions mission_options;
//         mission_options.leg_length_m = 250.0;
//         mission_options.relative_altitude_m = 40.0;
//         mission_options.rtl_at_end = true;
//         tester.prepare_square_mission(mission_options);
//         tester.arm();
//         tester.execute_mission();
//         tester.wait_until_disarmed();
//     }

//     SECTION("Mission with manual RTL (plane)") {
//         AutopilotTester::MissionOptions mission_options;
//         mission_options.leg_length_m = 250.0;
//         mission_options.relative_altitude_m = 40.0;
//         mission_options.rtl_at_end = false;
//         tester.prepare_square_mission(mission_options);
//         tester.arm();
//         tester.execute_mission();
//         tester.wait_until_hovering();
//         tester.execute_rtl();
//         tester.wait_until_disarmed();
//     }
// }
<|endoftext|>


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

#define CATCH_CONFIG_ENABLE_BENCHMARKING

#include "util/test_file.hpp"
#include "util/test_utils.hpp"

#include <realm/object-store/object_schema.hpp>
#include <realm/object-store/property.hpp>
#include <realm/object-store/results.hpp>
#include <realm/object-store/schema.hpp>
#include <realm/object-store/impl/realm_coordinator.hpp>

#include <realm/db.hpp>
#include <realm/query_engine.hpp>
#include <realm/query_expression.hpp>

using namespace realm;

TEST_CASE("Benchmark results", "[benchmark]") {
    InMemoryTestFile config;
    config.schema = Schema{
        {"object",
         {
             {"value", PropertyType::Int},
             {"bool", PropertyType::Bool},
             {"data prop", PropertyType::Data},
             {"link", PropertyType::Object | PropertyType::Nullable, "object 2"},
             {"array", PropertyType::Object | PropertyType::Array, "object 2"},
         }},
        {"object 2",
         {
             {"value", PropertyType::Int},
             {"link", PropertyType::Object | PropertyType::Nullable, "object"},
         }},
    };

    auto realm = Realm::get_shared_realm(config);
    auto table = realm->read_group().get_table("class_object");
    auto table2 = realm->read_group().get_table("class_object 2");
    Results r(realm, table);

    realm->begin_transaction();
    ObjKeys table_keys;
    ObjKeys table2_keys;
    table->create_objects(4, table_keys);
    table2->create_objects(4, table2_keys);
    ColKey col_link = table->get_column_key("link");
    ColKey col_value = table->get_column_key("value");
    ColKey col_link2 = table2->get_column_key("link");
    for (int i = 0; i < 4; ++i) {
        table->get_object(table_keys[i]).set_all((i + 2) % 4, bool(i % 2)).set(col_link, table2_keys[3 - i]);
        table2->get_object(table2_keys[i]).set_all((i + 1) % 4).set(col_link2, table_keys[i]);
    }
    realm->commit_transaction();
    /*
     | index | value | bool | link.value | link.link.value |
     |-------|-------|------|------------|-----------------|
     | 0     | 2     | 0    | 0          | 1               |
     | 1     | 3     | 1    | 3          | 0               |
     | 2     | 0     | 0    | 2          | 3               |
     | 3     | 1     | 1    | 1          | 2               |
     */

#define REQUIRE_ORDER(sort, ...)                                                                                \
    do {                                                                                \
        ObjKeys expected({__VA_ARGS__});                                                                             \
        auto results = sort;                                                                                \
        REQUIRE(results.size() == expected.size());                                                                  \
        for (size_t i = 0; i < expected.size(); ++i)                                                                 \
            REQUIRE(results.get(i).get_key() == expected[i]);                                                        \
    } while (0)

    SECTION("basics") {
        REQUIRE(r.filter(Query(table->where().less(col_value, 2))).size() == 2);
        BENCHMARK("basic filter") {
            return r.filter(Query(table->where().less(col_value, 2))).size();
        };

        REQUIRE_ORDER((r.sort({{"value", true}})), 2, 3, 0, 1);
        BENCHMARK("sort simple ints") {
            return r.sort({{"value", true}});
        };

        REQUIRE_ORDER((r.sort({{"bool", true}, {"value", true}})), 2, 0, 3, 1);
        BENCHMARK("sort over two properties") {
            return r.sort({{"bool", true}, {"value", true}});
        };

        REQUIRE_ORDER((r.sort({{"link.value", true}})), 0, 3, 2, 1);
        BENCHMARK("sort over link") {
            return r.sort({{"link.value", true}});
        };

        REQUIRE_ORDER((r.sort({{"link.link.value", true}})), 1, 0, 3, 2);
        BENCHMARK("sort over two links") {
            return r.sort({{"link.link.value", true}});
        };

        REQUIRE(r.distinct({{"value"}}).size() == 4);
        BENCHMARK("distinct ints") {
            return r.distinct({{"value"}});
        };

        REQUIRE(r.distinct({{"bool"}}).size() == 2);
        BENCHMARK("distinct bool") {
            return r.distinct({{"bool"}});
        };
    }

    SECTION("iteration") {
        const int additional_row_count = 10000;
        realm->begin_transaction();
        table->create_objects(additional_row_count, table_keys);
        for (int i = 0; i < additional_row_count; ++i)
            table->get_object(table_keys[i]).set_all((i + 2) % 4, bool(i % 2));
        realm->commit_transaction();

        BENCHMARK("Table forwards") {
            for (size_t i = 0, size = r.size(); i < size; ++i) {
                r.get<Obj>(i);
            }
        };

        BENCHMARK("Table reverse") {
            for (size_t i = 0, size = r.size(); i < size; ++i) {
                r.get<Obj>(size - i - 1);
            }
        };

        auto tv = r.snapshot();
        BENCHMARK("TableView forwards") {
            for (size_t i = 0, size = r.size(); i < size; ++i) {
                tv.get<Obj>(i);
            }
        };

        BENCHMARK("TableView reverse") {
            for (size_t i = 0, size = r.size(); i < size; ++i) {
                tv.get<Obj>(size - i - 1);
            }
        };
    }
}

TEST_CASE("Benchmark results notifier", "[benchmark]") {
    InMemoryTestFile config;

    SECTION("100 strongly connected tables") {
        std::vector<ObjectSchema> schema;
        for (int i = 0; i < 100; ++i) {
            ObjectSchema os;
            os.name = util::format("table %1", i);
            os.persisted_properties = {{"value", PropertyType::Int}};
            for (int j = 0; j < 100; ++j) {
                os.persisted_properties.push_back({util::format("column %1", j),
                                                   PropertyType::Object | PropertyType::Nullable,
                                                   util::format("table %1", j)});
            }
            schema.push_back(std::move(os));
        }
        config.schema = Schema{schema};
        auto realm = Realm::get_shared_realm(config);
        auto table_0 = realm->read_group().get_table("class_table 0");

        BENCHMARK("create notifier") {
            Results r(realm, table_0->where());
            r.evaluate_query_if_needed(true);
        };
    }

    config.automatic_change_notifications = false;
    static const int table_count = 6;
    static const int column_count = 50;
    static const int object_count = 50;

    auto make_schema = [](PropertyType link_type) {
        std::vector<ObjectSchema> schema;
        for (int i = 0; i < table_count; ++i) {
            ObjectSchema os;
            os.name = util::format("table %1", i);
            os.persisted_properties = {{"value", PropertyType::Int}};
            for (int j = 0; j < column_count; ++j) {
                os.persisted_properties.push_back(
                    {util::format("column %1", j), link_type, util::format("table %1", (i + 1) % table_count)});
            }
            schema.push_back(std::move(os));
        }
        return schema;
    };

    SECTION("chained tables using links") {
        std::vector<ObjectSchema> schema = make_schema(PropertyType::Object | PropertyType::Nullable);
        config.schema = Schema{schema};
        auto realm = Realm::get_shared_realm(config);

        auto& group = realm->read_group();
        std::vector<TableRef> tables;
        for (int i = 0; i < table_count; ++i) {
            tables.push_back(group.get_table(util::format("class_table %1", i)));
        }

        realm->begin_transaction();
        for (int i = 0; i < table_count; ++i) {
            for (int j = 0; j < object_count; ++j) {
                tables[i]->create_object();
            }
        }
        for (int i = 0; i < table_count; ++i) {
            auto target_table = tables[(i + 1) % table_count];
            for (int j = 0; j < object_count; ++j) {
                auto obj = tables[i]->get_object(j);
                for (int k = 0; k < column_count; ++k) {
                    obj.set(util::format("column %1", k), target_table->get_object((j + k) % object_count).get_key());
                }
            }
        }
        realm->commit_transaction();

        Results r(realm, tables[0]->where());
        auto token = r.add_notification_callback([](CollectionChangeSet) {});
        auto& coordinator = *_impl::RealmCoordinator::get_coordinator(config.path);
        coordinator.on_change();

        BENCHMARK("modify at depth 0", iteration) {
            realm->begin_transaction();
            for (int i = 0; i < object_count; ++i) {
                tables[0]->get_object(i).set_all(iteration);
            }
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 1", iteration) {
            realm->begin_transaction();
            tables[1]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 2", iteration) {
            realm->begin_transaction();
            tables[2]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 3", iteration) {
            realm->begin_transaction();
            tables[3]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };
    }

    SECTION("chained tables using lists") {
        std::vector<ObjectSchema> schema = make_schema(PropertyType::Object | PropertyType::Array);
        config.schema = Schema{schema};
        auto realm = Realm::get_shared_realm(config);

        auto& group = realm->read_group();
        std::vector<TableRef> tables;
        for (int i = 0; i < table_count; ++i) {
            tables.push_back(group.get_table(util::format("class_table %1", i)));
        }

        realm->begin_transaction();
        for (int i = 0; i < table_count; ++i) {
            for (int j = 0; j < object_count; ++j) {
                tables[i]->create_object();
            }
        }
        for (int i = 0; i < table_count; ++i) {
            auto target_table = tables[(i + 1) % table_count];
            for (int j = 0; j < object_count; ++j) {
                auto obj = tables[i]->get_object(j);
                for (int k = 0; k < column_count; ++k) {
                    obj.get_linklist(util::format("column %1", k))
                        .add(target_table->get_object((j + k) % object_count).get_key());
                }
            }
        }
        realm->commit_transaction();

        Results r(realm, tables[0]->where());
        auto token = r.add_notification_callback([](CollectionChangeSet) {});
        auto& coordinator = *_impl::RealmCoordinator::get_coordinator(config.path);
        coordinator.on_change();

        BENCHMARK("modify at depth 0", iteration) {
            realm->begin_transaction();
            for (int i = 0; i < object_count; ++i) {
                tables[0]->get_object(i).set_all(iteration);
            }
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 1", iteration) {
            realm->begin_transaction();
            tables[1]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 2", iteration) {
            realm->begin_transaction();
            tables[2]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 3", iteration) {
            realm->begin_transaction();
            tables[3]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };
    }
}
<commit_msg>Add basic benchmarks for aggregate operations<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2019 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////

#define CATCH_CONFIG_ENABLE_BENCHMARKING

#include "util/test_file.hpp"
#include "util/test_utils.hpp"

#include <realm/object-store/object_schema.hpp>
#include <realm/object-store/property.hpp>
#include <realm/object-store/results.hpp>
#include <realm/object-store/schema.hpp>
#include <realm/object-store/impl/realm_coordinator.hpp>

#include <realm/db.hpp>
#include <realm/query_engine.hpp>
#include <realm/query_expression.hpp>

using namespace realm;

TEST_CASE("Benchmark results", "[benchmark]") {
    InMemoryTestFile config;
    config.schema = Schema{
        {"object",
         {
             {"value", PropertyType::Int},
             {"bool", PropertyType::Bool},
             {"data prop", PropertyType::Data},
             {"link", PropertyType::Object | PropertyType::Nullable, "object 2"},
             {"array", PropertyType::Object | PropertyType::Array, "object 2"},
         }},
        {"object 2",
         {
             {"value", PropertyType::Int},
             {"link", PropertyType::Object | PropertyType::Nullable, "object"},
         }},
    };

    auto realm = Realm::get_shared_realm(config);
    auto table = realm->read_group().get_table("class_object");
    auto table2 = realm->read_group().get_table("class_object 2");
    Results r(realm, table);

    realm->begin_transaction();
    ObjKeys table_keys;
    ObjKeys table2_keys;
    table->create_objects(4, table_keys);
    table2->create_objects(4, table2_keys);
    ColKey col_link = table->get_column_key("link");
    ColKey col_value = table->get_column_key("value");
    ColKey col_link2 = table2->get_column_key("link");
    for (int i = 0; i < 4; ++i) {
        table->get_object(table_keys[i]).set_all((i + 2) % 4, bool(i % 2)).set(col_link, table2_keys[3 - i]);
        table2->get_object(table2_keys[i]).set_all((i + 1) % 4).set(col_link2, table_keys[i]);
    }
    realm->commit_transaction();
    /*
     | index | value | bool | link.value | link.link.value |
     |-------|-------|------|------------|-----------------|
     | 0     | 2     | 0    | 0          | 1               |
     | 1     | 3     | 1    | 3          | 0               |
     | 2     | 0     | 0    | 2          | 3               |
     | 3     | 1     | 1    | 1          | 2               |
     */

#define REQUIRE_ORDER(sort, ...)                                                                                \
    do {                                                                                \
        ObjKeys expected({__VA_ARGS__});                                                                             \
        auto results = sort;                                                                                \
        REQUIRE(results.size() == expected.size());                                                                  \
        for (size_t i = 0; i < expected.size(); ++i)                                                                 \
            REQUIRE(results.get(i).get_key() == expected[i]);                                                        \
    } while (0)

    SECTION("basics") {
        REQUIRE(r.filter(Query(table->where().less(col_value, 2))).size() == 2);
        BENCHMARK("basic filter") {
            return r.filter(Query(table->where().less(col_value, 2))).size();
        };

        REQUIRE_ORDER((r.sort({{"value", true}})), 2, 3, 0, 1);
        BENCHMARK("sort simple ints") {
            return r.sort({{"value", true}});
        };

        REQUIRE_ORDER((r.sort({{"bool", true}, {"value", true}})), 2, 0, 3, 1);
        BENCHMARK("sort over two properties") {
            return r.sort({{"bool", true}, {"value", true}});
        };

        REQUIRE_ORDER((r.sort({{"link.value", true}})), 0, 3, 2, 1);
        BENCHMARK("sort over link") {
            return r.sort({{"link.value", true}});
        };

        REQUIRE_ORDER((r.sort({{"link.link.value", true}})), 1, 0, 3, 2);
        BENCHMARK("sort over two links") {
            return r.sort({{"link.link.value", true}});
        };

        REQUIRE(r.distinct({{"value"}}).size() == 4);
        BENCHMARK("distinct ints") {
            return r.distinct({{"value"}});
        };

        REQUIRE(r.distinct({{"bool"}}).size() == 2);
        BENCHMARK("distinct bool") {
            return r.distinct({{"bool"}});
        };
    }

    SECTION("iteration") {
        const int additional_row_count = 10000;
        realm->begin_transaction();
        table->create_objects(additional_row_count, table_keys);
        for (int i = 0; i < additional_row_count; ++i)
            table->get_object(table_keys[i]).set_all((i + 2) % 4, bool(i % 2));
        realm->commit_transaction();

        BENCHMARK("Table forwards") {
            for (size_t i = 0, size = r.size(); i < size; ++i) {
                r.get<Obj>(i);
            }
        };

        BENCHMARK("Table reverse") {
            for (size_t i = 0, size = r.size(); i < size; ++i) {
                r.get<Obj>(size - i - 1);
            }
        };

        auto tv = r.snapshot();
        BENCHMARK("TableView forwards") {
            for (size_t i = 0, size = r.size(); i < size; ++i) {
                tv.get<Obj>(i);
            }
        };

        BENCHMARK("TableView reverse") {
            for (size_t i = 0, size = r.size(); i < size; ++i) {
                tv.get<Obj>(size - i - 1);
            }
        };
    }
}

TEST_CASE("Benchmark results notifier", "[benchmark]") {
    InMemoryTestFile config;

    SECTION("100 strongly connected tables") {
        std::vector<ObjectSchema> schema;
        for (int i = 0; i < 100; ++i) {
            ObjectSchema os;
            os.name = util::format("table %1", i);
            os.persisted_properties = {{"value", PropertyType::Int}};
            for (int j = 0; j < 100; ++j) {
                os.persisted_properties.push_back({util::format("column %1", j),
                                                   PropertyType::Object | PropertyType::Nullable,
                                                   util::format("table %1", j)});
            }
            schema.push_back(std::move(os));
        }
        config.schema = Schema{schema};
        auto realm = Realm::get_shared_realm(config);
        auto table_0 = realm->read_group().get_table("class_table 0");

        BENCHMARK("create notifier") {
            Results r(realm, table_0->where());
            r.evaluate_query_if_needed(true);
        };
    }

    config.automatic_change_notifications = false;
    static const int table_count = 6;
    static const int column_count = 50;
    static const int object_count = 50;

    auto make_schema = [](PropertyType link_type) {
        std::vector<ObjectSchema> schema;
        for (int i = 0; i < table_count; ++i) {
            ObjectSchema os;
            os.name = util::format("table %1", i);
            os.persisted_properties = {{"value", PropertyType::Int}};
            for (int j = 0; j < column_count; ++j) {
                os.persisted_properties.push_back(
                    {util::format("column %1", j), link_type, util::format("table %1", (i + 1) % table_count)});
            }
            schema.push_back(std::move(os));
        }
        return schema;
    };

    SECTION("chained tables using links") {
        std::vector<ObjectSchema> schema = make_schema(PropertyType::Object | PropertyType::Nullable);
        config.schema = Schema{schema};
        auto realm = Realm::get_shared_realm(config);

        auto& group = realm->read_group();
        std::vector<TableRef> tables;
        for (int i = 0; i < table_count; ++i) {
            tables.push_back(group.get_table(util::format("class_table %1", i)));
        }

        realm->begin_transaction();
        for (int i = 0; i < table_count; ++i) {
            for (int j = 0; j < object_count; ++j) {
                tables[i]->create_object();
            }
        }
        for (int i = 0; i < table_count; ++i) {
            auto target_table = tables[(i + 1) % table_count];
            for (int j = 0; j < object_count; ++j) {
                auto obj = tables[i]->get_object(j);
                for (int k = 0; k < column_count; ++k) {
                    obj.set(util::format("column %1", k), target_table->get_object((j + k) % object_count).get_key());
                }
            }
        }
        realm->commit_transaction();

        Results r(realm, tables[0]->where());
        auto token = r.add_notification_callback([](CollectionChangeSet) {});
        auto& coordinator = *_impl::RealmCoordinator::get_coordinator(config.path);
        coordinator.on_change();

        BENCHMARK("modify at depth 0", iteration) {
            realm->begin_transaction();
            for (int i = 0; i < object_count; ++i) {
                tables[0]->get_object(i).set_all(iteration);
            }
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 1", iteration) {
            realm->begin_transaction();
            tables[1]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 2", iteration) {
            realm->begin_transaction();
            tables[2]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 3", iteration) {
            realm->begin_transaction();
            tables[3]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };
    }

    SECTION("chained tables using lists") {
        std::vector<ObjectSchema> schema = make_schema(PropertyType::Object | PropertyType::Array);
        config.schema = Schema{schema};
        auto realm = Realm::get_shared_realm(config);

        auto& group = realm->read_group();
        std::vector<TableRef> tables;
        for (int i = 0; i < table_count; ++i) {
            tables.push_back(group.get_table(util::format("class_table %1", i)));
        }

        realm->begin_transaction();
        for (int i = 0; i < table_count; ++i) {
            for (int j = 0; j < object_count; ++j) {
                tables[i]->create_object();
            }
        }
        for (int i = 0; i < table_count; ++i) {
            auto target_table = tables[(i + 1) % table_count];
            for (int j = 0; j < object_count; ++j) {
                auto obj = tables[i]->get_object(j);
                for (int k = 0; k < column_count; ++k) {
                    obj.get_linklist(util::format("column %1", k))
                        .add(target_table->get_object((j + k) % object_count).get_key());
                }
            }
        }
        realm->commit_transaction();

        Results r(realm, tables[0]->where());
        auto token = r.add_notification_callback([](CollectionChangeSet) {});
        auto& coordinator = *_impl::RealmCoordinator::get_coordinator(config.path);
        coordinator.on_change();

        BENCHMARK("modify at depth 0", iteration) {
            realm->begin_transaction();
            for (int i = 0; i < object_count; ++i) {
                tables[0]->get_object(i).set_all(iteration);
            }
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 1", iteration) {
            realm->begin_transaction();
            tables[1]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 2", iteration) {
            realm->begin_transaction();
            tables[2]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };

        BENCHMARK("modify at depth 3", iteration) {
            realm->begin_transaction();
            tables[3]->get_object(0).set_all(iteration);
            realm->commit_transaction();
            coordinator.on_change();
        };
    }
}

TEST_CASE("aggregates") {
    InMemoryTestFile config;
    config.schema = Schema{
        {"object",
         {
             {"value", PropertyType::Int},
         }},
        {"link",
         {
             {"list", PropertyType::Object | PropertyType::Array, "object"},
             {"set", PropertyType::Object | PropertyType::Set, "object"},
             {"dictionary", PropertyType::Object | PropertyType::Dictionary | PropertyType::Nullable, "object"},
         }},
        {"primitive",
         {
             {"list", PropertyType::Int | PropertyType::Array},
             {"set", PropertyType::Int | PropertyType::Set},
             {"dictionary", PropertyType::Int | PropertyType::Dictionary},
         }},
    };

    auto realm = Realm::get_shared_realm(config);
    auto table = realm->read_group().get_table("class_object");
    auto link_table = realm->read_group().get_table("class_link");
    auto prim_table = realm->read_group().get_table("class_primitive");

    realm->begin_transaction();

    auto link_obj = link_table->create_object();
    auto obj_list = link_obj.get_linklist("list");
    auto obj_set = link_obj.get_linkset(link_obj.get_table()->get_column_key("set"));
    auto obj_dict = link_obj.get_dictionary("dictionary");

    auto prim_obj = prim_table->create_object();
    auto int_list = prim_obj.get_list<int64_t>("list");
    auto int_set = prim_obj.get_set<int64_t>("set");
    auto int_dict = prim_obj.get_dictionary("dictionary");

    const auto value_count = GENERATE(0, 100, 1'000'000);
    for (int i = 0; i < value_count; ++i) {
        auto key = table->create_object().set_all(1LL).get_key();
        obj_list.add(key);
        obj_set.insert(key);
        obj_dict.insert(std::to_string(i), key);
        int_list.add(1);
        int_set.insert(i);
        int_dict.insert(std::to_string(i), 1);
    }
    realm->commit_transaction();

    ColKey col = table->get_column_key("value");
    Results table_results(realm, table);
    Results query_results(realm, table->where());
    Results tv_results(realm, table->where());
    tv_results.evaluate_query_if_needed();

    BENCHMARK("table") {
        return table_results.sum(col);
    };
    BENCHMARK("query") {
        return query_results.sum(col);
    };
    BENCHMARK("tableview") {
        return tv_results.sum(col);
    };
    BENCHMARK("object list") {
        return List(realm, obj_list).sum(col);
    };
    BENCHMARK("object set") {
        return object_store::Set(realm, obj_set).sum(col);
    };
    BENCHMARK("object dictionary") {
        return object_store::Dictionary(realm, obj_dict).sum(col);
    };
    BENCHMARK("int list") {
        return List(realm, int_list).sum();
    };
    BENCHMARK("int set") {
        return object_store::Set(realm, int_set).sum();
    };
    BENCHMARK("int dictionary") {
        return object_store::Dictionary(realm, int_dict).sum();
    };
}
<|endoftext|>


<commit_before>/* **** **** **** **** **** **** **** **** *
 *
 *         _/        _/        _/
 *        _/_/_/    _/_/_/    _/_/_/
 *       _/    _/  _/    _/  _/    _/
 *      _/    _/  _/    _/  _/    _/
 *     _/_/_/    _/_/_/    _/_/_/
 *
 * bit by bit
 * bit_by_bit.hpp
 *
 * author: ISHII 2bit
 * mail:   2bit@backspace.tokyo
 *
 * **** **** **** **** **** **** **** **** */

#pragma once

#include "core/constants.hpp"
#include "core/type_utils.hpp"
#include "function/lambda_utils.hpp"
#include "container/container_utils.hpp"
#include "container/reusable_array.hpp"
#include "thread/thread_utils.hpp"
#include "math/math_utils.hpp"
#include "misc/stop_watch.hpp"
#include "misc/logger.hpp"
#include "misc/simple_test.hpp"<commit_msg>update headers<commit_after>/* **** **** **** **** **** **** **** **** *
 *
 *         _/        _/        _/
 *        _/_/_/    _/_/_/    _/_/_/
 *       _/    _/  _/    _/  _/    _/
 *      _/    _/  _/    _/  _/    _/
 *     _/_/_/    _/_/_/    _/_/_/
 *
 * bit by bit
 * bit_by_bit.hpp
 *
 * author: ISHII 2bit
 * mail:   2bit@backspace.tokyo
 *
 * **** **** **** **** **** **** **** **** */

#pragma once

#include "core/constants.hpp"
#include "core/type_utils.hpp"

#include "container/container_utils.hpp"
#include "container/container_delegation.hpp"
#include "container/iterator_utils.hpp"
#include "container/reusable_array.hpp"

#include "function/lambda_utils.hpp"

#include "thread/thread_utils.hpp"

#include "math/math_utils.hpp"

#include "misc/dirty.hpp"
#include "misc/stop_watch.hpp"
#include "misc/logger.hpp"
#include "misc/simple_test.hpp"

#include "thread/thread_utils.hpp"<|endoftext|>


<commit_before>#pragma once
// bitset_helpers.hpp: definitions of bitset operators and helpers
//
// Copyright (C) 2017 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

// number representation is sign-magnitude, sign is msb

namespace sw {
	namespace unum {
		template<size_t sign_magnitude>
		std::bitset<sign_magnitude> ones_complement(std::bitset<sign_magnitude> number) {
			std::bitset<sign_magnitude> complement;
			for (size_t i = 0; i < sign_magnitude; i++) {
				complement.set(i, !number[i]);
			}
			return complement;
		}

		template<size_t nbits>
		std::bitset<nbits> twos_complement(std::bitset<nbits> number) {
			std::bitset<nbits> complement;
			uint8_t _slice = 0;
			uint8_t carry = 1;
			for (size_t i = 0; i < nbits; i++) {
				_slice = uint8_t(!number[i]) + carry;
				carry = _slice >> 1;
				complement[i] = (0x1 & _slice);
			}
			return complement;
		}

		// DANGER: this depends on the implicit type conversion of number to a uint64_t to sign extent a 2's complement number system
		// if nbits > 64 then this code breaks.
		template<size_t nbits, class Type>
		std::bitset<nbits> convert_to_bitset(Type number) {
			std::bitset<nbits> _Bits;
			uint64_t mask = uint64_t(1);
			for (std::size_t i = 0; i < nbits; i++) {
				_Bits[i] = mask & number;
				mask <<= 1;
			}
			return _Bits;
		}

		template<size_t nbits>
		std::string to_binary(std::bitset<nbits> bits) {
			std::stringstream ss;
			int msb = nbits; // compilation warning work-around for nbits = 0
			for (int i = msb - 1; i >= 0; --i) {
				ss << (bits[std::size_t(i)] ? "1" : "0");
			}
			return ss.str();
		}

		template<size_t nbits>
		std::string to_hex(std::bitset<nbits> bits) {
			char str[nbits];   // plenty of room
			const char* hexits = "0123456789ABCDEF";
			unsigned int max = (nbits >> 2) + (nbits % 4 ? 2 : 1);
			for (unsigned int i = 0; i < max; i++) {
				unsigned int hexit = (bits[3] << 3) + (bits[2] << 2) + (bits[1] << 1) + bits[0];
				str[max - 1 - i] = hexits[hexit];
				bits >>= 4;
			}
			str[max] = 0;
			return std::string(str);
		}

		template<size_t sign_magnitude>
		std::string signed_magnitude_to_binary(std::bitset<sign_magnitude> bits) {
			std::stringstream ss;
			ss << (bits[sign_magnitude - 1] ? "n-" : "p-");
			if (sign_magnitude < 2) return ss.str();
			for (int i = sign_magnitude - 2; i >= 0; --i) {
				ss << (bits[i] ? "1" : "0");
			}
			return ss.str();
		}

		// return a new bitset with the sign flipped as compared to the input bitset
		template<size_t nbits>
		std::bitset<nbits> flip_sign_bit(std::bitset<nbits> number) {
			number.flip(nbits - 1);
			return number;
		}

	} // namespace unum

} // namespace sw

<commit_msg>Build: Fix compile errors due to missing header includes.<commit_after>#pragma once
// bitset_helpers.hpp: definitions of bitset operators and helpers
//
// Copyright (C) 2017 Stillwater Supercomputing, Inc.
//
// This file is part of the universal numbers project, which is released under an MIT Open Source license.

// number representation is sign-magnitude, sign is msb

#include <bitset>
#include <sstream>

namespace sw {
	namespace unum {
		template<size_t sign_magnitude>
		std::bitset<sign_magnitude> ones_complement(std::bitset<sign_magnitude> number) {
			std::bitset<sign_magnitude> complement;
			for (size_t i = 0; i < sign_magnitude; i++) {
				complement.set(i, !number[i]);
			}
			return complement;
		}

		template<size_t nbits>
		std::bitset<nbits> twos_complement(std::bitset<nbits> number) {
			std::bitset<nbits> complement;
			uint8_t _slice = 0;
			uint8_t carry = 1;
			for (size_t i = 0; i < nbits; i++) {
				_slice = uint8_t(!number[i]) + carry;
				carry = _slice >> 1;
				complement[i] = (0x1 & _slice);
			}
			return complement;
		}

		// DANGER: this depends on the implicit type conversion of number to a uint64_t to sign extent a 2's complement number system
		// if nbits > 64 then this code breaks.
		template<size_t nbits, class Type>
		std::bitset<nbits> convert_to_bitset(Type number) {
			std::bitset<nbits> _Bits;
			uint64_t mask = uint64_t(1);
			for (std::size_t i = 0; i < nbits; i++) {
				_Bits[i] = mask & number;
				mask <<= 1;
			}
			return _Bits;
		}

		template<size_t nbits>
		std::string to_binary(std::bitset<nbits> bits) {
			std::stringstream ss;
			int msb = nbits; // compilation warning work-around for nbits = 0
			for (int i = msb - 1; i >= 0; --i) {
				ss << (bits[std::size_t(i)] ? "1" : "0");
			}
			return ss.str();
		}

		template<size_t nbits>
		std::string to_hex(std::bitset<nbits> bits) {
			char str[nbits];   // plenty of room
			const char* hexits = "0123456789ABCDEF";
			unsigned int max = (nbits >> 2) + (nbits % 4 ? 2 : 1);
			for (unsigned int i = 0; i < max; i++) {
				unsigned int hexit = (bits[3] << 3) + (bits[2] << 2) + (bits[1] << 1) + bits[0];
				str[max - 1 - i] = hexits[hexit];
				bits >>= 4;
			}
			str[max] = 0;
			return std::string(str);
		}

		template<size_t sign_magnitude>
		std::string signed_magnitude_to_binary(std::bitset<sign_magnitude> bits) {
			std::stringstream ss;
			ss << (bits[sign_magnitude - 1] ? "n-" : "p-");
			if (sign_magnitude < 2) return ss.str();
			for (int i = sign_magnitude - 2; i >= 0; --i) {
				ss << (bits[i] ? "1" : "0");
			}
			return ss.str();
		}

		// return a new bitset with the sign flipped as compared to the input bitset
		template<size_t nbits>
		std::bitset<nbits> flip_sign_bit(std::bitset<nbits> number) {
			number.flip(nbits - 1);
			return number;
		}

	} // namespace unum

} // namespace sw

<|endoftext|>