<commit_before>/*
 * MIT License
 *
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <fcntl.h>
#include <string.h>
#include <list>
#include "SelectWrap.h"
#include "EventPoller.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/uv_errno.h"
#include "Util/TimeTicker.h"
#include "Thread/ThreadPool.h"
#include "Network/sockutil.h"

using namespace ZL::Util;
using namespace ZL::Thread;
using namespace ZL::Network;

#if defined(HAS_EPOLL)
    #include <sys/epoll.h>
    #define EPOLL_SIZE 1024
    #define toEpoll(event)    (((event) & Event_Read) ? EPOLLIN : 0) \
                            | (((event) & Event_Write) ? EPOLLOUT : 0) \
                            | (((event) & Event_Error) ? (EPOLLHUP | EPOLLERR) : 0) \
                            | (((event) & Event_LT) ?  0 : EPOLLET)
    #define toPoller(epoll_event) (((epoll_event) & EPOLLIN) ? Event_Read : 0) \
                                | (((epoll_event) & EPOLLOUT) ? Event_Write : 0) \
                                | (((epoll_event) & EPOLLHUP) ? Event_Error : 0) \
                                | (((epoll_event) & EPOLLERR) ? Event_Error : 0)
#endif //HAS_EPOLL

namespace ZL {
namespace Poller {

EventPoller::EventPoller(bool enableSelfRun) {
#if defined(HAS_EPOLL)
    _epoll_fd = epoll_create(EPOLL_SIZE);
    if (_epoll_fd == -1) {
        throw runtime_error(StrPrinter << "创建epoll文件描述符失败:" << get_uv_errmsg() << endl);
    }
#endif //HAS_EPOLL
    initPoll();
    if (enableSelfRun) {
        _loopThread = new thread(&EventPoller::runLoop, this);
        _mainThreadId = _loopThread->get_id();
    } else {
        _mainThreadId = this_thread::get_id();
    }
}

inline int EventPoller::sigalPipe(uint64_t type, uint64_t i64_size, uint64_t *buf) {
    uint64_t *pipeBuf = new uint64_t[2 + i64_size];
    pipeBuf[0] = type;
    pipeBuf[1] = i64_size;
    if (i64_size) {
        memcpy(pipeBuf + 2, buf, i64_size * sizeof(uint64_t));
    }
    auto ret = _pipe.write(pipeBuf, (2 + i64_size) * sizeof(uint64_t));
    delete[] pipeBuf;
    return ret;
}

void EventPoller::shutdown() {
    sigalPipe(Sig_Exit);
}

EventPoller::~EventPoller() {
    shutdown();

    if (_loopThread) {
        _loopThread->join();
        delete _loopThread;
        _loopThread = nullptr;
    }

    if (_epoll_fd != -1) {
        close(_epoll_fd);
        _epoll_fd = -1;
    }
    //退出前清理管道中的数据
    _mainThreadId = this_thread::get_id();
    handlePipeEvent();
    InfoL;
}

int EventPoller::addEvent(int fd, int event, const PollEventCB &cb) {
    TimeTicker();
    if (!cb) {
        WarnL << "PollEventCB 为空!";
        return -1;
    }
#if defined(HAS_EPOLL)
    lock_guard<mutex> lck(_mtx_event_map);
    struct epoll_event ev = {0};
    ev.events = toEpoll(event);
    ev.data.fd = fd;
    int ret = epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
    if (ret == 0) {
        _event_map.emplace(fd, cb);
    }
    return ret;
#else
    if (isMainThread()) {
        lock_guard<mutex> lck(_mtx_event_map);
        Poll_Record record;
        record.event = (Poll_Event)event;
        record.callBack = cb;
        _event_map.emplace(fd, record);
        return 0;
    }
    async([this, fd, event, cb]() {
        addEvent(fd, event, cb);
    });
    return 0;
#endif //HAS_EPOLL
}

int EventPoller::delEvent(int fd, const PollDelCB &delCb) {
    TimeTicker();
    if (!delCb) {
        const_cast<PollDelCB &>(delCb) = [](bool success) {};
    }
#if defined(HAS_EPOLL)
    int ret0 = epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, NULL);
    int ret1 = 0;
    {
        lock_guard<mutex> lck(_mtx_event_map);
        ret1 = _event_map.erase(fd);
    }
    bool success = ret0 == 0 && ret1 > 0;
    delCb(success);
    return success ? 0 : -1;
#else
    if (isMainThread()) {
        lock_guard<mutex> lck(_mtx_event_map);
        if (_event_map.erase(fd)) {
            delCb(true);
        }else {
            delCb(false);
        }
        return 0;
    }
    async([this, fd, delCb]() {
        delEvent(fd, delCb);
    });
    return 0;
#endif //HAS_EPOLL
}

int EventPoller::modifyEvent(int fd, int event) {
    TimeTicker();
    //TraceL<<fd<<" "<<event;
#if defined(HAS_EPOLL)
    struct epoll_event ev = {0};
    ev.events = toEpoll(event);
    ev.data.fd = fd;
    return epoll_ctl(_epoll_fd, EPOLL_CTL_MOD, fd, &ev);
#else
    if (isMainThread()) {
        lock_guard<mutex> lck(_mtx_event_map);
        auto it = _event_map.find(fd);
        if (it != _event_map.end()) {
            it->second.event = (Poll_Event)event;
        }
        return 0;
    }
    async([this, fd, event]() {
        modifyEvent(fd, event);
    });
    return 0;
#endif //HAS_EPOLL
}

void EventPoller::sync(const PollAsyncCB &syncCb) {
    TimeTicker();
    if (!syncCb) {
        return;
    }
    semaphore sem;
    async([&]() {
        syncCb();
        sem.post();
    });
    sem.wait();
}

void EventPoller::async(const PollAsyncCB &asyncCb) {
    TimeTicker();
    if (!asyncCb) {
        return;
    }
    if (_mainThreadId == this_thread::get_id()) {
        asyncCb();
        return;
    }
    std::shared_ptr<Ticker> pTicker(new Ticker(5, "wake up main thread", WarnL, true));
    auto lam = [asyncCb, pTicker]() {
        const_cast<std::shared_ptr<Ticker> &>(pTicker).reset();
        asyncCb();
    };
    uint64_t buf[1] = {(uint64_t) (new PollAsyncCB(lam))};
    sigalPipe(Sig_Async, 1, buf);
}

bool EventPoller::isMainThread() {
    return _mainThreadId == this_thread::get_id();
}

inline Sigal_Type EventPoller::_handlePipeEvent(uint64_t type, uint64_t i64_size, uint64_t *buf) {
    switch (type) {
        case Sig_Async: {
            PollAsyncCB **cb = (PollAsyncCB **) buf;
            try {
                (*cb)->operator()();
            }
            catch (std::exception &ex) {
                FatalL << ex.what();
            }
            delete *cb;
        }
            break;
        default:
            break;
    }
    return (Sigal_Type) type;
}

inline bool EventPoller::handlePipeEvent() {
    TimeTicker();
    int nread;
    char buf[1024];
    int err = 0;
    do {
        nread = _pipe.read(buf, sizeof(buf));
        if (nread > 0) {
            _pipeBuffer.append(buf, nread);
            continue;
        }
        err = get_uv_error();
    } while (err != UV_EAGAIN);

    bool ret = true;
    while (_pipeBuffer.size() >= 2 * sizeof(uint64_t)) {
        uint64_t type = *((uint64_t *) _pipeBuffer.data());
        uint64_t slinceSize = *((uint64_t *) (_pipeBuffer.data()) + 1);
        uint64_t slinceByte = (2 + slinceSize) * sizeof(uint64_t);
        if (slinceByte > _pipeBuffer.size()) {
            break;
        }
        uint64_t *ptr = (uint64_t *) (_pipeBuffer.data()) + 2;
        if (Sig_Exit == _handlePipeEvent(type, slinceSize, ptr)) {
            ret = false;
        }
        _pipeBuffer.erase(0, slinceByte);
    }
    return ret;
}

void EventPoller::initPoll() {
#if defined(HAS_EPOLL)
    if (addEvent(_pipe.readFD(), Event_Read | Event_Error, [](int event) {}) == -1) {
        FatalL << "epoll添加管道失败" << endl;
        std::runtime_error("epoll添加管道失败");
    }
#endif //HAS_EPOLL
}

void EventPoller::runLoop() {
    _mainThreadId = this_thread::get_id();
    ThreadPool::setPriority(ThreadPool::PRIORITY_HIGHEST);
#if defined(HAS_EPOLL)
    struct epoll_event events[EPOLL_SIZE];
    while (true) {
        int nfds = epoll_wait(_epoll_fd, events, EPOLL_SIZE, -1);
        TimeTicker();
        if (nfds == -1) {
            WarnL << "epoll_wait() interrupted:" << get_uv_errmsg();
            continue;
        }

        for (int i = 0; i < nfds; ++i) {
            struct epoll_event &ev = events[i];
            int fd = ev.data.fd;
            int event = toPoller(ev.events);
            if (fd == _pipe.readFD()) {
                //inner pipe event
                if (event & Event_Error) {
                    WarnL << "Poller 异常退出监听。";
                    return;
                }
                if (!handlePipeEvent()) {
                    InfoL << "Poller 退出监听。";
                    return;
                }
                continue;
            }
            // other event
            PollEventCB eventCb;
            {
                lock_guard<mutex> lck(_mtx_event_map);
                auto it = _event_map.find(fd);
                if (it == _event_map.end()) {
                    WarnL << "未找到Poll事件回调对象!";
                    epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, NULL);
                    continue;
                }
                eventCb = it->second;
            }
            eventCb(event);
        }
    }
#else
    int ret, maxFd;
    FdSet Set_read, Set_write, Set_err;
    list<unordered_map<int, Poll_Record>::value_type> listCB;
    while (true) {
        Set_read.fdZero();
        Set_write.fdZero();
        Set_err.fdZero();
        Set_read.fdSet(_pipe.readFD()); //监听管道可读事件
        maxFd = _pipe.readFD();
        {
            lock_guard<mutex> lck(_mtx_event_map);
            for (auto &pr : _event_map) {
                if (pr.first > maxFd) {
                    maxFd = pr.first;
                }
                if (pr.second.event & Event_Read) {
                    Set_read.fdSet(pr.first);//监听管道可读事件
                }
                if (pr.second.event & Event_Write) {
                    Set_write.fdSet(pr.first);//监听管道可写事件
                }
                if (pr.second.event & Event_Error) {
                    Set_err.fdSet(pr.first);//监听管道错误事件
                }
            }
        }
        ret = zl_select(maxFd + 1, &Set_read, &Set_write, &Set_err, NULL);
        if (ret < 1) {
            WarnL << "select() interrupted:" << get_uv_errmsg();
            continue;
        }

        if (Set_read.isSet(_pipe.readFD())) {
            //判断有否监听操作
            if (!handlePipeEvent()) {
                InfoL << "EventPoller exiting...";
                break;
            }
            if (ret == 1) {
                //没有其他事件
                continue;
            }
        }

        {
            lock_guard<mutex> lck(_mtx_event_map);
            for (auto &pr : _event_map) {
                int event = 0;
                if (Set_read.isSet(pr.first)) {
                    event |= Event_Read;
                }
                if (Set_write.isSet(pr.first)) {
                    event |= Event_Write;
                }
                if (Set_err.isSet(pr.first)) {
                    event |= Event_Error;
                }
                if (event != 0) {
                    pr.second.attach = event;
                    listCB.push_back(pr);
                }
            }
        }
        for (auto &pr : listCB) {
            pr.second();
        }
        listCB.clear();
    }
#endif //HAS_EPOLL
}

}  // namespace Poller
}  // namespace ZL

<commit_msg>修复非linux下编译问题<commit_after>/*
 * MIT License
 *
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <fcntl.h>
#include <string.h>
#include <list>
#include "SelectWrap.h"
#include "EventPoller.h"
#include "Util/util.h"
#include "Util/logger.h"
#include "Util/uv_errno.h"
#include "Util/TimeTicker.h"
#include "Thread/ThreadPool.h"
#include "Network/sockutil.h"

using namespace ZL::Util;
using namespace ZL::Thread;
using namespace ZL::Network;

#if defined(HAS_EPOLL)
    #include <sys/epoll.h>
    #define EPOLL_SIZE 1024
    #define toEpoll(event)    (((event) & Event_Read) ? EPOLLIN : 0) \
                            | (((event) & Event_Write) ? EPOLLOUT : 0) \
                            | (((event) & Event_Error) ? (EPOLLHUP | EPOLLERR) : 0) \
                            | (((event) & Event_LT) ?  0 : EPOLLET)
    #define toPoller(epoll_event) (((epoll_event) & EPOLLIN) ? Event_Read : 0) \
                                | (((epoll_event) & EPOLLOUT) ? Event_Write : 0) \
                                | (((epoll_event) & EPOLLHUP) ? Event_Error : 0) \
                                | (((epoll_event) & EPOLLERR) ? Event_Error : 0)
#endif //HAS_EPOLL

namespace ZL {
namespace Poller {

EventPoller::EventPoller(bool enableSelfRun) {
#if defined(HAS_EPOLL)
    _epoll_fd = epoll_create(EPOLL_SIZE);
    if (_epoll_fd == -1) {
        throw runtime_error(StrPrinter << "创建epoll文件描述符失败:" << get_uv_errmsg() << endl);
    }
#endif //HAS_EPOLL
    initPoll();
    if (enableSelfRun) {
        _loopThread = new thread(&EventPoller::runLoop, this);
        _mainThreadId = _loopThread->get_id();
    } else {
        _mainThreadId = this_thread::get_id();
    }
}

inline int EventPoller::sigalPipe(uint64_t type, uint64_t i64_size, uint64_t *buf) {
    uint64_t *pipeBuf = new uint64_t[2 + i64_size];
    pipeBuf[0] = type;
    pipeBuf[1] = i64_size;
    if (i64_size) {
        memcpy(pipeBuf + 2, buf, i64_size * sizeof(uint64_t));
    }
    auto ret = _pipe.write(pipeBuf, (2 + i64_size) * sizeof(uint64_t));
    delete[] pipeBuf;
    return ret;
}

void EventPoller::shutdown() {
    sigalPipe(Sig_Exit);
}

EventPoller::~EventPoller() {
    shutdown();

    if (_loopThread) {
        _loopThread->join();
        delete _loopThread;
        _loopThread = nullptr;
    }

#if defined(HAS_EPOLL)
    if (_epoll_fd != -1) {
        close(_epoll_fd);
        _epoll_fd = -1;
    }
#endif //defined(HAS_EPOLL)
    //退出前清理管道中的数据
    _mainThreadId = this_thread::get_id();
    handlePipeEvent();
    InfoL;
}

int EventPoller::addEvent(int fd, int event, const PollEventCB &cb) {
    TimeTicker();
    if (!cb) {
        WarnL << "PollEventCB 为空!";
        return -1;
    }
#if defined(HAS_EPOLL)
    lock_guard<mutex> lck(_mtx_event_map);
    struct epoll_event ev = {0};
    ev.events = toEpoll(event);
    ev.data.fd = fd;
    int ret = epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
    if (ret == 0) {
        _event_map.emplace(fd, cb);
    }
    return ret;
#else
    if (isMainThread()) {
        lock_guard<mutex> lck(_mtx_event_map);
        Poll_Record record;
        record.event = (Poll_Event)event;
        record.callBack = cb;
        _event_map.emplace(fd, record);
        return 0;
    }
    async([this, fd, event, cb]() {
        addEvent(fd, event, cb);
    });
    return 0;
#endif //HAS_EPOLL
}

int EventPoller::delEvent(int fd, const PollDelCB &delCb) {
    TimeTicker();
    if (!delCb) {
        const_cast<PollDelCB &>(delCb) = [](bool success) {};
    }
#if defined(HAS_EPOLL)
    int ret0 = epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, NULL);
    int ret1 = 0;
    {
        lock_guard<mutex> lck(_mtx_event_map);
        ret1 = _event_map.erase(fd);
    }
    bool success = ret0 == 0 && ret1 > 0;
    delCb(success);
    return success ? 0 : -1;
#else
    if (isMainThread()) {
        lock_guard<mutex> lck(_mtx_event_map);
        if (_event_map.erase(fd)) {
            delCb(true);
        }else {
            delCb(false);
        }
        return 0;
    }
    async([this, fd, delCb]() {
        delEvent(fd, delCb);
    });
    return 0;
#endif //HAS_EPOLL
}

int EventPoller::modifyEvent(int fd, int event) {
    TimeTicker();
    //TraceL<<fd<<" "<<event;
#if defined(HAS_EPOLL)
    struct epoll_event ev = {0};
    ev.events = toEpoll(event);
    ev.data.fd = fd;
    return epoll_ctl(_epoll_fd, EPOLL_CTL_MOD, fd, &ev);
#else
    if (isMainThread()) {
        lock_guard<mutex> lck(_mtx_event_map);
        auto it = _event_map.find(fd);
        if (it != _event_map.end()) {
            it->second.event = (Poll_Event)event;
        }
        return 0;
    }
    async([this, fd, event]() {
        modifyEvent(fd, event);
    });
    return 0;
#endif //HAS_EPOLL
}

void EventPoller::sync(const PollAsyncCB &syncCb) {
    TimeTicker();
    if (!syncCb) {
        return;
    }
    semaphore sem;
    async([&]() {
        syncCb();
        sem.post();
    });
    sem.wait();
}

void EventPoller::async(const PollAsyncCB &asyncCb) {
    TimeTicker();
    if (!asyncCb) {
        return;
    }
    if (_mainThreadId == this_thread::get_id()) {
        asyncCb();
        return;
    }
    std::shared_ptr<Ticker> pTicker(new Ticker(5, "wake up main thread", WarnL, true));
    auto lam = [asyncCb, pTicker]() {
        const_cast<std::shared_ptr<Ticker> &>(pTicker).reset();
        asyncCb();
    };
    uint64_t buf[1] = {(uint64_t) (new PollAsyncCB(lam))};
    sigalPipe(Sig_Async, 1, buf);
}

bool EventPoller::isMainThread() {
    return _mainThreadId == this_thread::get_id();
}

inline Sigal_Type EventPoller::_handlePipeEvent(uint64_t type, uint64_t i64_size, uint64_t *buf) {
    switch (type) {
        case Sig_Async: {
            PollAsyncCB **cb = (PollAsyncCB **) buf;
            try {
                (*cb)->operator()();
            }
            catch (std::exception &ex) {
                FatalL << ex.what();
            }
            delete *cb;
        }
            break;
        default:
            break;
    }
    return (Sigal_Type) type;
}

inline bool EventPoller::handlePipeEvent() {
    TimeTicker();
    int nread;
    char buf[1024];
    int err = 0;
    do {
        nread = _pipe.read(buf, sizeof(buf));
        if (nread > 0) {
            _pipeBuffer.append(buf, nread);
            continue;
        }
        err = get_uv_error();
    } while (err != UV_EAGAIN);

    bool ret = true;
    while (_pipeBuffer.size() >= 2 * sizeof(uint64_t)) {
        uint64_t type = *((uint64_t *) _pipeBuffer.data());
        uint64_t slinceSize = *((uint64_t *) (_pipeBuffer.data()) + 1);
        uint64_t slinceByte = (2 + slinceSize) * sizeof(uint64_t);
        if (slinceByte > _pipeBuffer.size()) {
            break;
        }
        uint64_t *ptr = (uint64_t *) (_pipeBuffer.data()) + 2;
        if (Sig_Exit == _handlePipeEvent(type, slinceSize, ptr)) {
            ret = false;
        }
        _pipeBuffer.erase(0, slinceByte);
    }
    return ret;
}

void EventPoller::initPoll() {
#if defined(HAS_EPOLL)
    if (addEvent(_pipe.readFD(), Event_Read | Event_Error, [](int event) {}) == -1) {
        FatalL << "epoll添加管道失败" << endl;
        std::runtime_error("epoll添加管道失败");
    }
#endif //HAS_EPOLL
}

void EventPoller::runLoop() {
    _mainThreadId = this_thread::get_id();
    ThreadPool::setPriority(ThreadPool::PRIORITY_HIGHEST);
#if defined(HAS_EPOLL)
    struct epoll_event events[EPOLL_SIZE];
    while (true) {
        int nfds = epoll_wait(_epoll_fd, events, EPOLL_SIZE, -1);
        TimeTicker();
        if (nfds == -1) {
            WarnL << "epoll_wait() interrupted:" << get_uv_errmsg();
            continue;
        }

        for (int i = 0; i < nfds; ++i) {
            struct epoll_event &ev = events[i];
            int fd = ev.data.fd;
            int event = toPoller(ev.events);
            if (fd == _pipe.readFD()) {
                //inner pipe event
                if (event & Event_Error) {
                    WarnL << "Poller 异常退出监听。";
                    return;
                }
                if (!handlePipeEvent()) {
                    InfoL << "Poller 退出监听。";
                    return;
                }
                continue;
            }
            // other event
            PollEventCB eventCb;
            {
                lock_guard<mutex> lck(_mtx_event_map);
                auto it = _event_map.find(fd);
                if (it == _event_map.end()) {
                    WarnL << "未找到Poll事件回调对象!";
                    epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, NULL);
                    continue;
                }
                eventCb = it->second;
            }
            eventCb(event);
        }
    }
#else
    int ret, maxFd;
    FdSet Set_read, Set_write, Set_err;
    list<unordered_map<int, Poll_Record>::value_type> listCB;
    while (true) {
        Set_read.fdZero();
        Set_write.fdZero();
        Set_err.fdZero();
        Set_read.fdSet(_pipe.readFD()); //监听管道可读事件
        maxFd = _pipe.readFD();
        {
            lock_guard<mutex> lck(_mtx_event_map);
            for (auto &pr : _event_map) {
                if (pr.first > maxFd) {
                    maxFd = pr.first;
                }
                if (pr.second.event & Event_Read) {
                    Set_read.fdSet(pr.first);//监听管道可读事件
                }
                if (pr.second.event & Event_Write) {
                    Set_write.fdSet(pr.first);//监听管道可写事件
                }
                if (pr.second.event & Event_Error) {
                    Set_err.fdSet(pr.first);//监听管道错误事件
                }
            }
        }
        ret = zl_select(maxFd + 1, &Set_read, &Set_write, &Set_err, NULL);
        if (ret < 1) {
            WarnL << "select() interrupted:" << get_uv_errmsg();
            continue;
        }

        if (Set_read.isSet(_pipe.readFD())) {
            //判断有否监听操作
            if (!handlePipeEvent()) {
                InfoL << "EventPoller exiting...";
                break;
            }
            if (ret == 1) {
                //没有其他事件
                continue;
            }
        }

        {
            lock_guard<mutex> lck(_mtx_event_map);
            for (auto &pr : _event_map) {
                int event = 0;
                if (Set_read.isSet(pr.first)) {
                    event |= Event_Read;
                }
                if (Set_write.isSet(pr.first)) {
                    event |= Event_Write;
                }
                if (Set_err.isSet(pr.first)) {
                    event |= Event_Error;
                }
                if (event != 0) {
                    pr.second.attach = event;
                    listCB.push_back(pr);
                }
            }
        }
        for (auto &pr : listCB) {
            pr.second();
        }
        listCB.clear();
    }
#endif //HAS_EPOLL
}

}  // namespace Poller
}  // namespace ZL

<|endoftext|>


<commit_before>#include <composite.hpp>

Composite::Composite() :
	Shape{},
	shapes_{}{}

Composite::Composite(std::string const& name) :
	Shape{name, Material{}},
	shapes_{}{}

Composite::~Composite(){}

void Composite::add(std::shared_ptr<Shape>& shape) {
	shapes_.insert(shapes_.begin(),std::pair<std::string,std::shared_ptr<Shape>>(shape->name(),shape));
}

void Composite::remove(std::string const& name) {
	shapes_.erase(name);
}

std::ostream& Composite::print(std::ostream& os) const {
	for(auto element : shapes_) {
		element.second->print(os);
	}
	return os;
}

std::map<std::string, std::shared_ptr<Shape>> Composite::get_children() {
	return shapes_;
}<commit_msg>compositie update<commit_after>#include <composite.hpp>

Composite::Composite() :
	Shape{},
	shapes_{}{}

Composite::Composite(std::string const& name) :
	Shape{name, Material{}},
	shapes_{}{}

Composite::~Composite(){}

void Composite::add(std::shared_ptr<Shape>& shape) {
	shapes_.insert(shapes_.begin(),std::pair<std::string,std::shared_ptr<Shape>>(shape->name(),shape));
}

void Composite::remove(std::string const& name) {
	shapes_.erase(name);
}

std::ostream& Composite::print(std::ostream& os) const {
	for(auto element: shapes_) {
		element.second->print(os);
	}
	return os;
}

std::map<std::string, std::shared_ptr<Shape>> Composite::get_children() {
	return shapes_;
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: rscclobj.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 13:53:38 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
/****************** I N C L U D E S **************************************/

// C and C++ Includes.

// Solar Definitionen
#include <tools/solar.h>

// Programmabhaengige Includes.
#ifndef _RSCCLOBJ_HXX
#include <rscclobj.hxx>
#endif
#ifndef _RSCTOP_HXX
#include <rsctop.hxx>
#endif

/****************** C O D E **********************************************/

/****************** R e f N o d e ****************************************/
/*************************************************************************
|*
|*    RefNode::RefNode()
|*
|*    Beschreibung
|*    Ersterstellung    MM 03.05.91
|*    Letzte Aenderung  MM 03.05.91
|*
*************************************************************************/
RefNode::RefNode( Atom nTyp ){
    pObjBiTree = 0;
    nTypNameId = nTyp;
}

/*************************************************************************
|*
|*    RefNode::GetId()
|*
|*    Beschreibung
|*    Ersterstellung    MM 29.10.91
|*    Letzte Aenderung  MM 29.10.91
|*
*************************************************************************/
sal_uInt32 RefNode::GetId() const
{
    return( nTypNameId );
}

/*************************************************************************
|*
|*    RefNode::PutObjNode()
|*
|*    Beschreibung      NAME.DOC
|*    Ersterstellung    MM 21.03.90
|*    Letzte Aenderung  MM 27.06.90
|*
*************************************************************************/
BOOL RefNode::PutObjNode( ObjNode * pPutObject ){
// insert a node in the b-tree pObjBiTree
// if the node with the same name is in pObjBiTree,
// return FALSE and no insert,

    if( pObjBiTree )
        return( pObjBiTree->Insert( pPutObject ) );

    pObjBiTree = pPutObject;
    return( TRUE );
}

/****************** O b j N o d e ****************************************/
/*************************************************************************
|*
|*    RefNode::GetObjNode()
|*
|*    Beschreibung      NAME.DOC
|*    Ersterstellung    MM 21.03.90
|*    Letzte Aenderung  MM 27.06.90
|*
*************************************************************************/
ObjNode * RefNode :: GetObjNode( const RscId & rRscId ){
// insert a node in the b-tree pObjBiTree
// if the node with the same name is in pObjBiTree,
// return NULL and no insert,
// if not return the pointer to the Object

    if( pObjBiTree )
        return( pObjBiTree->Search( rRscId ) );
    return( NULL );
}

/*************************************************************************
|*
|*    ObjNode::ObjNode()
|*
|*    Beschreibung
|*    Ersterstellung    MM 15.05.91
|*    Letzte Aenderung  MM 15.05.91
|*
*************************************************************************/
ObjNode::ObjNode( const RscId & rId, CLASS_DATA pData, ULONG lKey ){
    pRscObj  = pData;
    aRscId   = rId;
    lFileKey = lKey;
}

/*************************************************************************
|*
|*    ObjNode::DelObjNode()
|*
|*    Beschreibung
|*    Ersterstellung    MM 09.12.91
|*    Letzte Aenderung  MM 09.12.91
|*
*************************************************************************/
ObjNode * ObjNode::DelObjNode( RscTop * pClass, ULONG nFileKey ){
    ObjNode * pRetNode = this;

    if( Right() )
        pRight = ((ObjNode *)Right())->DelObjNode( pClass, nFileKey );
    if( Left() )
        pLeft = ((ObjNode *)Left())->DelObjNode( pClass, nFileKey );

    if( GetFileKey() == nFileKey ){
        if( GetRscObj() ){
            pClass->Destroy( RSCINST( pClass, GetRscObj() ) );
            rtl_freeMemory( GetRscObj() );
        }
        pRetNode = (ObjNode *)Right();
        if( pRetNode ){
            if( Left() )
                pRetNode->Insert( (ObjNode *)Left() );
        }
        else
            pRetNode = (ObjNode *)Left();
        delete this;
    }
    return pRetNode;
}

/*************************************************************************
|*
|*    ObjNode::GetId()
|*
|*    Beschreibung
|*    Ersterstellung    MM 29.10.91
|*    Letzte Aenderung  MM 29.10.91
|*
*************************************************************************/
sal_uInt32 ObjNode::GetId() const
{
    return( (sal_uInt32)(long)aRscId );
}

/*************************************************************************
|*
|*    ObjNode::IsConsistent()
|*
|*    Beschreibung
|*    Ersterstellung    MM 23.09.91
|*    Letzte Aenderung  MM 23.09.91
|*
*************************************************************************/
BOOL ObjNode::IsConsistent( RscInconsList * pList )
{
    BOOL bRet = TRUE;

    if( (long)aRscId > 0x7FFF || (long)aRscId < 1 )
    {
        bRet = FALSE;
        if( pList )
            pList->Insert( new RscInconsistent( aRscId, aRscId ) );
    }
    else
    {
        if( Left() )
        {
            if( !((ObjNode *)Left())->IsConsistent( pList ) )
                bRet = FALSE;
            if( ((ObjNode *)Left())->aRscId >= aRscId )
            {
                bRet = FALSE;
                if( pList )
                    pList->Insert(
                        new RscInconsistent( ((ObjNode *)Left())->GetRscId(),
                                             GetRscId() ) );
            }
        };
        if( Right() )
        {
            if( ((ObjNode *)Right())->aRscId <= aRscId )
            {
                bRet = FALSE;
                if( pList )
                    pList->Insert(
                        new RscInconsistent( GetRscId(),
                                             ((ObjNode *)Right())->GetRscId() ) );
            }
            if( !((ObjNode *)Right())->IsConsistent( pList ) )
                bRet = FALSE;
        };
    };

    return( bRet );
}
<commit_msg>INTEGRATION: CWS pchfix02 (1.4.46); FILE MERGED 2006/09/01 17:33:23 kaib 1.4.46.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: rscclobj.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 16:01:42 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_rsc.hxx"
/****************** I N C L U D E S **************************************/

// C and C++ Includes.

// Solar Definitionen
#include <tools/solar.h>

// Programmabhaengige Includes.
#ifndef _RSCCLOBJ_HXX
#include <rscclobj.hxx>
#endif
#ifndef _RSCTOP_HXX
#include <rsctop.hxx>
#endif

/****************** C O D E **********************************************/

/****************** R e f N o d e ****************************************/
/*************************************************************************
|*
|*    RefNode::RefNode()
|*
|*    Beschreibung
|*    Ersterstellung    MM 03.05.91
|*    Letzte Aenderung  MM 03.05.91
|*
*************************************************************************/
RefNode::RefNode( Atom nTyp ){
    pObjBiTree = 0;
    nTypNameId = nTyp;
}

/*************************************************************************
|*
|*    RefNode::GetId()
|*
|*    Beschreibung
|*    Ersterstellung    MM 29.10.91
|*    Letzte Aenderung  MM 29.10.91
|*
*************************************************************************/
sal_uInt32 RefNode::GetId() const
{
    return( nTypNameId );
}

/*************************************************************************
|*
|*    RefNode::PutObjNode()
|*
|*    Beschreibung      NAME.DOC
|*    Ersterstellung    MM 21.03.90
|*    Letzte Aenderung  MM 27.06.90
|*
*************************************************************************/
BOOL RefNode::PutObjNode( ObjNode * pPutObject ){
// insert a node in the b-tree pObjBiTree
// if the node with the same name is in pObjBiTree,
// return FALSE and no insert,

    if( pObjBiTree )
        return( pObjBiTree->Insert( pPutObject ) );

    pObjBiTree = pPutObject;
    return( TRUE );
}

/****************** O b j N o d e ****************************************/
/*************************************************************************
|*
|*    RefNode::GetObjNode()
|*
|*    Beschreibung      NAME.DOC
|*    Ersterstellung    MM 21.03.90
|*    Letzte Aenderung  MM 27.06.90
|*
*************************************************************************/
ObjNode * RefNode :: GetObjNode( const RscId & rRscId ){
// insert a node in the b-tree pObjBiTree
// if the node with the same name is in pObjBiTree,
// return NULL and no insert,
// if not return the pointer to the Object

    if( pObjBiTree )
        return( pObjBiTree->Search( rRscId ) );
    return( NULL );
}

/*************************************************************************
|*
|*    ObjNode::ObjNode()
|*
|*    Beschreibung
|*    Ersterstellung    MM 15.05.91
|*    Letzte Aenderung  MM 15.05.91
|*
*************************************************************************/
ObjNode::ObjNode( const RscId & rId, CLASS_DATA pData, ULONG lKey ){
    pRscObj  = pData;
    aRscId   = rId;
    lFileKey = lKey;
}

/*************************************************************************
|*
|*    ObjNode::DelObjNode()
|*
|*    Beschreibung
|*    Ersterstellung    MM 09.12.91
|*    Letzte Aenderung  MM 09.12.91
|*
*************************************************************************/
ObjNode * ObjNode::DelObjNode( RscTop * pClass, ULONG nFileKey ){
    ObjNode * pRetNode = this;

    if( Right() )
        pRight = ((ObjNode *)Right())->DelObjNode( pClass, nFileKey );
    if( Left() )
        pLeft = ((ObjNode *)Left())->DelObjNode( pClass, nFileKey );

    if( GetFileKey() == nFileKey ){
        if( GetRscObj() ){
            pClass->Destroy( RSCINST( pClass, GetRscObj() ) );
            rtl_freeMemory( GetRscObj() );
        }
        pRetNode = (ObjNode *)Right();
        if( pRetNode ){
            if( Left() )
                pRetNode->Insert( (ObjNode *)Left() );
        }
        else
            pRetNode = (ObjNode *)Left();
        delete this;
    }
    return pRetNode;
}

/*************************************************************************
|*
|*    ObjNode::GetId()
|*
|*    Beschreibung
|*    Ersterstellung    MM 29.10.91
|*    Letzte Aenderung  MM 29.10.91
|*
*************************************************************************/
sal_uInt32 ObjNode::GetId() const
{
    return( (sal_uInt32)(long)aRscId );
}

/*************************************************************************
|*
|*    ObjNode::IsConsistent()
|*
|*    Beschreibung
|*    Ersterstellung    MM 23.09.91
|*    Letzte Aenderung  MM 23.09.91
|*
*************************************************************************/
BOOL ObjNode::IsConsistent( RscInconsList * pList )
{
    BOOL bRet = TRUE;

    if( (long)aRscId > 0x7FFF || (long)aRscId < 1 )
    {
        bRet = FALSE;
        if( pList )
            pList->Insert( new RscInconsistent( aRscId, aRscId ) );
    }
    else
    {
        if( Left() )
        {
            if( !((ObjNode *)Left())->IsConsistent( pList ) )
                bRet = FALSE;
            if( ((ObjNode *)Left())->aRscId >= aRscId )
            {
                bRet = FALSE;
                if( pList )
                    pList->Insert(
                        new RscInconsistent( ((ObjNode *)Left())->GetRscId(),
                                             GetRscId() ) );
            }
        };
        if( Right() )
        {
            if( ((ObjNode *)Right())->aRscId <= aRscId )
            {
                bRet = FALSE;
                if( pList )
                    pList->Insert(
                        new RscInconsistent( GetRscId(),
                                             ((ObjNode *)Right())->GetRscId() ) );
            }
            if( !((ObjNode *)Right())->IsConsistent( pList ) )
                bRet = FALSE;
        };
    };

    return( bRet );
}
<|endoftext|>


<commit_before>#include "Core/Core.h"

#if(INTRA_LIBRARY_SOUND_SYSTEM==INTRA_LIBRARY_SOUND_SYSTEM_OpenAL)

#include "Sound/SoundApi.h"

#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#elif __linux
#include <AL/al.h>
#include <AL/alc.h>
#else
#include <al.h>
#include <alc.h>
#endif

#ifdef _MSC_VER
#pragma comment(lib, "OpenAL32.lib")
#endif

namespace Intra {

using namespace Math;

namespace SoundAPI {

const ValueType::I InternalBufferType = ValueType::Short;
const int InternalChannelsInterleaved = true;

struct Buffer
{
	Buffer(uint buf, uint sample_count, uint sample_rate, uint ch, ushort format):
		buffer(buf), sampleCount(sample_count), sampleRate(sample_rate), channels(ch), alformat(format) {}

	uint SizeInBytes() const {return uint(sampleCount*channels*sizeof(short));}

	uint buffer;
	uint sampleCount;
	uint sampleRate;
	uint channels;
	ushort alformat;

	void* locked_bits=null;
};

struct Instance
{
	Instance(uint src, BufferHandle my_parent): source(src), parent(my_parent) {}

	uint source;
	BufferHandle parent;

	bool deleteOnStop=false;
};

struct StreamedBuffer
{
	//StreamedBuffer(uint bufs[2], StreamingCallback callback, uint sample_count, uint sample_rate, ushort ch):
		//buffers{bufs[0], bufs[1]}, streamingCallback(callback), sampleCount(sampleCount), sampleRate(sample_rate), channels(ch) {}

	uint SizeInBytes() const {return uint(sampleCount*channels*sizeof(short));}

	uint buffers[2];
	uint source;
	uint sampleCount; //Размер половины буфера
	uint sampleRate;
	uint channels;
	StreamingCallback streamingCallback;
	short* temp_buffer;

	bool deleteOnStop=false;
	bool looping=false;
	byte stop_soon=0;
};

struct Context
{
	Context(): ald(null), alc(null) {}

	~Context()
	{
		if(alc==null) return;
		alcMakeContextCurrent(null);
		alcDestroyContext(alc);
		alc = null;
		if(ald==null) return;
		alcCloseDevice(ald);
	}

	void Prepare()
	{
		if(alc!=null) return;
		const ALCchar* defaultDevice = reinterpret_cast<const ALCchar*>(alcGetString(null, ALC_DEFAULT_DEVICE_SPECIFIER));
		if(ald==null) ald = alcOpenDevice(defaultDevice);
		alc = alcCreateContext(ald, null);
		alcMakeContextCurrent(alc);
		alcProcessContext(alc);
		//alListenerfv(AL_POSITION, Vec3(0,0,0));
		//alListenerfv(AL_VELOCITY, Vec3(0,0,0));
		//alListenerfv(AL_ORIENTATION, Vec3(0,0,0));
	}

	Context(const Context&) = delete;
	Context& operator=(const Context&) = delete;

	ALCdevice* ald;
	ALCcontext* alc;
};
static Context context;

static ushort get_format(uint channels)
{
	INTRA_ASSERT(channels>0 && channels<=2);
    if(channels==1) return AL_FORMAT_MONO16;
    if(channels==2) return AL_FORMAT_STEREO16;
    return 0;
}

BufferHandle BufferCreate(size_t sampleCount, uint channels, uint sampleRate)
{
	context.Prepare();
	uint buffer;
	alGenBuffers(1, &buffer);
	return new Buffer(buffer, uint(sampleCount), sampleRate, channels, get_format(channels));
}

void BufferSetDataInterleaved(BufferHandle snd, const void* data, ValueType type)
{
	(void)type;
	INTRA_ASSERT(data!=null);
	INTRA_ASSERT(type==ValueType::Short);
    alBufferData(snd->buffer, snd->alformat, data, int(snd->SizeInBytes()), int(snd->sampleRate));
    INTRA_ASSERT(alGetError()==AL_NO_ERROR);
}

void* BufferLock(BufferHandle snd)
{
	INTRA_ASSERT(snd!=null);
    snd->locked_bits = Memory::SystemHeapAllocator::Allocate(snd->SizeInBytes(), INTRA_SOURCE_INFO);
	return snd->locked_bits;
}

void BufferUnlock(BufferHandle snd)
{
	INTRA_ASSERT(snd!=null);
    alBufferData(snd->buffer, snd->alformat, snd->locked_bits, int(snd->SizeInBytes()), int(snd->sampleRate));
    INTRA_ASSERT(alGetError()==AL_NO_ERROR);
    Memory::SystemHeapAllocator::Free(snd->locked_bits);
    snd->locked_bits=null;
}

void BufferDelete(BufferHandle snd)
{
	if(snd==null) return;
	alDeleteBuffers(1, &snd->buffer);
	delete snd;
}

InstanceHandle InstanceCreate(BufferHandle snd)
{
	INTRA_ASSERT(snd!=null);
	uint source;
	alGenSources(1, &source);
	//alSource3f(source, AL_POSITION, 0, 0, 0);
	//alSource3f(source, AL_VELOCITY, 0, 0, 0);
	//alSource3f(source, AL_DIRECTION, 0, 0, 0);
	//alSourcef(source, AL_ROLLOFF_FACTOR, 0);
	//alSourcei(source, AL_SOURCE_RELATIVE, true);
	alSourcei(source, AL_BUFFER, int(snd->buffer));
	INTRA_ASSERT(alGetError()==AL_NO_ERROR);
	return new Instance(source, snd);
}

void InstanceSetDeleteOnStop(InstanceHandle si, bool del)
{
	si->deleteOnStop = del;
}

void InstanceDelete(InstanceHandle si)
{
	if(si==null) return;
	alDeleteSources(1, &si->source);
	delete si;
}

void InstancePlay(InstanceHandle si, bool loop)
{
	INTRA_ASSERT(si!=null);
	alSourcei(si->source, AL_LOOPING, loop);
	alSourcePlay(si->source);
	INTRA_ASSERT(alGetError()==AL_NO_ERROR);
}

bool InstanceIsPlaying(InstanceHandle si)
{
	if(si==null) return false;
	ALenum state;
	alGetSourcei(si->source, AL_SOURCE_STATE, &state);
	return (state==AL_PLAYING);
}

void InstanceStop(InstanceHandle si)
{
	if(si==null) return;
	alSourceStop(si->source);
}

StreamedBufferHandle StreamedBufferCreate(size_t sampleCount,
	uint channels, uint sampleRate, StreamingCallback callback)
{
	context.Prepare();
	if(sampleCount==0 || channels==0 ||
		sampleRate==0 || callback.CallbackFunction==null)
			return null;
	INTRA_ASSERT(channels<=2);
	StreamedBufferHandle result = new StreamedBuffer;
	alGenBuffers(2, result->buffers);
	alGenSources(1, &result->source);
	result->sampleCount = uint(sampleCount);
	result->sampleRate = sampleRate;
	result->channels = channels;
	result->streamingCallback = callback;
	result->temp_buffer = Memory::SystemHeapAllocator::Allocate(result->SizeInBytes(), INTRA_SOURCE_INFO);
	return result;
}

void StreamedBufferSetDeleteOnStop(StreamedBufferHandle snd, bool del)
{
	snd->deleteOnStop = del;
}

void StreamedBufferDelete(StreamedBufferHandle snd)
{
	alDeleteSources(1, &snd->source);
	alDeleteBuffers(2, snd->buffers);
	Memory::SystemHeapAllocator::Free(snd->temp_buffer);
}

static void load_buffer(StreamedBufferHandle snd, size_t index)
{
	const int alFmt = snd->channels==1? AL_FORMAT_MONO16: AL_FORMAT_STEREO16;
	const size_t samplesProcessed = snd->streamingCallback.CallbackFunction(reinterpret_cast<void**>(&snd->temp_buffer),
		snd->channels, ValueType::Short, true, snd->sampleCount, snd->streamingCallback.CallbackData);
	if(samplesProcessed<snd->sampleCount)
	{
		short* const endOfData = snd->temp_buffer+snd->sampleCount*snd->channels;
		const size_t totalSamplesInBuffer = (snd->sampleCount-samplesProcessed)*snd->channels;
		core::memset(endOfData, 0, totalSamplesInBuffer*sizeof(short));
		snd->stop_soon = true;
	}
	alBufferData(snd->buffers[index], alFmt, snd->temp_buffer, int(snd->SizeInBytes()), int(snd->sampleRate));
}

void StreamedSoundPlay(StreamedBufferHandle snd, bool loop)
{
	INTRA_ASSERT(snd!=null);
	load_buffer(snd, 0);
	if(!snd->stop_soon) load_buffer(snd, 1);
	alSourceQueueBuffers(snd->source, 2, snd->buffers);
	alSourcePlay(snd->source);
	snd->looping = loop;
}

bool StreamedSoundIsPlaying(StreamedBufferHandle si)
{
	int state;
	alGetSourcei(si->source, AL_SOURCE_STATE, &state);
	return state==AL_PLAYING;
}

void StreamedSoundStop(StreamedBufferHandle snd)
{
	if(!StreamedSoundIsPlaying(snd)) return;
	alSourceStop(snd->source);
	alSourceUnqueueBuffers(snd->source, 2, snd->buffers);
	snd->stop_soon = false;
	if(snd->deleteOnStop) StreamedBufferDelete(snd);
}

void StreamedSoundUpdate(StreamedBufferHandle snd)
{
	int countProcessed;
	alGetSourcei(snd->source, AL_BUFFERS_PROCESSED, &countProcessed);
	while(countProcessed--!=0)
	{
		if(snd->stop_soon && !snd->looping)
		{
			StreamedSoundStop(snd);
			snd->stop_soon = false;
			return;
		}
		alSourceUnqueueBuffers(snd->source, 1, snd->buffers);
		load_buffer(snd, 0);
		alSourceQueueBuffers(snd->source, 1, snd->buffers);
		core::swap(snd->buffers[0], snd->buffers[1]);
	}
}

}}

#endif
<commit_msg>OpenAL include fix<commit_after>#include "Core/Core.h"

#if(INTRA_LIBRARY_SOUND_SYSTEM==INTRA_LIBRARY_SOUND_SYSTEM_OpenAL)

#include "Sound/SoundApi.h"

#ifdef __APPLE__
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#elif(INTRA_PLATFORM_OS==PLATFORM_OS_Linux || INTRA_PLATFORM_OS==PLATFORM_OS_FreeBSD)
#include <AL/al.h>
#include <AL/alc.h>
#else
#include <al.h>
#include <alc.h>
#endif

#ifdef _MSC_VER
#pragma comment(lib, "OpenAL32.lib")
#endif

namespace Intra {

using namespace Math;

namespace SoundAPI {

const ValueType::I InternalBufferType = ValueType::Short;
const int InternalChannelsInterleaved = true;

struct Buffer
{
	Buffer(uint buf, uint sample_count, uint sample_rate, uint ch, ushort format):
		buffer(buf), sampleCount(sample_count), sampleRate(sample_rate), channels(ch), alformat(format) {}

	uint SizeInBytes() const {return uint(sampleCount*channels*sizeof(short));}

	uint buffer;
	uint sampleCount;
	uint sampleRate;
	uint channels;
	ushort alformat;

	void* locked_bits=null;
};

struct Instance
{
	Instance(uint src, BufferHandle my_parent): source(src), parent(my_parent) {}

	uint source;
	BufferHandle parent;

	bool deleteOnStop=false;
};

struct StreamedBuffer
{
	//StreamedBuffer(uint bufs[2], StreamingCallback callback, uint sample_count, uint sample_rate, ushort ch):
		//buffers{bufs[0], bufs[1]}, streamingCallback(callback), sampleCount(sampleCount), sampleRate(sample_rate), channels(ch) {}

	uint SizeInBytes() const {return uint(sampleCount*channels*sizeof(short));}

	uint buffers[2];
	uint source;
	uint sampleCount; //Размер половины буфера
	uint sampleRate;
	uint channels;
	StreamingCallback streamingCallback;
	short* temp_buffer;

	bool deleteOnStop=false;
	bool looping=false;
	byte stop_soon=0;
};

struct Context
{
	Context(): ald(null), alc(null) {}

	~Context()
	{
		if(alc==null) return;
		alcMakeContextCurrent(null);
		alcDestroyContext(alc);
		alc = null;
		if(ald==null) return;
		alcCloseDevice(ald);
	}

	void Prepare()
	{
		if(alc!=null) return;
		const ALCchar* defaultDevice = reinterpret_cast<const ALCchar*>(alcGetString(null, ALC_DEFAULT_DEVICE_SPECIFIER));
		if(ald==null) ald = alcOpenDevice(defaultDevice);
		alc = alcCreateContext(ald, null);
		alcMakeContextCurrent(alc);
		alcProcessContext(alc);
		//alListenerfv(AL_POSITION, Vec3(0,0,0));
		//alListenerfv(AL_VELOCITY, Vec3(0,0,0));
		//alListenerfv(AL_ORIENTATION, Vec3(0,0,0));
	}

	Context(const Context&) = delete;
	Context& operator=(const Context&) = delete;

	ALCdevice* ald;
	ALCcontext* alc;
};
static Context context;

static ushort get_format(uint channels)
{
	INTRA_ASSERT(channels>0 && channels<=2);
    if(channels==1) return AL_FORMAT_MONO16;
    if(channels==2) return AL_FORMAT_STEREO16;
    return 0;
}

BufferHandle BufferCreate(size_t sampleCount, uint channels, uint sampleRate)
{
	context.Prepare();
	uint buffer;
	alGenBuffers(1, &buffer);
	return new Buffer(buffer, uint(sampleCount), sampleRate, channels, get_format(channels));
}

void BufferSetDataInterleaved(BufferHandle snd, const void* data, ValueType type)
{
	(void)type;
	INTRA_ASSERT(data!=null);
	INTRA_ASSERT(type==ValueType::Short);
    alBufferData(snd->buffer, snd->alformat, data, int(snd->SizeInBytes()), int(snd->sampleRate));
    INTRA_ASSERT(alGetError()==AL_NO_ERROR);
}

void* BufferLock(BufferHandle snd)
{
	INTRA_ASSERT(snd!=null);
    snd->locked_bits = Memory::SystemHeapAllocator::Allocate(snd->SizeInBytes(), INTRA_SOURCE_INFO);
	return snd->locked_bits;
}

void BufferUnlock(BufferHandle snd)
{
	INTRA_ASSERT(snd!=null);
    alBufferData(snd->buffer, snd->alformat, snd->locked_bits, int(snd->SizeInBytes()), int(snd->sampleRate));
    INTRA_ASSERT(alGetError()==AL_NO_ERROR);
    Memory::SystemHeapAllocator::Free(snd->locked_bits);
    snd->locked_bits=null;
}

void BufferDelete(BufferHandle snd)
{
	if(snd==null) return;
	alDeleteBuffers(1, &snd->buffer);
	delete snd;
}

InstanceHandle InstanceCreate(BufferHandle snd)
{
	INTRA_ASSERT(snd!=null);
	uint source;
	alGenSources(1, &source);
	//alSource3f(source, AL_POSITION, 0, 0, 0);
	//alSource3f(source, AL_VELOCITY, 0, 0, 0);
	//alSource3f(source, AL_DIRECTION, 0, 0, 0);
	//alSourcef(source, AL_ROLLOFF_FACTOR, 0);
	//alSourcei(source, AL_SOURCE_RELATIVE, true);
	alSourcei(source, AL_BUFFER, int(snd->buffer));
	INTRA_ASSERT(alGetError()==AL_NO_ERROR);
	return new Instance(source, snd);
}

void InstanceSetDeleteOnStop(InstanceHandle si, bool del)
{
	si->deleteOnStop = del;
}

void InstanceDelete(InstanceHandle si)
{
	if(si==null) return;
	alDeleteSources(1, &si->source);
	delete si;
}

void InstancePlay(InstanceHandle si, bool loop)
{
	INTRA_ASSERT(si!=null);
	alSourcei(si->source, AL_LOOPING, loop);
	alSourcePlay(si->source);
	INTRA_ASSERT(alGetError()==AL_NO_ERROR);
}

bool InstanceIsPlaying(InstanceHandle si)
{
	if(si==null) return false;
	ALenum state;
	alGetSourcei(si->source, AL_SOURCE_STATE, &state);
	return (state==AL_PLAYING);
}

void InstanceStop(InstanceHandle si)
{
	if(si==null) return;
	alSourceStop(si->source);
}

StreamedBufferHandle StreamedBufferCreate(size_t sampleCount,
	uint channels, uint sampleRate, StreamingCallback callback)
{
	context.Prepare();
	if(sampleCount==0 || channels==0 ||
		sampleRate==0 || callback.CallbackFunction==null)
			return null;
	INTRA_ASSERT(channels<=2);
	StreamedBufferHandle result = new StreamedBuffer;
	alGenBuffers(2, result->buffers);
	alGenSources(1, &result->source);
	result->sampleCount = uint(sampleCount);
	result->sampleRate = sampleRate;
	result->channels = channels;
	result->streamingCallback = callback;
	result->temp_buffer = Memory::SystemHeapAllocator::Allocate(result->SizeInBytes(), INTRA_SOURCE_INFO);
	return result;
}

void StreamedBufferSetDeleteOnStop(StreamedBufferHandle snd, bool del)
{
	snd->deleteOnStop = del;
}

void StreamedBufferDelete(StreamedBufferHandle snd)
{
	alDeleteSources(1, &snd->source);
	alDeleteBuffers(2, snd->buffers);
	Memory::SystemHeapAllocator::Free(snd->temp_buffer);
}

static void load_buffer(StreamedBufferHandle snd, size_t index)
{
	const int alFmt = snd->channels==1? AL_FORMAT_MONO16: AL_FORMAT_STEREO16;
	const size_t samplesProcessed = snd->streamingCallback.CallbackFunction(reinterpret_cast<void**>(&snd->temp_buffer),
		snd->channels, ValueType::Short, true, snd->sampleCount, snd->streamingCallback.CallbackData);
	if(samplesProcessed<snd->sampleCount)
	{
		short* const endOfData = snd->temp_buffer+snd->sampleCount*snd->channels;
		const size_t totalSamplesInBuffer = (snd->sampleCount-samplesProcessed)*snd->channels;
		core::memset(endOfData, 0, totalSamplesInBuffer*sizeof(short));
		snd->stop_soon = true;
	}
	alBufferData(snd->buffers[index], alFmt, snd->temp_buffer, int(snd->SizeInBytes()), int(snd->sampleRate));
}

void StreamedSoundPlay(StreamedBufferHandle snd, bool loop)
{
	INTRA_ASSERT(snd!=null);
	load_buffer(snd, 0);
	if(!snd->stop_soon) load_buffer(snd, 1);
	alSourceQueueBuffers(snd->source, 2, snd->buffers);
	alSourcePlay(snd->source);
	snd->looping = loop;
}

bool StreamedSoundIsPlaying(StreamedBufferHandle si)
{
	int state;
	alGetSourcei(si->source, AL_SOURCE_STATE, &state);
	return state==AL_PLAYING;
}

void StreamedSoundStop(StreamedBufferHandle snd)
{
	if(!StreamedSoundIsPlaying(snd)) return;
	alSourceStop(snd->source);
	alSourceUnqueueBuffers(snd->source, 2, snd->buffers);
	snd->stop_soon = false;
	if(snd->deleteOnStop) StreamedBufferDelete(snd);
}

void StreamedSoundUpdate(StreamedBufferHandle snd)
{
	int countProcessed;
	alGetSourcei(snd->source, AL_BUFFERS_PROCESSED, &countProcessed);
	while(countProcessed--!=0)
	{
		if(snd->stop_soon && !snd->looping)
		{
			StreamedSoundStop(snd);
			snd->stop_soon = false;
			return;
		}
		alSourceUnqueueBuffers(snd->source, 1, snd->buffers);
		load_buffer(snd, 0);
		alSourceQueueBuffers(snd->source, 1, snd->buffers);
		core::swap(snd->buffers[0], snd->buffers[1]);
	}
}

}}

#endif
<|endoftext|>


<commit_before>#include <agency/execution_policy.hpp>
#include <iostream>

int main()
{
  std::cout << "Starting two tasks asynchronously..." << std::endl;

  std::mutex mut;

  // asynchronously create 5 agents to greet us in bulk
  auto f1 = agency::bulk_async(agency::par(5), [&](agency::parallel_agent& self)
  {
    mut.lock();
    std::cout << "Hello, world from agent " << self.index() << " in task 1" << std::endl;
    mut.unlock();
  });

  // asynchronously create 5 agents to greet us in bulk
  auto f2 = agency::bulk_async(agency::par(5), [&](agency::parallel_agent& self)
  {
    mut.lock();
    std::cout << "Hello, world from agent " << self.index() << " in task 2" << std::endl;
    mut.unlock();
  });

  std::cout << "Sleeping before waiting on the tasks..." << std::endl;
  std::this_thread::sleep_for(std::chrono::seconds(1));
  std::cout << "Woke up, waiting for the tasks to complete..." << std::endl;

  // wait for tasks 1 & 2 to complete before continuing
  f1.wait();
  f2.wait();

  std::cout << "OK" << std::endl;

  return 0;
}

<commit_msg>Use using<commit_after>#include <agency/execution_policy.hpp>
#include <iostream>

int main()
{
  using namespace agency;

  std::cout << "Starting two tasks asynchronously..." << std::endl;

  std::mutex mut;

  // asynchronously create 5 agents to greet us in bulk
  auto f1 = bulk_async(par(5), [&](parallel_agent& self)
  {
    mut.lock();
    std::cout << "Hello, world from agent " << self.index() << " in task 1" << std::endl;
    mut.unlock();
  });

  // asynchronously create 5 agents to greet us in bulk
  auto f2 = bulk_async(par(5), [&](parallel_agent& self)
  {
    mut.lock();
    std::cout << "Hello, world from agent " << self.index() << " in task 2" << std::endl;
    mut.unlock();
  });

  std::cout << "Sleeping before waiting on the tasks..." << std::endl;
  std::this_thread::sleep_for(std::chrono::seconds(1));
  std::cout << "Woke up, waiting for the tasks to complete..." << std::endl;

  // wait for tasks 1 & 2 to complete before continuing
  f1.wait();
  f2.wait();

  std::cout << "OK" << std::endl;

  return 0;
}

<|endoftext|>


<commit_before>#pragma once

#include <stdexcept>
#include <variant>
#include <string>
#include <string_view>
#include <vector>
#include <map>
#include <iostream>
#include <cassert>

#include "acmacs-base/debug.hh"
#include "acmacs-base/float.hh"
#include "acmacs-base/filesystem.hh"

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

namespace rjson
{
    namespace implementation { class NumberHandler; }

    class value;

    class string
    {
     public:
        inline string(std::string aData) : mData{aData} {}
        inline string(const char* aData) : mData{aData} {}
        inline std::string to_json() const { return std::string{"\""} + static_cast<std::string>(mData) + "\""; }
        inline operator std::string() const { return mData; }
        inline string& operator=(std::string aSrc) { mData = aSrc; return *this; }
        inline bool operator==(const std::string aToCompare) const { return mData == aToCompare; }
        inline bool operator==(const string& aToCompare) const { return mData == aToCompare.mData; }
        inline size_t size() const { return mData.size(); }
        inline bool empty() const { return mData.empty(); }
        inline bool operator<(const string& to_compare) const { return mData < to_compare.mData; }

     private:
        std::string mData;
    };

    class boolean
    {
     public:
        inline boolean(bool aValue) : mValue{aValue} {}
        inline std::string to_json() const { return mValue ? "true" : "false"; }
        inline operator bool() const { return mValue; }
        inline boolean& operator=(bool aSrc) { mValue = aSrc; return *this; }

     private:
        bool mValue;
    };

    class null
    {
     public:
        inline null() {}
        inline std::string to_json() const { return "null"; }
    };

    class number
    {
     public:
        inline number(double aSrc) : mValue{double_to_string(aSrc)} {}
        inline number& operator=(double aSrc) { mValue = double_to_string(aSrc); return *this; }
        inline std::string to_json() const { return mValue; } // { return double_to_string(mValue); }
        inline operator double() const { return std::stod(mValue); } // { return mValue; }

     private:
        inline number(std::string_view&& aData) : mValue{aData} {} // mValue{std::stod(static_cast<std::string>(aData))} {}

          // double mValue;
        std::string mValue;

        friend class implementation::NumberHandler;
    };

    class integer
    {
     public:
        inline integer(long aSrc) : mValue{std::to_string(aSrc)} {}
        inline integer& operator=(long aSrc) { mValue = std::to_string(aSrc); return *this; }
        inline std::string to_json() const { return mValue; } // { return std::to_string(mValue); }
        inline operator double() const { return std::stod(mValue); } // { return mValue; }
        inline operator long() const { return std::stol(mValue); } // { return mValue; }

     private:
        inline integer(std::string_view&& aData) : mValue{aData} {} // mValue{std::stol(static_cast<std::string>(aData))} {}

          // long mValue;
        std::string mValue;

        friend class implementation::NumberHandler;
    };

    class object
    {
     public:
        std::string to_json() const;

        void insert(value&& aKey, value&& aValue);
        inline size_t size() const { return mContent.size(); }
        inline bool empty() const { return mContent.empty(); }

          // returns reference to the value at the passed key.
          // if key not found, inserts aDefault with the passed key and returns reference to the inserted
        value& get_ref(std::string aKey, value&& aDefault);
        void set_field(std::string aKey, value&& aValue);

     private:
        std::map<string, value> mContent;
          // std::vector<std::pair<string, value>> mContent;
    };

    class array
    {
     public:
        std::string to_json() const;

        void insert(value&& aValue);
        inline size_t size() const { return mContent.size(); }
        inline bool empty() const { return mContent.empty(); }
        inline value& operator[](size_t index) { return mContent[index]; }
        inline const value& operator[](size_t index) const { return mContent[index]; }

     private:
        std::vector<value> mContent;
    };

    namespace implementation
    {
        template <typename F> struct content_type;
        template <> struct content_type<double> { using type = rjson::number; };
        template <> struct content_type<long> { using type = rjson::integer; };
        template <> struct content_type<int> { using type = rjson::integer; };
        template <> struct content_type<bool> { using type = rjson::boolean; };
        template <> struct content_type<std::string> { using type = rjson::string; };

        template <typename FValue> value to_value(const FValue& aValue);
    }

    using value_base = std::variant<null, object, array, string, integer, number, boolean>; // null must be the first alternative, it is the default value;

    class value : public value_base
    {
     public:
        using value_base::operator=;
        using value_base::value_base;
        inline value(const value&) = default; // gcc7 wants this, otherwise it is deleted
        inline value& operator=(const value&) = default; // gcc7 wants this, otherwise it is deleted
          // inline ~value() { std::cerr << "DEBUG: ~value " << to_json() << DEBUG_LINE_FUNC << '\n'; }

          // returns reference to the value at the passed key.
          // if key not found, inserts aDefault with the passed key and returns reference to the inserted
          // if this is not an object, throws  std::bad_variant_access
        inline value& get_ref(std::string aKey, value&& aDefault)
            {
                try {
                    return std::get<object>(*this).get_ref(aKey, std::forward<value>(aDefault));
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::get_ref: not an object: valueless_by_exception:" << valueless_by_exception() << " index:" << index() << '\n'; // to_json() << '\n';
                    throw;
                }
            }

        template <typename F> inline std::decay_t<F> get_field(std::string aFieldName, F&& aDefaultValue)
            {
                using rjson_type = typename implementation::content_type<std::decay_t<F>>::type;
                return std::get<rjson_type>(get_ref(aFieldName, rjson_type{std::forward<F>(aDefaultValue)}));
            }

        template <typename F> inline void set_field(std::string aFieldName, F&& aValue)
            {
                try {
                    std::get<object>(*this).set_field(aFieldName, implementation::to_value(aValue));
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::set_field: not an object: " << to_json() << '\n';
                    throw;
                }
                  // using rjson_type = typename implementation::content_type<std::decay_t<F>>::type;
                  // std::get<object>(*this).set_field(aFieldName, rjson_type{std::forward<F>(aValue)});
            }

        std::string to_json() const;
    };

    namespace implementation
    {
        template <typename FValue> inline value to_value(const FValue& aValue)
        {
            using rjson_type = typename implementation::content_type<std::decay_t<FValue>>::type;
            return rjson_type{aValue};
        }
    }

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

    class field_container
    {
     public:
        inline void use_json(value& aData) { mData = &aData; }
        inline operator value&() { assert(mData); return *mData; }
        inline operator const value&() const { assert(mData); return *mData; }
        inline std::string to_json() const { return static_cast<const value&>(*this).to_json(); }

     private:
        mutable value* mData = nullptr;
    };

    template <typename FValue> class field_get_set
    {
     public:
        inline field_get_set(field_container* aContainer, std::string aFieldName, FValue&& aDefault) : mContainer{*aContainer}, mFieldName{aFieldName}, mDefault{std::move(aDefault)} {}
        inline operator FValue() const { return static_cast<value&>(mContainer).get_field(mFieldName, mDefault); } // static_cast to non-const because we need to set to mDefault
        inline field_get_set<FValue>& operator = (FValue&& aValue) { static_cast<value&>(mContainer).set_field(mFieldName, std::forward<FValue>(aValue)); return *this; }
        inline field_get_set<FValue>& operator = (const FValue& aValue) { static_cast<value&>(mContainer).set_field(mFieldName, aValue); return *this; }
        inline field_get_set<FValue>& operator = (const field_get_set<FValue>& aSource) { return operator=(static_cast<FValue>(aSource)); }

     protected:
        inline value& get_ref() { return static_cast<value&>(mContainer).get_ref(mFieldName, implementation::to_value(mDefault)); }
        inline const value& get_ref() const { return static_cast<value&>(mContainer).get_ref(mFieldName, implementation::to_value(mDefault)); }
        using rjson_type = typename implementation::content_type<FValue>::type;
        inline rjson_type& get_value_ref() { return std::get<rjson_type>(get_ref()); }
        inline const rjson_type& get_value_ref() const { return std::get<rjson_type>(get_ref()); }

     private:
        field_container& mContainer;
        std::string mFieldName;
        FValue mDefault;
    };

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

    class Error : public std::exception
    {
     public:
        // inline Error(size_t aLine, size_t aColumn, std::string aMessage)
        //     : mMessage{std::to_string(aLine) + ":" + std::to_string(aColumn) + ": " + aMessage} //, mLine{aLine}, mColumn{aColumn}
        //     {}

        inline Error(size_t aLine, size_t aColumn, std::string&& aMessage)
            : mMessage{std::to_string(aLine) + ":" + std::to_string(aColumn) + ": " + std::move(aMessage)} //, mLine{aLine}, mColumn{aColumn}
            {}

        inline const char* what() const noexcept override { return mMessage.c_str(); }

     private:
        std::string mMessage;
          //size_t mLine, mColumn;

    }; // class Error

    value parse_string(std::string aJsonData);
    value parse_file(std::string aFilename);

} // namespace rjson

// ----------------------------------------------------------------------
// gcc-7 support
// ----------------------------------------------------------------------

#if __GNUC__ == 7
namespace std
{
      // gcc 7.2 wants those, if we derive from std::variant
    template<> struct variant_size<rjson::value> : variant_size<rjson::value_base> {};
    template<size_t _Np> struct variant_alternative<_Np, rjson::value> : variant_alternative<_Np, rjson::value_base> {};
}
#endif

// ----------------------------------------------------------------------
// inline
// ----------------------------------------------------------------------

namespace rjson
{
    inline void object::insert(value&& aKey, value&& aValue)
    {
        mContent.emplace(std::get<rjson::string>(aKey), aValue);
          // mContent.emplace_back(std::get<rjson::string>(aKey), aValue);
    }

    inline value& object::get_ref(std::string aKey, value&& aDefault)
    {
        const auto [iter, inserted] = mContent.emplace(aKey, std::forward<value>(aDefault));
        return iter->second;

        // auto found = std::find_if(std::begin(mContent), std::end(mContent), [&aKey](const auto& entry) { return entry.first == aKey; });
        // if (found == std::end(mContent)) {
        //       // std::cerr << "DEBUG: object::get_ref: not found: " << aKey << ' ' << to_json() << " default:" << aDefault.to_json() << '\n';
        //       return mContent.emplace_back(aKey, std::forward<value>(aDefault)).second;
        // }
        // else {
        //     // std::cerr << "DEBUG: object::get_ref: found: " << aKey << ' ' << found->second.to_json() << '\n';
        //     return found->second;
        // }
    }

    inline void object::set_field(std::string aKey, value&& aValue)
    {
        mContent.insert_or_assign(aKey, std::forward<value>(aValue));

        // auto found = std::find_if(std::begin(mContent), std::end(mContent), [&aKey](const auto& entry) { return entry.first == aKey; });
        // if (found == std::end(mContent)) {
        //     mContent.emplace_back(std::move(aKey), std::forward<value>(aValue));
        // }
        // else {
        //     found->second = std::forward<value>(aValue);
        // }
    }

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

    inline void array::insert(value&& aValue)
    {
        mContent.push_back(std::move(aValue));
    }

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

    inline std::string value::to_json() const
    {
        return std::visit([](auto&& arg) -> std::string { return arg.to_json(); }, *this);
    }
}

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

inline std::ostream& operator<<(std::ostream& out, const rjson::value& aValue)
{
    return out << aValue.to_json();
}

template <typename FValue> inline std::ostream& operator<<(std::ostream& out, const rjson::field_get_set<FValue>& aValue)
{
    return out << static_cast<FValue>(aValue);
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>rjson development<commit_after>#pragma once

#include <stdexcept>
#include <variant>
#include <string>
#include <string_view>
#include <vector>
#include <map>
#include <iostream>
#include <cassert>

#include "acmacs-base/debug.hh"
#include "acmacs-base/float.hh"
#include "acmacs-base/filesystem.hh"

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

namespace rjson
{
    namespace implementation { class NumberHandler; }

    class value;

    class string
    {
     public:
        inline string(std::string aData) : mData{aData} {}
        inline string(const char* aData) : mData{aData} {}
        inline std::string to_json() const { return std::string{"\""} + static_cast<std::string>(mData) + "\""; }
        inline operator std::string() const { return mData; }
        inline string& operator=(std::string aSrc) { mData = aSrc; return *this; }
        inline bool operator==(const std::string aToCompare) const { return mData == aToCompare; }
        inline bool operator==(const string& aToCompare) const { return mData == aToCompare.mData; }
        inline size_t size() const { return mData.size(); }
        inline bool empty() const { return mData.empty(); }
        inline bool operator<(const string& to_compare) const { return mData < to_compare.mData; }

     private:
        std::string mData;
    };

    class boolean
    {
     public:
        inline boolean(bool aValue) : mValue{aValue} {}
        inline std::string to_json() const { return mValue ? "true" : "false"; }
        inline operator bool() const { return mValue; }
        inline boolean& operator=(bool aSrc) { mValue = aSrc; return *this; }

     private:
        bool mValue;
    };

    class null
    {
     public:
        inline null() {}
        inline std::string to_json() const { return "null"; }
    };

    class number
    {
     public:
        inline number(double aSrc) : mValue{double_to_string(aSrc)} {}
        inline number& operator=(double aSrc) { mValue = double_to_string(aSrc); return *this; }
        inline std::string to_json() const { return mValue; } // { return double_to_string(mValue); }
        inline operator double() const { return std::stod(mValue); } // { return mValue; }

     private:
        inline number(std::string_view&& aData) : mValue{aData} {} // mValue{std::stod(static_cast<std::string>(aData))} {}

          // double mValue;
        std::string mValue;

        friend class implementation::NumberHandler;
    };

    class integer
    {
     public:
        inline integer(long aSrc) : mValue{std::to_string(aSrc)} {}
        inline integer& operator=(long aSrc) { mValue = std::to_string(aSrc); return *this; }
        inline std::string to_json() const { return mValue; } // { return std::to_string(mValue); }
        inline operator double() const { return std::stod(mValue); } // { return mValue; }
        inline operator long() const { return std::stol(mValue); } // { return mValue; }

     private:
        inline integer(std::string_view&& aData) : mValue{aData} {} // mValue{std::stol(static_cast<std::string>(aData))} {}

          // long mValue;
        std::string mValue;

        friend class implementation::NumberHandler;
    };

    class object
    {
     public:
        std::string to_json() const;

        void insert(value&& aKey, value&& aValue);
        inline size_t size() const { return mContent.size(); }
        inline bool empty() const { return mContent.empty(); }

          // returns reference to the value at the passed key.
          // if key not found, inserts aDefault with the passed key and returns reference to the inserted
        value& get_ref(std::string aKey, value&& aDefault);
        void set_field(std::string aKey, value&& aValue);

     private:
        std::map<string, value> mContent;
          // std::vector<std::pair<string, value>> mContent;
    };

    class array
    {
     public:
        inline array() = default;
        inline array(array&&) = default;
        inline array(const array&) = default;
        inline array(std::initializer_list<value> args);
        inline array& operator=(array&&) = default;
        inline array& operator=(const array&) = default;

        std::string to_json() const;

        void insert(value&& aValue);
        void insert(const value& aValue);
        inline size_t size() const { return mContent.size(); }
        inline bool empty() const { return mContent.empty(); }
        inline value& operator[](size_t index) { return mContent[index]; }
        inline const value& operator[](size_t index) const { return mContent[index]; }

     private:
        std::vector<value> mContent;
    };

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

    template <typename F> struct content_type;
    template <> struct content_type<double> { using type = rjson::number; };
    template <> struct content_type<long> { using type = rjson::integer; };
    template <> struct content_type<int> { using type = rjson::integer; };
    template <> struct content_type<bool> { using type = rjson::boolean; };
    template <> struct content_type<std::string> { using type = rjson::string; };

    template <typename FValue> value to_value(const FValue& aValue);

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

    using value_base = std::variant<null, object, array, string, integer, number, boolean>; // null must be the first alternative, it is the default value;

    class value : public value_base
    {
     public:
        using value_base::operator=;
        using value_base::value_base;
        inline value(const value&) = default; // gcc7 wants this, otherwise it is deleted
        inline value& operator=(const value&) = default; // gcc7 wants this, otherwise it is deleted
          // inline ~value() { std::cerr << "DEBUG: ~value " << to_json() << DEBUG_LINE_FUNC << '\n'; }

          // returns reference to the value at the passed key.
          // if key not found, inserts aDefault with the passed key and returns reference to the inserted
          // if this is not an object, throws  std::bad_variant_access
        inline value& get_ref(std::string aKey, value&& aDefault)
            {
                try {
                    return std::get<object>(*this).get_ref(aKey, std::forward<value>(aDefault));
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::get_ref: not an object: valueless_by_exception:" << valueless_by_exception() << " index:" << index() << '\n'; // to_json() << '\n';
                    throw;
                }
            }

        template <typename F> inline std::decay_t<F> get_field(std::string aFieldName, F&& aDefaultValue)
            {
                using rjson_type = typename content_type<std::decay_t<F>>::type;
                return std::get<rjson_type>(get_ref(aFieldName, rjson_type{std::forward<F>(aDefaultValue)}));
            }

        template <typename F> inline void set_field(std::string aFieldName, F&& aValue)
            {
                try {
                    std::get<object>(*this).set_field(aFieldName, to_value(aValue));
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::set_field: not an object: " << to_json() << '\n';
                    throw;
                }
            }

        std::string to_json() const;
    };

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

    template <typename FValue> inline value to_value(const FValue& aValue)
    {
        using rjson_type = typename content_type<std::decay_t<FValue>>::type;
        return rjson_type{aValue};
    }

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

    class Error : public std::exception
    {
     public:
        // inline Error(size_t aLine, size_t aColumn, std::string aMessage)
        //     : mMessage{std::to_string(aLine) + ":" + std::to_string(aColumn) + ": " + aMessage} //, mLine{aLine}, mColumn{aColumn}
        //     {}

        inline Error(size_t aLine, size_t aColumn, std::string&& aMessage)
            : mMessage{std::to_string(aLine) + ":" + std::to_string(aColumn) + ": " + std::move(aMessage)} //, mLine{aLine}, mColumn{aColumn}
            {}

        inline const char* what() const noexcept override { return mMessage.c_str(); }

     private:
        std::string mMessage;
          //size_t mLine, mColumn;

    }; // class Error

    value parse_string(std::string aJsonData);
    value parse_file(std::string aFilename);

} // namespace rjson

// ----------------------------------------------------------------------
// gcc-7 support
// ----------------------------------------------------------------------

#if __GNUC__ == 7
namespace std
{
      // gcc 7.2 wants those, if we derive from std::variant
    template<> struct variant_size<rjson::value> : variant_size<rjson::value_base> {};
    template<size_t _Np> struct variant_alternative<_Np, rjson::value> : variant_alternative<_Np, rjson::value_base> {};
}
#endif

// ----------------------------------------------------------------------
// inline
// ----------------------------------------------------------------------

namespace rjson
{
    inline void object::insert(value&& aKey, value&& aValue)
    {
        mContent.emplace(std::get<rjson::string>(aKey), aValue);
          // mContent.emplace_back(std::get<rjson::string>(aKey), aValue);
    }

    inline value& object::get_ref(std::string aKey, value&& aDefault)
    {
        const auto [iter, inserted] = mContent.emplace(aKey, std::forward<value>(aDefault));
        return iter->second;

        // auto found = std::find_if(std::begin(mContent), std::end(mContent), [&aKey](const auto& entry) { return entry.first == aKey; });
        // if (found == std::end(mContent)) {
        //       // std::cerr << "DEBUG: object::get_ref: not found: " << aKey << ' ' << to_json() << " default:" << aDefault.to_json() << '\n';
        //       return mContent.emplace_back(aKey, std::forward<value>(aDefault)).second;
        // }
        // else {
        //     // std::cerr << "DEBUG: object::get_ref: found: " << aKey << ' ' << found->second.to_json() << '\n';
        //     return found->second;
        // }
    }

    inline void object::set_field(std::string aKey, value&& aValue)
    {
        mContent.insert_or_assign(aKey, std::forward<value>(aValue));

        // auto found = std::find_if(std::begin(mContent), std::end(mContent), [&aKey](const auto& entry) { return entry.first == aKey; });
        // if (found == std::end(mContent)) {
        //     mContent.emplace_back(std::move(aKey), std::forward<value>(aValue));
        // }
        // else {
        //     found->second = std::forward<value>(aValue);
        // }
    }

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

    inline void array::insert(value&& aValue) { mContent.push_back(std::move(aValue)); }
    inline void array::insert(const value& aValue) { mContent.push_back(aValue); }

    inline array::array(std::initializer_list<value> args)
    {
        for (const auto& arg: args)
            insert(arg);
    }

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

    inline std::string value::to_json() const
    {
        return std::visit([](auto&& arg) -> std::string { return arg.to_json(); }, *this);
    }
}

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

inline std::ostream& operator<<(std::ostream& out, const rjson::value& aValue)
{
    return out << aValue.to_json();
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>