<commit_before>#include "file_system.hpp"
#include <windows.h>

namespace msrv {

namespace {

inline int64_t makeInt64(DWORD high, DWORD low)
{
    return (static_cast<int64_t>(high) << 32) | static_cast<int64_t>(low);
}

inline FileType getFileType(DWORD attributes)
{
    return attributes & FILE_ATTRIBUTE_DIRECTORY
        ? FileType::DIRECTORY
        : FileType::REGULAR;
}

inline int64_t getUnixTimestamp(FILETIME time)
{
    return  makeInt64(time.dwHighDateTime, time.dwLowDateTime) / INT64_C(10000000) - INT64_C(11644473600);
}

}

Path getModulePath(void* symbol)
{
    ::HMODULE module;

    auto ret = ::GetModuleHandleExW(
        GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
        reinterpret_cast<wchar_t*>(symbol),
        &module);

    throwIfFailed("GetModuleHandleExW", ret != 0);

    Path::string_type path;
    path.resize(1024);
    auto size = ::GetModuleFileNameW(module, &path[0], path.length());
    throwIfFailed("GetModuleFileNameW", size > 0 && size < path.length());

    path.resize(static_cast<size_t>(size));
    return Path(std::move(path));
}

FileHandle openFile(const Path&)
{
    return FileHandle();
}

FileInfo queryFileInfo(FileHandle::Type handle)
{
    ::BY_HANDLE_FILE_INFORMATION data;
    auto ret = ::GetFileInformationByHandle(handle, &data);
    throwIfFailed("GetFileInformationByHandle", ret != 0);

    FileInfo info;
    info.inode = -1;
    info.size = makeInt64(data.nFileSizeHigh, data.nFileIndexLow);
    info.type = getFileType(data.dwFileAttributes);
    info.timestamp = getUnixTimestamp(data.ftLastWriteTime);
    return info;
}

FileInfo queryFileInfo(const Path& path)
{
    ::WIN32_FILE_ATTRIBUTE_DATA data;
    auto ret = ::GetFileAttributesExW(path.native().c_str(), GetFileExInfoStandard, &data);
    throwIfFailed("GetFileAttributesExW", ret != 0);

    FileInfo info;
    info.inode = -1;
    info.size = makeInt64(data.nFileSizeHigh, data.nFileSizeLow);
    info.type = getFileType(data.dwFileAttributes);
    info.timestamp = getUnixTimestamp(data.ftLastWriteTime);
    return info;
}

size_t readFile(FileHandle::Type handle, void* buffer, size_t bytes)
{
    DWORD bytesRead;
    auto ret = ::ReadFile(handle, buffer, static_cast<DWORD>(bytes), &bytesRead, nullptr);
    throwIfFailed("ReadFile", ret != 0);
    return bytesRead;
}

}
<commit_msg>implement openFile<commit_after>#include "file_system.hpp"
#include <windows.h>

namespace msrv {

namespace {

inline int64_t makeInt64(DWORD high, DWORD low)
{
    return (static_cast<int64_t>(high) << 32) | static_cast<int64_t>(low);
}

inline FileType getFileType(DWORD attributes)
{
    return attributes & FILE_ATTRIBUTE_DIRECTORY
        ? FileType::DIRECTORY
        : FileType::REGULAR;
}

inline int64_t getUnixTimestamp(FILETIME time)
{
    return  makeInt64(time.dwHighDateTime, time.dwLowDateTime) / INT64_C(10000000) - INT64_C(11644473600);
}

}

Path getModulePath(void* symbol)
{
    ::HMODULE module;

    auto ret = ::GetModuleHandleExW(
        GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
        reinterpret_cast<wchar_t*>(symbol),
        &module);

    throwIfFailed("GetModuleHandleExW", ret != 0);

    Path::string_type path;
    path.resize(1024);
    auto size = ::GetModuleFileNameW(module, &path[0], path.length());
    throwIfFailed("GetModuleFileNameW", size > 0 && size < path.length());

    path.resize(static_cast<size_t>(size));
    return Path(std::move(path));
}

FileHandle openFile(const Path& path)
{
    return FileHandle(::CreateFileW(
        path.c_str(),
        GENERIC_READ,
        FILE_SHARE_READ,
        nullptr,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        nullptr));
}

FileInfo queryFileInfo(FileHandle::Type handle)
{
    ::BY_HANDLE_FILE_INFORMATION data;
    auto ret = ::GetFileInformationByHandle(handle, &data);
    throwIfFailed("GetFileInformationByHandle", ret != 0);

    FileInfo info;
    info.inode = -1;
    info.size = makeInt64(data.nFileSizeHigh, data.nFileIndexLow);
    info.type = getFileType(data.dwFileAttributes);
    info.timestamp = getUnixTimestamp(data.ftLastWriteTime);
    return info;
}

FileInfo queryFileInfo(const Path& path)
{
    ::WIN32_FILE_ATTRIBUTE_DATA data;
    auto ret = ::GetFileAttributesExW(path.native().c_str(), GetFileExInfoStandard, &data);
    throwIfFailed("GetFileAttributesExW", ret != 0);

    FileInfo info;
    info.inode = -1;
    info.size = makeInt64(data.nFileSizeHigh, data.nFileSizeLow);
    info.type = getFileType(data.dwFileAttributes);
    info.timestamp = getUnixTimestamp(data.ftLastWriteTime);
    return info;
}

size_t readFile(FileHandle::Type handle, void* buffer, size_t bytes)
{
    DWORD bytesRead;
    auto ret = ::ReadFile(handle, buffer, static_cast<DWORD>(bytes), &bytesRead, nullptr);
    throwIfFailed("ReadFile", ret != 0);
    return bytesRead;
}

}
<|endoftext|>


<commit_before>#include "bufferAgent.h"

using boost::shared_ptr;
using boost::thread;
using boost::bind;

using std::string;

namespace veil {
namespace helpers {

BufferAgent::BufferAgent(write_fun w, read_fun r)
  : m_agentActive(false),
    doWrite(w),
    doRead(r)
{
    agentStart();
}
BufferAgent::~BufferAgent()
{
    agentStop();
}

int BufferAgent::onOpen(std::string path, ffi_type ffi)
{
    unique_lock guard(m_loopMutex);
    m_cacheMap.erase(ffi->fh);

    buffer_ptr lCache(new LockableCache());
    lCache->fileName = path;
    lCache->buffer = newFileCache();
    lCache->ffi = *ffi;

    m_cacheMap[ffi->fh] = lCache;

    return 0;
}

int BufferAgent::onWrite(std::string path, const std::string &buf, size_t size, off_t offset, ffi_type ffi)
{
    unique_lock guard(m_loopMutex);
        buffer_ptr wrapper = m_cacheMap[ffi->fh];
    guard.unlock();

    unique_lock buff_guard(wrapper->mutex);

    while(wrapper->buffer->byteSize() > 1024 * 1024 * 10) {
        guard.lock();
            m_jobQueue.push_front(ffi->fh);
            m_loopCond.notify_all();
        guard.unlock();
        wrapper->cond.wait(buff_guard);
    }

    wrapper->buffer->writeData(offset, buf);

    guard.lock();
    m_jobQueue.push_back(ffi->fh);
    m_loopCond.notify_all();

    return size;
}

int BufferAgent::onRead(std::string path, std::string &buf, size_t size, off_t offset, ffi_type ffi)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_loopMutex);
    return EOPNOTSUPP;
}

int BufferAgent::onFlush(std::string path, ffi_type ffi)
{
    unique_lock guard(m_loopMutex);
        buffer_ptr wrapper = m_cacheMap[ffi->fh];
    guard.unlock();

    unique_lock buff_guard(wrapper->mutex);

    while(wrapper->buffer->blockCount() > 0)
    {
        block_ptr block = wrapper->buffer->removeOldestBlock();
        int res = doWrite(wrapper->fileName, block->data, block->data.size(), block->offset, &wrapper->ffi);
        if(res < 0)
        {
            while(wrapper->buffer->blockCount() > 0)
            {
                (void) wrapper->buffer->removeOldestBlock();
            }
            return res;
        }
    }

    guard.lock();
    m_jobQueue.remove(ffi->fh);

    return 0;
}

int BufferAgent::onRelease(std::string path, ffi_type ffi)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_loopMutex);
    m_cacheMap.erase(ffi->fh);

    return 0;
}

void BufferAgent::agentStart(int worker_count)
{
    m_workers.clear();
    m_agentActive = true;

    while(worker_count--)
    {
        m_workers.push_back(shared_ptr<thread>(new thread(bind(&BufferAgent::workerLoop, this))));
    }
}

void BufferAgent::agentStop()
{
    m_agentActive = false;
    m_loopCond.notify_all();
    while(m_workers.size() > 0)
    {
        m_workers.back()->join();
        m_workers.pop_back();
    }
}

void BufferAgent::workerLoop()
{
    unique_lock guard(m_loopMutex);
    while(m_agentActive)
    {
        while(m_jobQueue.empty() && m_agentActive)
            m_loopCond.wait(guard);

        if(!m_agentActive)
            return;

        fd_type file = m_jobQueue.front();
        buffer_ptr wrapper = m_cacheMap[file];
        m_jobQueue.pop_front();
        m_loopCond.notify_all();

        if(!wrapper)
            continue;

        {
            guard.unlock();
            block_ptr block;
            {
                unique_lock buff_guard(wrapper->mutex);
                block = wrapper->buffer->removeOldestBlock();
            }

            if(block)
            {
                int res = doWrite(wrapper->fileName, block->data, block->data.size(), block->offset, &wrapper->ffi);

                wrapper->cond.notify_all();
            }

            guard.lock();
            if(wrapper->buffer->blockCount() > 0)
            {
                m_jobQueue.push_back(file);
            }

        }

    }
}

boost::shared_ptr<FileCache> BufferAgent::newFileCache()
{
    return boost::shared_ptr<FileCache>(new FileCache(500 * 1024));
}

} // namespace helpers
} // namespace veil

<commit_msg>VFS-292: debug<commit_after>#include "bufferAgent.h"

using boost::shared_ptr;
using boost::thread;
using boost::bind;

using std::string;

namespace veil {
namespace helpers {

BufferAgent::BufferAgent(write_fun w, read_fun r)
  : m_agentActive(false),
    doWrite(w),
    doRead(r)
{
    agentStart();
}
BufferAgent::~BufferAgent()
{
    agentStop();
}

int BufferAgent::onOpen(std::string path, ffi_type ffi)
{
    unique_lock guard(m_loopMutex);
    m_cacheMap.erase(ffi->fh);

    buffer_ptr lCache(new LockableCache());
    lCache->fileName = path;
    lCache->buffer = newFileCache();
    lCache->ffi = *ffi;

    m_cacheMap[ffi->fh] = lCache;

    return 0;
}

int BufferAgent::onWrite(std::string path, const std::string &buf, size_t size, off_t offset, ffi_type ffi)
{
    unique_lock guard(m_loopMutex);
        buffer_ptr wrapper = m_cacheMap[ffi->fh];
    guard.unlock();

    unique_lock buff_guard(wrapper->mutex);

    while(wrapper->buffer->byteSize() > 1024 * 1024 * 64) {
        guard.lock();
            m_jobQueue.push_front(ffi->fh);
            m_loopCond.notify_all();
        guard.unlock();
        wrapper->cond.wait(buff_guard);
    }

    wrapper->buffer->writeData(offset, buf);

    guard.lock();
    m_jobQueue.push_back(ffi->fh);
    m_loopCond.notify_all();

    return size;
}

int BufferAgent::onRead(std::string path, std::string &buf, size_t size, off_t offset, ffi_type ffi)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_loopMutex);
    return EOPNOTSUPP;
}

int BufferAgent::onFlush(std::string path, ffi_type ffi)
{
    unique_lock guard(m_loopMutex);
        buffer_ptr wrapper = m_cacheMap[ffi->fh];
    guard.unlock();

    unique_lock buff_guard(wrapper->mutex);

    while(wrapper->buffer->blockCount() > 0)
    {
        block_ptr block = wrapper->buffer->removeOldestBlock();
        int res = doWrite(wrapper->fileName, block->data, block->data.size(), block->offset, &wrapper->ffi);
        if(res < 0)
        {
            while(wrapper->buffer->blockCount() > 0)
            {
                (void) wrapper->buffer->removeOldestBlock();
            }
            return res;
        }
    }

    guard.lock();
    m_jobQueue.remove(ffi->fh);

    return 0;
}

int BufferAgent::onRelease(std::string path, ffi_type ffi)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_loopMutex);
    m_cacheMap.erase(ffi->fh);

    return 0;
}

void BufferAgent::agentStart(int worker_count)
{
    m_workers.clear();
    m_agentActive = true;

    while(worker_count--)
    {
        m_workers.push_back(shared_ptr<thread>(new thread(bind(&BufferAgent::workerLoop, this))));
    }
}

void BufferAgent::agentStop()
{
    m_agentActive = false;
    m_loopCond.notify_all();
    while(m_workers.size() > 0)
    {
        m_workers.back()->join();
        m_workers.pop_back();
    }
}

void BufferAgent::workerLoop()
{
    unique_lock guard(m_loopMutex);
    while(m_agentActive)
    {
        while(m_jobQueue.empty() && m_agentActive)
            m_loopCond.wait(guard);

        if(!m_agentActive)
            return;

        fd_type file = m_jobQueue.front();
        buffer_ptr wrapper = m_cacheMap[file];
        m_jobQueue.pop_front();
        m_loopCond.notify_all();

        if(!wrapper)
            continue;

        {
            guard.unlock();
            block_ptr block;
            {
                unique_lock buff_guard(wrapper->mutex);
                block = wrapper->buffer->removeOldestBlock();
            }

            if(block)
            {
                int res = doWrite(wrapper->fileName, block->data, block->data.size(), block->offset, &wrapper->ffi);

                wrapper->cond.notify_all();
            }

            guard.lock();
            if(wrapper->buffer->blockCount() > 0)
            {
                m_jobQueue.push_back(file);
            }

        }

    }
}

boost::shared_ptr<FileCache> BufferAgent::newFileCache()
{
    return boost::shared_ptr<FileCache>(new FileCache(1024 * 1024));
}

} // namespace helpers
} // namespace veil

<|endoftext|>


<commit_before>#include "bufferAgent.h"
#include "helpers/storageHelperFactory.h"
#include "glog/logging.h"

using boost::shared_ptr;
using boost::thread;
using boost::bind;

using std::string;

namespace veil {
namespace helpers {

boost::recursive_mutex BufferAgent::m_bufferSizeMutex;
volatile size_t         BufferAgent::m_rdBufferTotalSize;
volatile size_t         BufferAgent::m_wrBufferTotalSize;
rdbuf_size_mem_t        BufferAgent::m_rdBufferSizeMem;
wrbuf_size_mem_t        BufferAgent::m_wrBufferSizeMem;

BufferAgent::BufferAgent(write_fun w, read_fun r)
  : m_agentActive(false),
    doWrite(w),
    doRead(r)
{
    agentStart(1);
}

BufferAgent::~BufferAgent()
{
    agentStop();
}

void BufferAgent::updateWrBufferSize(fd_type key, size_t size)
{
    unique_lock guard(m_bufferSizeMutex);
    wrbuf_size_mem_t::iterator it = m_wrBufferSizeMem.find(key);

    // If entry for this key doesn't exist, just create one
    if(it == m_wrBufferSizeMem.end()) {
        m_wrBufferSizeMem[key] = size;
        m_rdBufferTotalSize += size;
    } else {
    // If key exists, update total bytes size according to diff between last size and current
        if(size < it->second && (it->second - size) >= m_wrBufferTotalSize) {
            m_wrBufferTotalSize = 0;
        } else {
            m_wrBufferTotalSize += (size - it->second);
        }

        if(size == 0) {
            m_wrBufferSizeMem.erase(key);
        } else {
            m_wrBufferSizeMem[key] = size;
        }
    }
}

void BufferAgent::updateRdBufferSize(std::string key, size_t size)
{
    unique_lock guard(m_bufferSizeMutex);
    rdbuf_size_mem_t::iterator it = m_rdBufferSizeMem.find(key);

    if(it == m_rdBufferSizeMem.end()) {
        m_rdBufferSizeMem[key] = size;
        m_rdBufferTotalSize += size;
    // If key exists, update total bytes size according to diff between last size and current
    } else {
        if(size < it->second && (it->second - size) >= m_rdBufferTotalSize) {
            m_rdBufferTotalSize = 0;
        } else {
            m_rdBufferTotalSize += (size - it->second);
        }

        if(size == 0) {
            m_rdBufferSizeMem.erase(key);
        } else {
            m_rdBufferSizeMem[key] = size;
        }
    }
}

size_t BufferAgent::getWriteBufferSize()
{
    unique_lock guard(m_bufferSizeMutex);
    return m_wrBufferTotalSize;
}

size_t BufferAgent::getReadBufferSize()
{
    unique_lock guard(m_bufferSizeMutex);
    return m_rdBufferTotalSize;
}

int BufferAgent::onOpen(std::string path, ffi_type ffi)
{
    DLOG(INFO) << "BufferAgent::onOpen(" << path << ")";
    // Initialize write buffer's holder
    {
        unique_lock guard(m_wrMutex);
        m_wrCacheMap.erase(ffi->fh);

        write_buffer_ptr lCache(new WriteCache());
        lCache->fileName = path;
        lCache->buffer = newFileCache(true);
        lCache->ffi = *ffi;

        m_wrCacheMap[ffi->fh] = lCache;
    }

    {   // Initialize read buffer's holder
        unique_lock guard(m_rdMutex);
        read_cache_map_t::iterator it;
        if(( it = m_rdCacheMap.find(path) ) != m_rdCacheMap.end()) {
            it->second->openCount++;
        } else {
            read_buffer_ptr lCache(new ReadCache());
            lCache->fileName = path;
            lCache->openCount = 1;
            lCache->ffi = *ffi;
            lCache->buffer = newFileCache(false);

            m_rdCacheMap[path] = lCache;
        }

        // Prefetch first 512B block
        m_rdJobQueue.insert(PrefetchJob(path, 0, 512, ffi->fh));
        m_rdCond.notify_one();
    }

    return 0;
}

int BufferAgent::onWrite(std::string path, const std::string &buf, size_t size, off_t offset, ffi_type ffi)
{
    DLOG(INFO) << "BufferAgent::onWrite(path: " << path << ", size: " << size << ", offset: " << offset <<")";
    unique_lock guard(m_wrMutex);
        write_buffer_ptr wrapper = m_wrCacheMap[ffi->fh];

        // If there was an error while sending cached data, return this error
        if(wrapper->lastError < 0) {
            wrapper->lastError = 0;
            return wrapper->lastError;
        }

    guard.unlock();

    {
        // If memory limit is exceeded, force flush
        if(wrapper->buffer->byteSize() > config::buffers::writeBufferPerFileSizeLimit ||
           getWriteBufferSize() > config::buffers::writeBufferGlobalSizeLimit) {
            DLOG(INFO) << "Write Buffer memory limit exceeded, force flush";
            if(int fRet = onFlush(path, ffi)) {
                return fRet;
            }
        }

        // If memory limit is still exceeded, send the block without using buffer
        if(wrapper->buffer->byteSize() > config::buffers::writeBufferPerFileSizeLimit ||
           getWriteBufferSize() > config::buffers::writeBufferGlobalSizeLimit) {
            return doWrite(path, buf, size, offset, ffi);
        }

        // Save the block in write buffer
        wrapper->buffer->writeData(offset, buf);
        updateWrBufferSize(ffi->fh, wrapper->buffer->byteSize());
    }

    unique_lock buffGuard(wrapper->mutex);
    guard.lock();
    if(!wrapper->opPending)
    {
        // Notify workers if needed
        wrapper->opPending = true;
        m_wrJobQueue.push_back(ffi->fh);
        m_wrCond.notify_one();
    }

    return size;
}

int BufferAgent::onRead(std::string path, std::string &buf, size_t size, off_t offset, ffi_type ffi)
{
    unique_lock guard(m_rdMutex);
        read_buffer_ptr wrapper = m_rdCacheMap[path];
    guard.unlock();

    {
        unique_lock buffGuard(wrapper->mutex);

        wrapper->lastBlock[ffi->fh] = offset;
        wrapper->blockSize = std::min((size_t) config::buffers::preferedBlockSize, (size_t) std::max(size, 2*wrapper->blockSize));
    }

    wrapper->buffer->readData(offset, size, buf);
    updateRdBufferSize(path, wrapper->buffer->byteSize());

    // If cached file block is not complete, read it from server and save to cache
    if(buf.size() < size) {

        string buf2;
        int ret = doRead(path, buf2, size - buf.size(), offset + buf.size(), &wrapper->ffi);
        if(ret < 0)
            return ret;

        wrapper->buffer->writeData(offset + buf.size(), buf2);

        buf += buf2;

        guard.lock();
            m_rdJobQueue.insert(PrefetchJob(wrapper->fileName, offset + buf.size() + config::buffers::preferedBlockSize, wrapper->blockSize, ffi->fh));
        guard.unlock();
    } else {
        string tmp;
        size_t prefSize = std::max(2*size, wrapper->blockSize);
        wrapper->buffer->readData(offset + size, prefSize, tmp);

        if(tmp.size() != prefSize) {
            guard.lock();
                m_rdJobQueue.insert(PrefetchJob(wrapper->fileName, offset + size + tmp.size(), wrapper->blockSize, ffi->fh));
                m_rdJobQueue.insert(PrefetchJob(wrapper->fileName, offset + size + tmp.size() + wrapper->blockSize, wrapper->blockSize, ffi->fh));
            guard.unlock();
        }
    }

    {
        unique_lock buffGuard(wrapper->mutex);
        if(offset + buf.size() > wrapper->endOfFile)
            wrapper->endOfFile = 0;
    }

    m_rdCond.notify_one();

    return buf.size();
}

int BufferAgent::onFlush(std::string path, ffi_type ffi)
{
    unique_lock guard(m_wrMutex);
        write_buffer_ptr wrapper = m_wrCacheMap[ffi->fh];
    guard.unlock();

    unique_lock sendGuard(wrapper->sendMutex);
    unique_lock buff_guard(wrapper->mutex);

    // Send all pending blocks to server
    while(wrapper->buffer->blockCount() > 0)
    {
        block_ptr block = wrapper->buffer->removeOldestBlock();
        uint64_t start = utils::mtime<uint64_t>();
        int res = doWrite(wrapper->fileName, block->data, block->data.size(), block->offset, &wrapper->ffi);
        uint64_t end = utils::mtime<uint64_t>();

        if(res < 0)
        {
            // Skip all blocks after receiving error
            while(wrapper->buffer->blockCount() > 0)
            {
                (void) wrapper->buffer->removeOldestBlock();
            }
            return res;
        } else if(res < block->data.size()) {
            // Send wasn't complete
            block->offset += res;
            block->data = block->data.substr(res);
            wrapper->buffer->insertBlock(*block);
        }
    }

    updateWrBufferSize(ffi->fh, wrapper->buffer->byteSize());

    guard.lock();
    m_wrJobQueue.remove(ffi->fh);

    return 0;
}

int BufferAgent::onRelease(std::string path, ffi_type ffi)
{
    {
        unique_lock guard(m_wrMutex);

        m_wrCacheMap.erase(ffi->fh);
        m_wrJobQueue.remove(ffi->fh);
    }

    {
        unique_lock guard(m_rdMutex);

        read_cache_map_t::iterator it;
        if(( it = m_rdCacheMap.find(path) ) != m_rdCacheMap.end()) {
            it->second->openCount--;
            if(it->second->openCount <= 0) {
                m_rdCacheMap.erase(it);
            }
        }
    }

    return 0;
}

void BufferAgent::agentStart(int worker_count)
{
    m_workers.clear();
    m_agentActive = true;

    while(worker_count--)
    {
        m_workers.push_back(shared_ptr<thread>(new thread(bind(&BufferAgent::writerLoop, this))));
        m_workers.push_back(shared_ptr<thread>(new thread(bind(&BufferAgent::readerLoop, this))));
    }
}

void BufferAgent::agentStop()
{
    m_agentActive = false;
    m_wrCond.notify_all();
    m_rdCond.notify_all();

    while(m_workers.size() > 0)
    {
        m_workers.back()->join();
        m_workers.pop_back();
    }
}

void BufferAgent::readerLoop()
{
    unique_lock guard(m_rdMutex);
    while(m_agentActive)
    {
        while(m_rdJobQueue.empty() && m_agentActive)
            m_rdCond.wait(guard);

        if(!m_agentActive)
            return;

        PrefetchJob job = *m_rdJobQueue.begin();
        read_buffer_ptr wrapper = m_rdCacheMap[job.fileName];
        m_rdJobQueue.erase(m_rdJobQueue.begin());
        m_rdCond.notify_one();

        if(!wrapper || wrapper->lastBlock[job.fh] + config::buffers::preferedBlockSize >= job.offset + job.size || (wrapper->endOfFile > 0 && wrapper->endOfFile <= job.offset))
            continue;

        guard.unlock();

        {

            string buff;
            wrapper->buffer->readData(job.offset, job.size, buff);
            if(buff.size() < job.size)
            {
                string tmp;
                off_t effectiveOffset = job.offset + buff.size();
                int ret = doRead(wrapper->fileName, tmp, job.size, effectiveOffset, &wrapper->ffi);
                LOG(INFO) << "Job: offset: " << job.offset << " size: " << job.size << " ret: " << ret;

                guard.lock();
                unique_lock buffGuard(wrapper->mutex);

                if(ret > 0 && tmp.size() >= ret) {
                    wrapper->buffer->writeData(effectiveOffset, tmp);
                    updateRdBufferSize(job.fileName, wrapper->buffer->byteSize());
                    //m_rdJobQueue.insert(PrefetchJob(job.fileName, effectiveOffset + ret, wrapper->blockSize, job.fh));
                } else if(ret == 0) {
                    wrapper->endOfFile = std::max(wrapper->endOfFile, effectiveOffset);
                }

                wrapper->cond.notify_all();

                guard.unlock();
            }
        }

        guard.lock();
    }
}

void BufferAgent::writerLoop()
{
    unique_lock guard(m_wrMutex);
    while(m_agentActive)
    {
        while(m_wrJobQueue.empty() && m_agentActive)
            m_wrCond.wait(guard);

        if(!m_agentActive)
            return;

        std::multiset<PrefetchJob, PrefetchJobCompare>::iterator it;

        fd_type file = m_wrJobQueue.front();
        write_buffer_ptr wrapper = m_wrCacheMap[file];
        m_wrJobQueue.pop_front();
        m_wrCond.notify_one();

        if(!wrapper)
            continue;

        guard.unlock();

        {
            unique_lock sendGuard(wrapper->sendMutex);

            block_ptr block;
            {
                unique_lock buff_guard(wrapper->mutex);
                block = wrapper->buffer->removeOldestBlock();
            }

            int writeRes;
            if(block)
            {
                uint64_t start = utils::mtime<uint64_t>();
                writeRes = doWrite(wrapper->fileName, block->data, block->data.size(), block->offset, &wrapper->ffi);
                uint64_t end = utils::mtime<uint64_t>();

                //LOG(INFO) << "Roundtrip: " << (end - start) << " for " << block->data.size() << " bytes";

                wrapper->cond.notify_all();
            }

            {
                unique_lock buff_guard(wrapper->mutex);
                guard.lock();

                if(block)
                {
                    if(writeRes < 0)
                    {
                        while(wrapper->buffer->blockCount() > 0)
                        {
                            wrapper->buffer->removeOldestBlock();
                        }

                        wrapper->lastError = writeRes;
                    }
                    else if(writeRes < block->data.size())
                    {
                        block->offset += writeRes;
                        block->data = block->data.substr(writeRes);
                        wrapper->buffer->insertBlock(*block);
                    }
                }

                if(wrapper->buffer->blockCount() > 0)
                {
                    m_wrJobQueue.push_back(file);
                }
                else
                {
                    wrapper->opPending = false;
                }

                updateWrBufferSize(file, wrapper->buffer->byteSize());
            }
        }

        wrapper->cond.notify_all();
    }
}

boost::shared_ptr<FileCache> BufferAgent::newFileCache(bool isBuffer)
{
    return boost::shared_ptr<FileCache>(new FileCache(config::buffers::preferedBlockSize, isBuffer));
}

} // namespace helpers
} // namespace veil

<commit_msg>VFS-292: docs<commit_after>#include "bufferAgent.h"
#include "helpers/storageHelperFactory.h"
#include "glog/logging.h"

using boost::shared_ptr;
using boost::thread;
using boost::bind;

using std::string;

namespace veil {
namespace helpers {

boost::recursive_mutex BufferAgent::m_bufferSizeMutex;
volatile size_t         BufferAgent::m_rdBufferTotalSize;
volatile size_t         BufferAgent::m_wrBufferTotalSize;
rdbuf_size_mem_t        BufferAgent::m_rdBufferSizeMem;
wrbuf_size_mem_t        BufferAgent::m_wrBufferSizeMem;

BufferAgent::BufferAgent(write_fun w, read_fun r)
  : m_agentActive(false),
    doWrite(w),
    doRead(r)
{
    agentStart(1);
}

BufferAgent::~BufferAgent()
{
    agentStop();
}

void BufferAgent::updateWrBufferSize(fd_type key, size_t size)
{
    unique_lock guard(m_bufferSizeMutex);
    wrbuf_size_mem_t::iterator it = m_wrBufferSizeMem.find(key);

    // If entry for this key doesn't exist, just create one
    if(it == m_wrBufferSizeMem.end()) {
        m_wrBufferSizeMem[key] = size;
        m_rdBufferTotalSize += size;
    } else {
    // If key exists, update total bytes size according to diff between last size and current
        if(size < it->second && (it->second - size) >= m_wrBufferTotalSize) {
            m_wrBufferTotalSize = 0;
        } else {
            m_wrBufferTotalSize += (size - it->second);
        }

        if(size == 0) {
            m_wrBufferSizeMem.erase(key);
        } else {
            m_wrBufferSizeMem[key] = size;
        }
    }
}

void BufferAgent::updateRdBufferSize(std::string key, size_t size)
{
    unique_lock guard(m_bufferSizeMutex);
    rdbuf_size_mem_t::iterator it = m_rdBufferSizeMem.find(key);

    if(it == m_rdBufferSizeMem.end()) {
        m_rdBufferSizeMem[key] = size;
        m_rdBufferTotalSize += size;
    // If key exists, update total bytes size according to diff between last size and current
    } else {
        if(size < it->second && (it->second - size) >= m_rdBufferTotalSize) {
            m_rdBufferTotalSize = 0;
        } else {
            m_rdBufferTotalSize += (size - it->second);
        }

        if(size == 0) {
            m_rdBufferSizeMem.erase(key);
        } else {
            m_rdBufferSizeMem[key] = size;
        }
    }
}

size_t BufferAgent::getWriteBufferSize()
{
    unique_lock guard(m_bufferSizeMutex);
    return m_wrBufferTotalSize;
}

size_t BufferAgent::getReadBufferSize()
{
    unique_lock guard(m_bufferSizeMutex);
    return m_rdBufferTotalSize;
}

int BufferAgent::onOpen(std::string path, ffi_type ffi)
{
    DLOG(INFO) << "BufferAgent::onOpen(" << path << ")";
    // Initialize write buffer's holder
    {
        unique_lock guard(m_wrMutex);
        m_wrCacheMap.erase(ffi->fh);

        write_buffer_ptr lCache(new WriteCache());
        lCache->fileName = path;
        lCache->buffer = newFileCache(true);
        lCache->ffi = *ffi;

        m_wrCacheMap[ffi->fh] = lCache;
    }

    {   // Initialize read buffer's holder
        unique_lock guard(m_rdMutex);
        read_cache_map_t::iterator it;
        if(( it = m_rdCacheMap.find(path) ) != m_rdCacheMap.end()) {
            it->second->openCount++;
        } else {
            read_buffer_ptr lCache(new ReadCache());
            lCache->fileName = path;
            lCache->openCount = 1;
            lCache->ffi = *ffi;
            lCache->buffer = newFileCache(false);

            m_rdCacheMap[path] = lCache;
        }

        // Prefetch first 512B block
        m_rdJobQueue.insert(PrefetchJob(path, 0, 512, ffi->fh));
        m_rdCond.notify_one();
    }

    return 0;
}

int BufferAgent::onWrite(std::string path, const std::string &buf, size_t size, off_t offset, ffi_type ffi)
{
    DLOG(INFO) << "BufferAgent::onWrite(path: " << path << ", size: " << size << ", offset: " << offset <<")";
    unique_lock guard(m_wrMutex);
        write_buffer_ptr wrapper = m_wrCacheMap[ffi->fh];

        // If there was an error while sending cached data, return this error
        if(wrapper->lastError < 0) {
            wrapper->lastError = 0;
            return wrapper->lastError;
        }

    guard.unlock();

    {
        // If memory limit is exceeded, force flush
        if(wrapper->buffer->byteSize() > config::buffers::writeBufferPerFileSizeLimit ||
           getWriteBufferSize() > config::buffers::writeBufferGlobalSizeLimit) {
            DLOG(INFO) << "Write Buffer memory limit exceeded, force flush";
            if(int fRet = onFlush(path, ffi)) {
                return fRet;
            }
        }

        // If memory limit is still exceeded, send the block without using buffer
        if(wrapper->buffer->byteSize() > config::buffers::writeBufferPerFileSizeLimit ||
           getWriteBufferSize() > config::buffers::writeBufferGlobalSizeLimit) {
            return doWrite(path, buf, size, offset, ffi);
        }

        // Save the block in write buffer
        wrapper->buffer->writeData(offset, buf);
        updateWrBufferSize(ffi->fh, wrapper->buffer->byteSize());
    }

    unique_lock buffGuard(wrapper->mutex);
    guard.lock();
    if(!wrapper->opPending)
    {
        // Notify workers if needed
        wrapper->opPending = true;
        m_wrJobQueue.push_back(ffi->fh);
        m_wrCond.notify_one();
    }

    return size;
}

int BufferAgent::onRead(std::string path, std::string &buf, size_t size, off_t offset, ffi_type ffi)
{
    unique_lock guard(m_rdMutex);
        read_buffer_ptr wrapper = m_rdCacheMap[path];
    guard.unlock();

    {
        unique_lock buffGuard(wrapper->mutex);

        wrapper->lastBlock[ffi->fh] = offset;
        wrapper->blockSize = std::min((size_t) config::buffers::preferedBlockSize, (size_t) std::max(size, 2*wrapper->blockSize));
    }

    wrapper->buffer->readData(offset, size, buf);
    updateRdBufferSize(path, wrapper->buffer->byteSize());

    // If cached file block is not complete, read it from server and save to cache
    if(buf.size() < size) {

        string buf2;
        int ret = doRead(path, buf2, size - buf.size(), offset + buf.size(), &wrapper->ffi);
        if(ret < 0)
            return ret;

        wrapper->buffer->writeData(offset + buf.size(), buf2);

        buf += buf2;

        guard.lock();
            m_rdJobQueue.insert(PrefetchJob(wrapper->fileName, offset + buf.size() + config::buffers::preferedBlockSize, wrapper->blockSize, ffi->fh));
        guard.unlock();
    } else {
        string tmp;
        size_t prefSize = std::max(2*size, wrapper->blockSize);
        wrapper->buffer->readData(offset + size, prefSize, tmp);

        if(tmp.size() != prefSize) {
            guard.lock();
                m_rdJobQueue.insert(PrefetchJob(wrapper->fileName, offset + size + tmp.size(), wrapper->blockSize, ffi->fh));
                m_rdJobQueue.insert(PrefetchJob(wrapper->fileName, offset + size + tmp.size() + wrapper->blockSize, wrapper->blockSize, ffi->fh));
            guard.unlock();
        }
    }

    {
        unique_lock buffGuard(wrapper->mutex);
        if(offset + buf.size() > wrapper->endOfFile)
            wrapper->endOfFile = 0;
    }

    m_rdCond.notify_one();

    return buf.size();
}

int BufferAgent::onFlush(std::string path, ffi_type ffi)
{
    unique_lock guard(m_wrMutex);
        write_buffer_ptr wrapper = m_wrCacheMap[ffi->fh];
    guard.unlock();

    unique_lock sendGuard(wrapper->sendMutex);
    unique_lock buff_guard(wrapper->mutex);

    // Send all pending blocks to server
    while(wrapper->buffer->blockCount() > 0)
    {
        block_ptr block = wrapper->buffer->removeOldestBlock();
        uint64_t start = utils::mtime<uint64_t>();
        int res = doWrite(wrapper->fileName, block->data, block->data.size(), block->offset, &wrapper->ffi);
        uint64_t end = utils::mtime<uint64_t>();

        if(res < 0)
        {
            // Skip all blocks after receiving error
            while(wrapper->buffer->blockCount() > 0)
            {
                (void) wrapper->buffer->removeOldestBlock();
            }
            return res;
        } else if(res < block->data.size()) {
            // Send wasn't complete
            block->offset += res;
            block->data = block->data.substr(res);
            wrapper->buffer->insertBlock(*block);
        }
    }

    updateWrBufferSize(ffi->fh, wrapper->buffer->byteSize());

    guard.lock();
    m_wrJobQueue.remove(ffi->fh);

    return 0;
}

int BufferAgent::onRelease(std::string path, ffi_type ffi)
{
    {
        unique_lock guard(m_wrMutex);

        m_wrCacheMap.erase(ffi->fh);
        m_wrJobQueue.remove(ffi->fh);
    }

    {
        unique_lock guard(m_rdMutex);

        read_cache_map_t::iterator it;
        if(( it = m_rdCacheMap.find(path) ) != m_rdCacheMap.end()) {
            it->second->openCount--;
            if(it->second->openCount <= 0) {
                m_rdCacheMap.erase(it);
            }
        }
    }

    return 0;
}

void BufferAgent::agentStart(int worker_count)
{
    m_workers.clear();
    m_agentActive = true;

    while(worker_count--)
    {
        m_workers.push_back(shared_ptr<thread>(new thread(bind(&BufferAgent::writerLoop, this))));
        m_workers.push_back(shared_ptr<thread>(new thread(bind(&BufferAgent::readerLoop, this))));
    }
}

void BufferAgent::agentStop()
{
    m_agentActive = false;
    m_wrCond.notify_all();
    m_rdCond.notify_all();

    while(m_workers.size() > 0)
    {
        m_workers.back()->join();
        m_workers.pop_back();
    }
}

void BufferAgent::readerLoop()
{
    unique_lock guard(m_rdMutex);
    while(m_agentActive)
    {
        while(m_rdJobQueue.empty() && m_agentActive)
            m_rdCond.wait(guard);

        if(!m_agentActive)
            return;

        PrefetchJob job = *m_rdJobQueue.begin();
        read_buffer_ptr wrapper = m_rdCacheMap[job.fileName];
        m_rdJobQueue.erase(m_rdJobQueue.begin());
        m_rdCond.notify_one();

        if(!wrapper || wrapper->lastBlock[job.fh] + config::buffers::preferedBlockSize >= job.offset + job.size || (wrapper->endOfFile > 0 && wrapper->endOfFile <= job.offset))
            continue;

        guard.unlock();

        {

            string buff;
            wrapper->buffer->readData(job.offset, job.size, buff);
            if(buff.size() < job.size)
            {
                string tmp;
                off_t effectiveOffset = job.offset + buff.size();
                int ret = doRead(wrapper->fileName, tmp, job.size, effectiveOffset, &wrapper->ffi);
                LOG(INFO) << "Job: offset: " << job.offset << " size: " << job.size << " ret: " << ret;

                guard.lock();
                unique_lock buffGuard(wrapper->mutex);

                if(ret > 0 && tmp.size() >= ret) {
                    wrapper->buffer->writeData(effectiveOffset, tmp);
                    updateRdBufferSize(job.fileName, wrapper->buffer->byteSize());
                    m_rdJobQueue.insert(PrefetchJob(job.fileName, effectiveOffset + ret, wrapper->blockSize, job.fh));
                } else if(ret == 0) {
                    wrapper->endOfFile = std::max(wrapper->endOfFile, effectiveOffset);
                }

                wrapper->cond.notify_all();

                guard.unlock();
            }
        }

        guard.lock();
    }
}

void BufferAgent::writerLoop()
{
    unique_lock guard(m_wrMutex);
    while(m_agentActive)
    {
        while(m_wrJobQueue.empty() && m_agentActive)
            m_wrCond.wait(guard);

        if(!m_agentActive)
            return;

        std::multiset<PrefetchJob, PrefetchJobCompare>::iterator it;

        fd_type file = m_wrJobQueue.front();
        write_buffer_ptr wrapper = m_wrCacheMap[file];
        m_wrJobQueue.pop_front();
        m_wrCond.notify_one();

        if(!wrapper)
            continue;

        guard.unlock();

        {
            unique_lock sendGuard(wrapper->sendMutex);

            block_ptr block;
            {
                unique_lock buff_guard(wrapper->mutex);
                block = wrapper->buffer->removeOldestBlock();
            }

            int writeRes;
            if(block)
            {
                uint64_t start = utils::mtime<uint64_t>();
                writeRes = doWrite(wrapper->fileName, block->data, block->data.size(), block->offset, &wrapper->ffi);
                uint64_t end = utils::mtime<uint64_t>();

                //LOG(INFO) << "Roundtrip: " << (end - start) << " for " << block->data.size() << " bytes";

                wrapper->cond.notify_all();
            }

            {
                unique_lock buff_guard(wrapper->mutex);
                guard.lock();

                if(block)
                {
                    if(writeRes < 0)
                    {
                        while(wrapper->buffer->blockCount() > 0)
                        {
                            wrapper->buffer->removeOldestBlock();
                        }

                        wrapper->lastError = writeRes;
                    }
                    else if(writeRes < block->data.size())
                    {
                        block->offset += writeRes;
                        block->data = block->data.substr(writeRes);
                        wrapper->buffer->insertBlock(*block);
                    }
                }

                if(wrapper->buffer->blockCount() > 0)
                {
                    m_wrJobQueue.push_back(file);
                }
                else
                {
                    wrapper->opPending = false;
                }

                updateWrBufferSize(file, wrapper->buffer->byteSize());
            }
        }

        wrapper->cond.notify_all();
    }
}

boost::shared_ptr<FileCache> BufferAgent::newFileCache(bool isBuffer)
{
    return boost::shared_ptr<FileCache>(new FileCache(config::buffers::preferedBlockSize, isBuffer));
}

} // namespace helpers
} // namespace veil

<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 * Copyright (C) 2005 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/opBuffer.h>

#ifndef DEBUG
#define DEBUG 0
#endif

namespace geos {

SubgraphDepthLocater::SubgraphDepthLocater(vector<BufferSubgraph*> *nsg):
	seg(new LineSegment()),
	subgraphs(nsg)
{
	//seg=new LineSegment();
	//cga=new RobustCGAlgorithms();
	//subgraphs=newSubgraphs;
}

SubgraphDepthLocater::~SubgraphDepthLocater(){
	delete seg;
	//delete cga;
}

int
SubgraphDepthLocater::getDepth(Coordinate &p)
{
	vector<DepthSegment*> *stabbedSegments=findStabbedSegments(p);
	// if no segments on stabbing line subgraph must be outside all others->
	if ((int)stabbedSegments->size()==0)
	{
		delete stabbedSegments;
		return 0;
	}
	sort(stabbedSegments->begin(),stabbedSegments->end(),DepthSegmentLT);
	DepthSegment *ds=(*stabbedSegments)[0];
	int ret = ds->leftDepth;
#if DEBUG
	cerr<<"SubgraphDepthLocater::getDepth("<<p.toString()<<"): "<<ret<<endl;
#endif

	vector<DepthSegment *>::iterator it;
	for (it=stabbedSegments->begin(); it != stabbedSegments->end(); it++)
		delete *it;
	delete stabbedSegments;

	return ret;
}

/**
* Finds all non-horizontal segments intersecting the stabbing line->
* The stabbing line is the ray to the right of stabbingRayLeftPt->
*
* @param stabbingRayLeftPt the left-hand origin of the stabbing line
* @return a List of {@link DepthSegments} intersecting the stabbing line
*/
vector<DepthSegment*>* SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt){
	vector<DepthSegment*> *stabbedSegments=new vector<DepthSegment*>();
	for (int i=0;i<(int)subgraphs->size();i++) {
		BufferSubgraph *bsg=(*subgraphs)[i];
		findStabbedSegments(stabbingRayLeftPt, bsg->getDirectedEdges(), stabbedSegments);
	}
	return stabbedSegments;
}

/**
* Finds all non-horizontal segments intersecting the stabbing line
* in the list of dirEdges->
* The stabbing line is the ray to the right of stabbingRayLeftPt->
*
* @param stabbingRayLeftPt the left-hand origin of the stabbing line
* @param stabbedSegments the current list of {@link DepthSegments} intersecting the stabbing line
*/
void SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,vector<DirectedEdge*> *dirEdges,vector<DepthSegment*> *stabbedSegments){
	/**
	* Check all forward DirectedEdges only->  This is still general,
	* because each Edge has a forward DirectedEdge->
	*/
	for(int i=0;i<(int)dirEdges->size();i++) {
		DirectedEdge *de=(*dirEdges)[i];
		if (!de->isForward())
			continue;
		findStabbedSegments(stabbingRayLeftPt, de, stabbedSegments);
	}
}

/**
 * Finds all non-horizontal segments intersecting the stabbing line
 * in the input dirEdge->
 * The stabbing line is the ray to the right of stabbingRayLeftPt->
 *
 * @param stabbingRayLeftPt the left-hand origin of the stabbing line
 * @param stabbedSegments the current list of DepthSegments
 * intersecting the stabbing line
 */
void
SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,DirectedEdge *dirEdge,vector<DepthSegment*> *stabbedSegments)
{
	const CoordinateSequence *pts=dirEdge->getEdge()->getCoordinates();

	for (int i=0; i<pts->getSize()-1; i++) {
		//seg->p0=pts->getAt(i);
		//seg->p1=pts->getAt(i + 1);

		const Coordinate *low=&(pts->getAt(i));
		const Coordinate *high=&(pts->getAt(i+1));
		const Coordinate *swap=NULL;

#if DEBUG
	cerr<<" SubgraphDepthLocater::findStabbedSegments: segment "<<i<<" ("<<seg->toString()<<") ";
#endif

//		// ensure segment always points upwards
//		//if (seg->p0.y > seg->p1.y)
//		{
//			seg->reverse();
//#if DEBUG
//			cerr<<" reverse ("<<seg->toString()<<") ";
//#endif
//		}

		// skip segment if it is left of the stabbing line
		//double maxx=max(seg->p0.x, seg->p1.x);
		double maxx=max(low->x, high->x);
		if (maxx < stabbingRayLeftPt.x)
		{
#if DEBUG
			cerr<<" segment is left to stabbing line, skipping "<<endl;
#endif
			continue;
		}

		// skip horizontal segments (there will be a non-horizontal
		// one carrying the same depth info
		//if (seg->isHorizontal())
		if (low->y == high->y)
		{
#if DEBUG
			cerr<<" segment is horizontal, skipping "<<endl;
#endif
			continue;
		}

		// skip if segment is above or below stabbing line
		//if (stabbingRayLeftPt.y < seg->p0.y ||
			//stabbingRayLeftPt.y > seg->p1.y)
		if (stabbingRayLeftPt.y < low->y ||
			stabbingRayLeftPt.y > high->y)
		{
#if DEBUG
			cerr<<" segment above or below stabbing line, skipping "<<endl;
#endif
			continue;
		}

		// skip if stabbing ray is right of the segment
		//if (CGAlgorithms::computeOrientation(seg->p0, seg->p1,
		if (CGAlgorithms::computeOrientation(*low, *high,
				stabbingRayLeftPt)==CGAlgorithms::RIGHT)
		{
#if DEBUG
			cerr<<" stabbing ray right of segment, skipping"<<endl;
#endif
			continue;
		}

//		// stabbing line cuts this segment, so record it
//		int depth=dirEdge->getDepth(Position::LEFT);
//		// if segment direction was flipped, use RHS depth instead
//		if (! (seg->p0==pts->getAt(i)))
//			depth=dirEdge->getDepth(Position::RIGHT);
		int depth = swap ?
			dirEdge->getDepth(Position::LEFT)
			:
			dirEdge->getDepth(Position::RIGHT);

#if DEBUG
	cerr<<" depth: "<<depth<<endl;
#endif
		seg->p0 = *low;
		seg->p1 = *high;
		DepthSegment *ds=new DepthSegment(seg, depth);
		stabbedSegments->push_back(ds);
	}
}

DepthSegment::DepthSegment(LineSegment *seg, int depth){
	// input seg is assumed to be normalized
	upwardSeg=new LineSegment(*seg);
	//upwardSeg->normalize();
	leftDepth=depth;
}

DepthSegment::~DepthSegment(){
	delete upwardSeg;
}
/**
* Defines a comparision operation on DepthSegments
* which orders them left to right
*
*

* DS1 < DS2   if   DS1->seg is left of DS2->seg
* DS1 > DS2   if   DS1->seg is right of DS2->seg
*

*
* @param obj
* @return
*/
int DepthSegment::compareTo(void* obj){
	DepthSegment *other=(DepthSegment*) obj;
	/**
	* try and compute a determinate orientation for the segments->
	* Test returns 1 if other is left of this (i->e-> this > other)
	*/
	int orientIndex=upwardSeg->orientationIndex(other->upwardSeg);
	/**
	* If comparison between this and other is indeterminate,
	* try the opposite call order->
	* orientationIndex value is 1 if this is left of other,
	* so have to flip sign to get proper comparison value of
	* -1 if this is leftmost
	*/
	if (orientIndex==0)
		orientIndex=-1 * other->upwardSeg->orientationIndex(upwardSeg);
	// if orientation is determinate, return it
	if (orientIndex != 0)
		return orientIndex;
	// otherwise, segs must be collinear - sort based on minimum X value
	return compareX(upwardSeg, other->upwardSeg);
}

/**
* Compare two collinear segments for left-most ordering->
* If segs are vertical, use vertical ordering for comparison->
* If segs are equal, return 0->
* Segments are assumed to be directed so that the second coordinate is >= to the first
* (e->g-> up and to the right)->
*
* @param seg0 a segment to compare
* @param seg1 a segment to compare
* @return
*/
int DepthSegment::compareX(LineSegment *seg0, LineSegment *seg1){
	int compare0=seg0->p0.compareTo(seg1->p0);
	if (compare0!=0)
		return compare0;
	return seg0->p1.compareTo(seg1->p1);

}

bool DepthSegmentLT(DepthSegment *first, DepthSegment *second) {
	if (first->compareTo(second)<0)
		return true;
	else
		return false;
}

} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.11  2005/06/27 21:58:31  strk
 * Bugfix in DepthSegmentLT as suggested by Graeme Hiebert
 *
 * Revision 1.10  2005/06/27 21:24:54  strk
 * Fixed bug just-introduced with optimization.
 *
 * Revision 1.9  2005/06/27 21:21:21  strk
 * Reduced Coordinate copies due to LineSegment overuse
 *
 * Revision 1.8  2005/05/23 15:13:00  strk
 * Added debugging output
 *
 * Revision 1.7  2005/05/20 16:15:41  strk
 * Code cleanups
 *
 * Revision 1.6  2005/05/19 10:29:28  strk
 * Removed some CGAlgorithms instances substituting them with direct calls
 * to the static functions. Interfaces accepting CGAlgorithms pointers kept
 * for backward compatibility but modified to make the argument optional.
 * Fixed a small memory leak in OffsetCurveBuilder::getRingCurve.
 * Inlined some smaller functions encountered during bug hunting.
 * Updated Copyright notices in the touched files.
 *
 * Revision 1.5  2004/07/08 19:34:49  strk
 * Mirrored JTS interface of CoordinateSequence, factory and
 * default implementations.
 * Added DefaultCoordinateSequenceFactory::instance() function.
 *
 * Revision 1.4  2004/07/02 13:28:28  strk
 * Fixed all #include lines to reflect headers layout change.
 * Added client application build tips in README.
 *
 * Revision 1.3  2004/05/05 12:29:44  strk
 * memleak fixed in ::getDepth
 *
 * Revision 1.2  2004/05/03 22:56:44  strk
 * leaks fixed, exception specification omitted.
 *
 * Revision 1.1  2004/04/10 08:40:01  ybychkov
 * "operation/buffer" upgraded to JTS 1.4
 *
 *
 **********************************************************************/

<commit_msg>Fixed a bug introduced by LineSegment skip - made LineSegment skip a compile-time optione<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 * Copyright (C) 2005 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/opBuffer.h>

#ifndef DEBUG
#define DEBUG 0
#endif

namespace geos {

SubgraphDepthLocater::SubgraphDepthLocater(vector<BufferSubgraph*> *nsg):
	seg(new LineSegment()),
	subgraphs(nsg)
{
	//seg=new LineSegment();
	//cga=new RobustCGAlgorithms();
	//subgraphs=newSubgraphs;
}

SubgraphDepthLocater::~SubgraphDepthLocater(){
	delete seg;
	//delete cga;
}

int
SubgraphDepthLocater::getDepth(Coordinate &p)
{
	vector<DepthSegment*> *stabbedSegments=findStabbedSegments(p);
	// if no segments on stabbing line subgraph must be outside all others->
	if ((int)stabbedSegments->size()==0)
	{
		delete stabbedSegments;
		return 0;
	}
	sort(stabbedSegments->begin(),stabbedSegments->end(),DepthSegmentLT);
	DepthSegment *ds=(*stabbedSegments)[0];
	int ret = ds->leftDepth;
#if DEBUG
	cerr<<"SubgraphDepthLocater::getDepth("<<p.toString()<<"): "<<ret<<endl;
#endif

	vector<DepthSegment *>::iterator it;
	for (it=stabbedSegments->begin(); it != stabbedSegments->end(); it++)
		delete *it;
	delete stabbedSegments;

	return ret;
}

/**
* Finds all non-horizontal segments intersecting the stabbing line->
* The stabbing line is the ray to the right of stabbingRayLeftPt->
*
* @param stabbingRayLeftPt the left-hand origin of the stabbing line
* @return a List of {@link DepthSegments} intersecting the stabbing line
*/
vector<DepthSegment*>* SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt){
	vector<DepthSegment*> *stabbedSegments=new vector<DepthSegment*>();
	for (int i=0;i<(int)subgraphs->size();i++) {
		BufferSubgraph *bsg=(*subgraphs)[i];
		findStabbedSegments(stabbingRayLeftPt, bsg->getDirectedEdges(), stabbedSegments);
	}
	return stabbedSegments;
}

/**
* Finds all non-horizontal segments intersecting the stabbing line
* in the list of dirEdges->
* The stabbing line is the ray to the right of stabbingRayLeftPt->
*
* @param stabbingRayLeftPt the left-hand origin of the stabbing line
* @param stabbedSegments the current list of {@link DepthSegments} intersecting the stabbing line
*/
void SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,vector<DirectedEdge*> *dirEdges,vector<DepthSegment*> *stabbedSegments){
	/**
	* Check all forward DirectedEdges only->  This is still general,
	* because each Edge has a forward DirectedEdge->
	*/
	for(int i=0;i<(int)dirEdges->size();i++) {
		DirectedEdge *de=(*dirEdges)[i];
		if (!de->isForward())
			continue;
		findStabbedSegments(stabbingRayLeftPt, de, stabbedSegments);
	}
}

/**
 * Finds all non-horizontal segments intersecting the stabbing line
 * in the input dirEdge->
 * The stabbing line is the ray to the right of stabbingRayLeftPt->
 *
 * @param stabbingRayLeftPt the left-hand origin of the stabbing line
 * @param stabbedSegments the current list of DepthSegments
 * intersecting the stabbing line
 */
void
SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,DirectedEdge *dirEdge,vector<DepthSegment*> *stabbedSegments)
{
	const CoordinateSequence *pts=dirEdge->getEdge()->getCoordinates();

// It seems that LineSegment is *very* slow... undef this
// to see yourself
#define SKIP_LS 1

	for (int i=0; i<pts->getSize()-1; i++) {
#ifndef SKIP_LS
		seg->p0=pts->getAt(i);
		seg->p1=pts->getAt(i + 1);
#else

		const Coordinate *low=&(pts->getAt(i));
		const Coordinate *high=&(pts->getAt(i+1));
		const Coordinate *swap=NULL;

#endif

#if DEBUG
	cerr<<" SubgraphDepthLocater::findStabbedSegments: segment "<<i<<" ("<<seg->toString()<<") ";
#endif

#ifndef SKIP_LS
		// ensure segment always points upwards
		//if (seg->p0.y > seg->p1.y)
		{
			seg->reverse();
#if DEBUG
			cerr<<" reverse ("<<seg->toString()<<") ";
#endif
		}
#else
		if (low->y > high->y)
		{
			swap=low;
			low=high;
			high=swap;
		}
#endif

		// skip segment if it is left of the stabbing line
		// skip if segment is above or below stabbing line
#ifndef SKIP_LS
		double maxx=max(seg->p0.x, seg->p1.x);
#else
		double maxx=max(low->x, high->x);
#endif
		if (maxx < stabbingRayLeftPt.x)
		{
#if DEBUG
			cerr<<" segment is left to stabbing line, skipping "<<endl;
#endif
			continue;
		}

		// skip horizontal segments (there will be a non-horizontal
		// one carrying the same depth info
#ifndef SKIP_LS
		if (seg->isHorizontal())
#else
		if (low->y == high->y)
#endif
		{
#if DEBUG
			cerr<<" segment is horizontal, skipping "<<endl;
#endif
			continue;
		}

		// skip if segment is above or below stabbing line
#ifndef SKIP_LS
		if (stabbingRayLeftPt.y < seg->p0.y ||
			stabbingRayLeftPt.y > seg->p1.y)
#else
		if (stabbingRayLeftPt.y < low->y ||
			stabbingRayLeftPt.y > high->y)
#endif
		{
#if DEBUG
			cerr<<" segment above or below stabbing line, skipping "<<endl;
#endif
			continue;
		}

		// skip if stabbing ray is right of the segment
#ifndef SKIP_LS
		if (CGAlgorithms::computeOrientation(seg->p0, seg->p1,
#else
		if (CGAlgorithms::computeOrientation(*low, *high,
#endif
				stabbingRayLeftPt)==CGAlgorithms::RIGHT)
		{
#if DEBUG
			cerr<<" stabbing ray right of segment, skipping"<<endl;
#endif
			continue;
		}

#ifndef SKIP_LS
		// stabbing line cuts this segment, so record it
		int depth=dirEdge->getDepth(Position::LEFT);
		// if segment direction was flipped, use RHS depth instead
		if (! (seg->p0==pts->getAt(i)))
			depth=dirEdge->getDepth(Position::RIGHT);
#else
		int depth = swap ?
			dirEdge->getDepth(Position::RIGHT)
			:
			dirEdge->getDepth(Position::LEFT);
#endif

#if DEBUG
	cerr<<" depth: "<<depth<<endl;
#endif

#ifdef SKIP_LS
		seg->p0 = *low;
		seg->p1 = *high;
#endif
		DepthSegment *ds=new DepthSegment(seg, depth);
		stabbedSegments->push_back(ds);
	}
}

DepthSegment::DepthSegment(LineSegment *seg, int depth){
	// input seg is assumed to be normalized
	upwardSeg=new LineSegment(*seg);
	//upwardSeg->normalize();
	leftDepth=depth;
}

DepthSegment::~DepthSegment(){
	delete upwardSeg;
}
/**
* Defines a comparision operation on DepthSegments
* which orders them left to right
*
*

* DS1 < DS2   if   DS1->seg is left of DS2->seg
* DS1 > DS2   if   DS1->seg is right of DS2->seg
*

*
* @param obj
* @return
*/
int DepthSegment::compareTo(void* obj){
	DepthSegment *other=(DepthSegment*) obj;
	/**
	* try and compute a determinate orientation for the segments->
	* Test returns 1 if other is left of this (i->e-> this > other)
	*/
	int orientIndex=upwardSeg->orientationIndex(other->upwardSeg);
	/**
	* If comparison between this and other is indeterminate,
	* try the opposite call order->
	* orientationIndex value is 1 if this is left of other,
	* so have to flip sign to get proper comparison value of
	* -1 if this is leftmost
	*/
	if (orientIndex==0)
		orientIndex=-1 * other->upwardSeg->orientationIndex(upwardSeg);
	// if orientation is determinate, return it
	if (orientIndex != 0)
		return orientIndex;
	// otherwise, segs must be collinear - sort based on minimum X value
	return compareX(upwardSeg, other->upwardSeg);
}

/**
* Compare two collinear segments for left-most ordering->
* If segs are vertical, use vertical ordering for comparison->
* If segs are equal, return 0->
* Segments are assumed to be directed so that the second coordinate is >= to the first
* (e->g-> up and to the right)->
*
* @param seg0 a segment to compare
* @param seg1 a segment to compare
* @return
*/
int DepthSegment::compareX(LineSegment *seg0, LineSegment *seg1){
	int compare0=seg0->p0.compareTo(seg1->p0);
	if (compare0!=0)
		return compare0;
	return seg0->p1.compareTo(seg1->p1);

}

bool DepthSegmentLT(DepthSegment *first, DepthSegment *second) {
	if (first->compareTo(second)<0)
		return true;
	else
		return false;
}

} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.12  2005/06/28 21:13:43  strk
 * Fixed a bug introduced by LineSegment skip - made LineSegment skip a compile-time optione
 *
 * Revision 1.11  2005/06/27 21:58:31  strk
 * Bugfix in DepthSegmentLT as suggested by Graeme Hiebert
 *
 * Revision 1.10  2005/06/27 21:24:54  strk
 * Fixed bug just-introduced with optimization.
 *
 * Revision 1.9  2005/06/27 21:21:21  strk
 * Reduced Coordinate copies due to LineSegment overuse
 *
 * Revision 1.8  2005/05/23 15:13:00  strk
 * Added debugging output
 *
 * Revision 1.7  2005/05/20 16:15:41  strk
 * Code cleanups
 *
 * Revision 1.6  2005/05/19 10:29:28  strk
 * Removed some CGAlgorithms instances substituting them with direct calls
 * to the static functions. Interfaces accepting CGAlgorithms pointers kept
 * for backward compatibility but modified to make the argument optional.
 * Fixed a small memory leak in OffsetCurveBuilder::getRingCurve.
 * Inlined some smaller functions encountered during bug hunting.
 * Updated Copyright notices in the touched files.
 *
 * Revision 1.5  2004/07/08 19:34:49  strk
 * Mirrored JTS interface of CoordinateSequence, factory and
 * default implementations.
 * Added DefaultCoordinateSequenceFactory::instance() function.
 *
 * Revision 1.4  2004/07/02 13:28:28  strk
 * Fixed all #include lines to reflect headers layout change.
 * Added client application build tips in README.
 *
 * Revision 1.3  2004/05/05 12:29:44  strk
 * memleak fixed in ::getDepth
 *
 * Revision 1.2  2004/05/03 22:56:44  strk
 * leaks fixed, exception specification omitted.
 *
 * Revision 1.1  2004/04/10 08:40:01  ybychkov
 * "operation/buffer" upgraded to JTS 1.4
 *
 *
 **********************************************************************/

<|endoftext|>


<commit_before>/*
 * Copyright (C) Alex Nekipelov (alex@nekipelov.net)
 * License: MIT
 */

// See http://tools.ietf.org/search/rfc7049

#include <string.h>
#include <endian.h>
#include <stdint.h>

#include "cborprivate.h"
#include "cborwriter.h"

static const int positiveIntegerStart = 0x00;
static const int negativeIntegerStart = 0x20;
static const int byteStringStart = 0x40;
static const int utf8StringStart = 0x60;
static const int arrayStart = 0x80;
static const int mapStart = 0xa0;
static const int taggedStart = 0xc0;
static const int textBasedDateTime = taggedStart;      // 0xc0
static const int epochBasedDateTime = taggedStart + 1; // 0xc1
static const int positiveBignum = taggedStart + 2;     // 0xc2
static const int negativeBignum = taggedStart + 3;     // 0xc3
//...
static const int simpleStart = 0xe0;
static const int halfPrecisionFloat = simpleStart + 0x19;   // 0xf9
static const int singlePrecisionFloat = simpleStart + 0x1a; // 0xfa
static const int doublePrecisionFloat = simpleStart + 0x1b; // 0xfb

static void cborWriteInternal(std::vector<char> &buff, const CborValue &value);

static void writeNull(std::vector<char> &buff)
{
    const char nil = static_cast<char>(0xf6);
    buff.push_back(nil);
}

static void writeUndefined(std::vector<char> &buff)
{
    const char undefined = static_cast<char>(0xf7);
    buff.push_back(undefined);
}

static void writeBool(std::vector<char> &buff, const CborValue &value)
{
    const char trueValue = static_cast<char>(0xf5);
    const char falseValue = static_cast<char>(0xf4);

    if( value.toBool() )
        buff.push_back(trueValue);
    else
        buff.push_back(falseValue);
}

static void writeInteger(std::vector<char> &buff, uint64_t value, int type)
{
    assert(type + 24 < 256);

    if( value < 24 )
    {
        uint8_t byte = type + value;

        buff.push_back(byte);
    }
    else if( value < 256 )
    {
        uint8_t bytes[2] = {static_cast<uint8_t>(type + 24), static_cast<uint8_t>(value)};

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else if( value < 65536 )
    {
        uint16_t ui16 = htobe16(value);
        uint8_t bytes[3] = {
            static_cast<uint8_t>(type + 25),
            static_cast<uint8_t>(ui16 & 0xff),
            static_cast<uint8_t>((ui16 & 0xff00) >> 8)
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else if( value < 4294967296LU )
    {
        uint32_t ui32 = htobe32(value);
        uint8_t bytes[5] = {
            static_cast<uint8_t>(type + 26),
            static_cast<uint8_t>(ui32 & 0xff),
            static_cast<uint8_t>((ui32 & 0xff00) >> 8),
            static_cast<uint8_t>((ui32 & 0xff0000) >> 16),
            static_cast<uint8_t>((ui32 & 0xff000000) >> 24)
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else
    {
        uint64_t ui64 = htobe64(value);
        uint8_t bytes[9] = {
            static_cast<uint8_t>(type + 27),
            static_cast<uint8_t>(ui64 & 0xff),
            static_cast<uint8_t>((ui64 & 0xff00) >> 8),
            static_cast<uint8_t>((ui64 & 0xff0000) >> 16),
            static_cast<uint8_t>((ui64 & 0xff000000) >> 24),
            static_cast<uint8_t>((ui64 & 0xff00000000UL) >> 32),
            static_cast<uint8_t>((ui64 & 0xff0000000000UL) >> 40),
            static_cast<uint8_t>((ui64 & 0xff000000000000UL) >> 48),
            static_cast<uint8_t>((ui64 & 0xff00000000000000UL) >> 56)
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
}

static void writePositiveInteger(std::vector<char> &buff, const CborValue &value)
{
    uint64_t i = value.toPositiveInteger();

    if( i > 0 )
    {
        writeInteger(buff, i, positiveIntegerStart);
    }
    else
    {
        const char zero = 0;
        buff.push_back(zero);
    }
}

static void writeNegativeInteger(std::vector<char> &buff, const CborValue &value)
{
    uint64_t i = value.toNegativeInteger();

    if( i == 0 )
    {
        writeInteger(buff, 0xFFFFFFFFFFFFFFFF, negativeIntegerStart);
    }
    else
    {
        writeInteger(buff, i - 1, negativeIntegerStart);
    }
}

static void writeString(std::vector<char> &buff, const CborValue &value)
{
    const std::string &s = value.toString();

    writeInteger(buff, s.size(), utf8StringStart);

    buff.insert(buff.end(), s.begin(), s.end());
}

static void writeByteString(std::vector<char> &buff, const CborValue &value)
{
    const std::vector<char> &data = value.toByteString();

    writeInteger(buff, data.size(), byteStringStart);

    buff.insert(buff.end(), data.begin(), data.end());
}

static void writeDouble(std::vector<char> &buff, const CborValue &value)
{
    double dv = value.toDouble();
    float fv = dv;

    if( fv == dv )
    {
        // Warning: code from MessagePack

        union {
            float f;
            uint32_t ui32;
        } buf = { fv };

        int i32 = buf.ui32;
        if ((i32 & 0x1FFF) == 0)
        {
            do
            {
                // IEEE 754 half-precision
                uint16_t s16 = (i32 >> 16) & 0x8000;
                int exponent = (i32 >> 23) & 0xff;
                int mantissa = i32 & 0x7fffff;

                if (exponent == 0 && mantissa == 0)
                {
                    ;
                }
                else if (exponent >= 113 && exponent <= 142)
                {
                    // normalized
                    s16 += ((exponent - 112) << 10) + (mantissa >> 13);
                }
                else if (exponent >= 103 && exponent < 113)
                {
                    // denorm, exp16 = 0
                    if (mantissa & ((1 << (126 - exponent)) - 1))
                        break; // loss of precision
                    s16 += ((mantissa + 0x800000) >> (126 - exponent));
                }
                else if (exponent == 255 && mantissa == 0)
                {
                    // Inf
                    s16 += 0x7c00;
                }
                else
                {
                    break;  // loss of range
                }

                s16 = htobe16(s16);

                uint8_t bytes[3] = {
                    halfPrecisionFloat,
                    static_cast<uint8_t>(s16 & 0xff),
                    static_cast<uint8_t>((s16 & 0xff00) >> 8)
                };

                buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
                return;
            } while(0);
        }

        // IEEE 754 single-precision
        buf.ui32 = htobe32(buf.ui32);

        uint8_t bytes[5] = {
            singlePrecisionFloat,
            static_cast<uint8_t>(buf.ui32 & 0xff),
            static_cast<uint8_t>((buf.ui32 & 0xff00) >> 8),
            static_cast<uint8_t>((buf.ui32 & 0xff0000) >> 16),
            static_cast<uint8_t>((buf.ui32 & 0xff000000) >> 24),
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else if( dv != dv )
    {
        // NaN
        uint8_t bytes[3] = {halfPrecisionFloat, 0x7e, 0x00};

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else
    {
        // IEEE 754 double-precision
        union {
            double dv;
            uint64_t ui64;
        } buf = { dv };

        buf.ui64 = htobe64(buf.ui64);

        uint8_t bytes[9] = {
            doublePrecisionFloat,
            static_cast<uint8_t>(buf.ui64 & 0xff),
            static_cast<uint8_t>((buf.ui64 & 0xff00) >> 8),
            static_cast<uint8_t>((buf.ui64 & 0xff0000) >> 16),
            static_cast<uint8_t>((buf.ui64 & 0xff000000) >> 24),
            static_cast<uint8_t>((buf.ui64 & 0xff00000000UL) >> 32),
            static_cast<uint8_t>((buf.ui64 & 0xff0000000000UL) >> 40),
            static_cast<uint8_t>((buf.ui64 & 0xff000000000000UL) >> 48),
            static_cast<uint8_t>((buf.ui64 & 0xff00000000000000UL) >> 56)
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
}

static void writeArray(std::vector<char> &buff, const CborValue &value)
{
    const std::vector<CborValue> &arr = value.toArray();

    writeInteger(buff, arr.size(), arrayStart);

    for(size_t i = 0; i < arr.size(); ++i)
    {
        cborWriteInternal(buff, arr[i]);
    }
}

static void writeMap(std::vector<char> &buff, const CborValue &value)
{
    const std::map<CborValue, CborValue> &map = value.toMap();
    std::map<CborValue, CborValue>::const_iterator it = map.begin();
    std::map<CborValue, CborValue>::const_iterator end = map.end();

    writeInteger(buff, map.size(), mapStart);

    for(; it != end; ++it)
    {
        cborWriteInternal(buff, it->first);
        cborWriteInternal(buff, it->second);
    }
}

static void writeBigInteger(std::vector<char> &buff, const CborValue &value)
{
    CborValue::BigInteger bigInteger = value.toBigInteger();

    bool canBeWrittenAs64BitInteger = bigInteger.bigint.size() < 9;
    canBeWrittenAs64BitInteger = canBeWrittenAs64BitInteger || (
                                    bigInteger.bigint.size() == 9 &&
                                    bigInteger.bigint[8] == 0 &&
                                    bigInteger.bigint[7] == 0 &&
                                    bigInteger.bigint[6] == 0 &&
                                    bigInteger.bigint[5] == 0 &&
                                    bigInteger.bigint[4] == 0 &&
                                    bigInteger.bigint[3] == 0 &&
                                    bigInteger.bigint[2] == 0 &&
                                    bigInteger.bigint[1] == 0 &&
                                    bigInteger.bigint[0] == 1 &&
                                    bigInteger.positive == false);

    if(canBeWrittenAs64BitInteger)
    {
        // This number can be written as integer value.

        if( bigInteger.bigint.size() == 9 )
        {
            writeInteger(buff, 0xFFFFFFFFFFFFFFFF, negativeIntegerStart);
        }
        else
        {
            uint64_t ui = 0;

            for(size_t i = 0; i < bigInteger.bigint.size(); ++i)
                ui = bigInteger.bigint[i] + (ui << 8);

            if( bigInteger.positive)
                writeInteger(buff, ui, positiveIntegerStart);
            else
                writeInteger(buff, ui - 1, negativeIntegerStart);
        }
    }
    else
    {
        if( bigInteger.positive )
        {
            buff.push_back(static_cast<char>(positiveBignum));
        }
        else
        {
            buff.push_back(static_cast<char>(negativeBignum));

            for(size_t i = bigInteger.bigint.size(); i != 0 ; --i)
            {
                unsigned char c = bigInteger.bigint[i - 1];
                if( c != 0 )
                {
                    bigInteger.bigint[i - 1] = c - 1u;
                    break;
                }
                else
                {
                    bigInteger.bigint[i - 1] = static_cast<char>(0xff);
                }
            }
        }

        writeByteString(buff, CborValue(bigInteger.bigint));
    }
}

static void cborWriteInternal(std::vector<char> &buff, const CborValue &value)
{
    switch(value.type())
    {
    case CborValue::NullType:
        writeNull(buff);
        break;
    case CborValue::UndefinedType:
        writeUndefined(buff);
        break;
    case CborValue::BoolType:
        writeBool(buff, value);
        break;
    case CborValue::NegativeIntegerType:
        writeNegativeInteger(buff, value);
        break;
    case CborValue::PositiveIntegerType:
        writePositiveInteger(buff, value);
        break;
    case CborValue::DoubleType:
        writeDouble(buff, value);
        break;
    case CborValue::StringType:
        writeString(buff, value);
        break;
    case CborValue::ByteStringType:
        writeByteString(buff, value);
        break;
    case CborValue::ArrayType:
        writeArray(buff, value);
        break;
    case CborValue::MapType:
        writeMap(buff, value);
        break;
    case CborValue::BigIntegerType:
        writeBigInteger(buff, value);
        break;
    default:
        assert(false);
        std::cerr << "Internal error: invalid type" << std::endl;
    }
}

std::vector<char> cborWrite(const CborValue &value)
{
    std::vector<char> result;

    cborWriteInternal(result, value);
    return result;
}

<commit_msg>Missing header file<commit_after>/*
 * Copyright (C) Alex Nekipelov (alex@nekipelov.net)
 * License: MIT
 */

// See http://tools.ietf.org/search/rfc7049

#include <string.h>
#include <endian.h>
#include <stdint.h>
#include <iostream>

#include "cborprivate.h"
#include "cborwriter.h"

static const int positiveIntegerStart = 0x00;
static const int negativeIntegerStart = 0x20;
static const int byteStringStart = 0x40;
static const int utf8StringStart = 0x60;
static const int arrayStart = 0x80;
static const int mapStart = 0xa0;
static const int taggedStart = 0xc0;
static const int textBasedDateTime = taggedStart;      // 0xc0
static const int epochBasedDateTime = taggedStart + 1; // 0xc1
static const int positiveBignum = taggedStart + 2;     // 0xc2
static const int negativeBignum = taggedStart + 3;     // 0xc3
//...
static const int simpleStart = 0xe0;
static const int halfPrecisionFloat = simpleStart + 0x19;   // 0xf9
static const int singlePrecisionFloat = simpleStart + 0x1a; // 0xfa
static const int doublePrecisionFloat = simpleStart + 0x1b; // 0xfb

static void cborWriteInternal(std::vector<char> &buff, const CborValue &value);

static void writeNull(std::vector<char> &buff)
{
    const char nil = static_cast<char>(0xf6);
    buff.push_back(nil);
}

static void writeUndefined(std::vector<char> &buff)
{
    const char undefined = static_cast<char>(0xf7);
    buff.push_back(undefined);
}

static void writeBool(std::vector<char> &buff, const CborValue &value)
{
    const char trueValue = static_cast<char>(0xf5);
    const char falseValue = static_cast<char>(0xf4);

    if( value.toBool() )
        buff.push_back(trueValue);
    else
        buff.push_back(falseValue);
}

static void writeInteger(std::vector<char> &buff, uint64_t value, int type)
{
    assert(type + 24 < 256);

    if( value < 24 )
    {
        uint8_t byte = type + value;

        buff.push_back(byte);
    }
    else if( value < 256 )
    {
        uint8_t bytes[2] = {static_cast<uint8_t>(type + 24), static_cast<uint8_t>(value)};

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else if( value < 65536 )
    {
        uint16_t ui16 = htobe16(value);
        uint8_t bytes[3] = {
            static_cast<uint8_t>(type + 25),
            static_cast<uint8_t>(ui16 & 0xff),
            static_cast<uint8_t>((ui16 & 0xff00) >> 8)
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else if( value < 4294967296LU )
    {
        uint32_t ui32 = htobe32(value);
        uint8_t bytes[5] = {
            static_cast<uint8_t>(type + 26),
            static_cast<uint8_t>(ui32 & 0xff),
            static_cast<uint8_t>((ui32 & 0xff00) >> 8),
            static_cast<uint8_t>((ui32 & 0xff0000) >> 16),
            static_cast<uint8_t>((ui32 & 0xff000000) >> 24)
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else
    {
        uint64_t ui64 = htobe64(value);
        uint8_t bytes[9] = {
            static_cast<uint8_t>(type + 27),
            static_cast<uint8_t>(ui64 & 0xff),
            static_cast<uint8_t>((ui64 & 0xff00) >> 8),
            static_cast<uint8_t>((ui64 & 0xff0000) >> 16),
            static_cast<uint8_t>((ui64 & 0xff000000) >> 24),
            static_cast<uint8_t>((ui64 & 0xff00000000UL) >> 32),
            static_cast<uint8_t>((ui64 & 0xff0000000000UL) >> 40),
            static_cast<uint8_t>((ui64 & 0xff000000000000UL) >> 48),
            static_cast<uint8_t>((ui64 & 0xff00000000000000UL) >> 56)
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
}

static void writePositiveInteger(std::vector<char> &buff, const CborValue &value)
{
    uint64_t i = value.toPositiveInteger();

    if( i > 0 )
    {
        writeInteger(buff, i, positiveIntegerStart);
    }
    else
    {
        const char zero = 0;
        buff.push_back(zero);
    }
}

static void writeNegativeInteger(std::vector<char> &buff, const CborValue &value)
{
    uint64_t i = value.toNegativeInteger();

    if( i == 0 )
    {
        writeInteger(buff, 0xFFFFFFFFFFFFFFFF, negativeIntegerStart);
    }
    else
    {
        writeInteger(buff, i - 1, negativeIntegerStart);
    }
}

static void writeString(std::vector<char> &buff, const CborValue &value)
{
    const std::string &s = value.toString();

    writeInteger(buff, s.size(), utf8StringStart);

    buff.insert(buff.end(), s.begin(), s.end());
}

static void writeByteString(std::vector<char> &buff, const CborValue &value)
{
    const std::vector<char> &data = value.toByteString();

    writeInteger(buff, data.size(), byteStringStart);

    buff.insert(buff.end(), data.begin(), data.end());
}

static void writeDouble(std::vector<char> &buff, const CborValue &value)
{
    double dv = value.toDouble();
    float fv = dv;

    if( fv == dv )
    {
        // Warning: code from MessagePack

        union {
            float f;
            uint32_t ui32;
        } buf = { fv };

        int i32 = buf.ui32;
        if ((i32 & 0x1FFF) == 0)
        {
            do
            {
                // IEEE 754 half-precision
                uint16_t s16 = (i32 >> 16) & 0x8000;
                int exponent = (i32 >> 23) & 0xff;
                int mantissa = i32 & 0x7fffff;

                if (exponent == 0 && mantissa == 0)
                {
                    ;
                }
                else if (exponent >= 113 && exponent <= 142)
                {
                    // normalized
                    s16 += ((exponent - 112) << 10) + (mantissa >> 13);
                }
                else if (exponent >= 103 && exponent < 113)
                {
                    // denorm, exp16 = 0
                    if (mantissa & ((1 << (126 - exponent)) - 1))
                        break; // loss of precision
                    s16 += ((mantissa + 0x800000) >> (126 - exponent));
                }
                else if (exponent == 255 && mantissa == 0)
                {
                    // Inf
                    s16 += 0x7c00;
                }
                else
                {
                    break;  // loss of range
                }

                s16 = htobe16(s16);

                uint8_t bytes[3] = {
                    halfPrecisionFloat,
                    static_cast<uint8_t>(s16 & 0xff),
                    static_cast<uint8_t>((s16 & 0xff00) >> 8)
                };

                buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
                return;
            } while(0);
        }

        // IEEE 754 single-precision
        buf.ui32 = htobe32(buf.ui32);

        uint8_t bytes[5] = {
            singlePrecisionFloat,
            static_cast<uint8_t>(buf.ui32 & 0xff),
            static_cast<uint8_t>((buf.ui32 & 0xff00) >> 8),
            static_cast<uint8_t>((buf.ui32 & 0xff0000) >> 16),
            static_cast<uint8_t>((buf.ui32 & 0xff000000) >> 24),
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else if( dv != dv )
    {
        // NaN
        uint8_t bytes[3] = {halfPrecisionFloat, 0x7e, 0x00};

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
    else
    {
        // IEEE 754 double-precision
        union {
            double dv;
            uint64_t ui64;
        } buf = { dv };

        buf.ui64 = htobe64(buf.ui64);

        uint8_t bytes[9] = {
            doublePrecisionFloat,
            static_cast<uint8_t>(buf.ui64 & 0xff),
            static_cast<uint8_t>((buf.ui64 & 0xff00) >> 8),
            static_cast<uint8_t>((buf.ui64 & 0xff0000) >> 16),
            static_cast<uint8_t>((buf.ui64 & 0xff000000) >> 24),
            static_cast<uint8_t>((buf.ui64 & 0xff00000000UL) >> 32),
            static_cast<uint8_t>((buf.ui64 & 0xff0000000000UL) >> 40),
            static_cast<uint8_t>((buf.ui64 & 0xff000000000000UL) >> 48),
            static_cast<uint8_t>((buf.ui64 & 0xff00000000000000UL) >> 56)
        };

        buff.insert(buff.end(), bytes, bytes + sizeof(bytes));
    }
}

static void writeArray(std::vector<char> &buff, const CborValue &value)
{
    const std::vector<CborValue> &arr = value.toArray();

    writeInteger(buff, arr.size(), arrayStart);

    for(size_t i = 0; i < arr.size(); ++i)
    {
        cborWriteInternal(buff, arr[i]);
    }
}

static void writeMap(std::vector<char> &buff, const CborValue &value)
{
    const std::map<CborValue, CborValue> &map = value.toMap();
    std::map<CborValue, CborValue>::const_iterator it = map.begin();
    std::map<CborValue, CborValue>::const_iterator end = map.end();

    writeInteger(buff, map.size(), mapStart);

    for(; it != end; ++it)
    {
        cborWriteInternal(buff, it->first);
        cborWriteInternal(buff, it->second);
    }
}

static void writeBigInteger(std::vector<char> &buff, const CborValue &value)
{
    CborValue::BigInteger bigInteger = value.toBigInteger();

    bool canBeWrittenAs64BitInteger = bigInteger.bigint.size() < 9;
    canBeWrittenAs64BitInteger = canBeWrittenAs64BitInteger || (
                                    bigInteger.bigint.size() == 9 &&
                                    bigInteger.bigint[8] == 0 &&
                                    bigInteger.bigint[7] == 0 &&
                                    bigInteger.bigint[6] == 0 &&
                                    bigInteger.bigint[5] == 0 &&
                                    bigInteger.bigint[4] == 0 &&
                                    bigInteger.bigint[3] == 0 &&
                                    bigInteger.bigint[2] == 0 &&
                                    bigInteger.bigint[1] == 0 &&
                                    bigInteger.bigint[0] == 1 &&
                                    bigInteger.positive == false);

    if(canBeWrittenAs64BitInteger)
    {
        // This number can be written as integer value.

        if( bigInteger.bigint.size() == 9 )
        {
            writeInteger(buff, 0xFFFFFFFFFFFFFFFF, negativeIntegerStart);
        }
        else
        {
            uint64_t ui = 0;

            for(size_t i = 0; i < bigInteger.bigint.size(); ++i)
                ui = bigInteger.bigint[i] + (ui << 8);

            if( bigInteger.positive)
                writeInteger(buff, ui, positiveIntegerStart);
            else
                writeInteger(buff, ui - 1, negativeIntegerStart);
        }
    }
    else
    {
        if( bigInteger.positive )
        {
            buff.push_back(static_cast<char>(positiveBignum));
        }
        else
        {
            buff.push_back(static_cast<char>(negativeBignum));

            for(size_t i = bigInteger.bigint.size(); i != 0 ; --i)
            {
                unsigned char c = bigInteger.bigint[i - 1];
                if( c != 0 )
                {
                    bigInteger.bigint[i - 1] = c - 1u;
                    break;
                }
                else
                {
                    bigInteger.bigint[i - 1] = static_cast<char>(0xff);
                }
            }
        }

        writeByteString(buff, CborValue(bigInteger.bigint));
    }
}

static void cborWriteInternal(std::vector<char> &buff, const CborValue &value)
{
    switch(value.type())
    {
    case CborValue::NullType:
        writeNull(buff);
        break;
    case CborValue::UndefinedType:
        writeUndefined(buff);
        break;
    case CborValue::BoolType:
        writeBool(buff, value);
        break;
    case CborValue::NegativeIntegerType:
        writeNegativeInteger(buff, value);
        break;
    case CborValue::PositiveIntegerType:
        writePositiveInteger(buff, value);
        break;
    case CborValue::DoubleType:
        writeDouble(buff, value);
        break;
    case CborValue::StringType:
        writeString(buff, value);
        break;
    case CborValue::ByteStringType:
        writeByteString(buff, value);
        break;
    case CborValue::ArrayType:
        writeArray(buff, value);
        break;
    case CborValue::MapType:
        writeMap(buff, value);
        break;
    case CborValue::BigIntegerType:
        writeBigInteger(buff, value);
        break;
    default:
        assert(false);
        std::cerr << "Internal error: invalid type" << std::endl;
    }
}

std::vector<char> cborWrite(const CborValue &value)
{
    std::vector<char> result;

    cborWriteInternal(result, value);
    return result;
}

<|endoftext|>


<commit_before>///////////////////////////////////////
/// file: match.cpp
/// 括号匹配的检验
///////////////////////////////////////

#include <iostream>
#include <iomanip>  // for std::setw
#include "sqstack.h"

using namespace std;

///
/// 输入一行字符串，检验其中括号是否匹配
///
bool match(const char *expr)
{
    // 匹配括号
    SqStack<char> s;
    InitStack(s);
    for(int i = 0; expr[i]; i++) {
        char c = expr[i];
        if(c=='(' || c=='[' || c=='{') {
            Push(s,c);
        } else if(c==')') {
            if(StackEmpty(s)) {
                cout << expr << endl;
                cout << setw(i+1) << '^' << " : 多余的 )" << endl;
                return false;
            }
            char b;
            Pop(s,b);
            if(b!='(') {
                cout << expr << endl;
                cout << setw(i+1) << '^' << " : 匹配错误 )" << endl;
                return false;
            }
        } else if(c==']') {
            if(StackEmpty(s)) {
                cout << expr << endl;
                cout << setw(i+1) << '^' << " : 多余的 ]" << endl;
                return false;
            }
            char b;
            Pop(s,b);
            if(b!='[') {
                cout << expr << endl;
                cout << setw(i+1) << '^' << " : 匹配错误 ]" << endl;
                return false;
            }
        } else if(c=='}') {
            if(StackEmpty(s)) {
                cout << expr << endl;
                cout << setw(i+1) << '^' << " : 多余的 }" << endl;
                return false;
            }
            char b;
            Pop(s,b);
            if(b!='{') {
                cout << expr << endl;
                cout << setw(i+1) << '^' << " : 匹配错误 }" << endl;
                return false;
            }
        }
    }

    // 若栈空，则匹配成功
    if(StackEmpty(s)) {
        cout << expr << endl;
        cout << "匹配成功" << endl;
        return true;
    } else {
        cout << expr << endl;
        cout << "缺少右括号" << endl;;
        return  false;
    }
}

int main()
{
    match("([]())");
    match("[([][])]");
    match("[([][]]");
    match("[([][])])");
    match("(([][])]");

    return 0;
}<commit_msg>Update match.cpp<commit_after>///////////////////////////////////////
/// file: match.cpp
/// 括号匹配的检验
///////////////////////////////////////

#include <iostream>
#include "sqstack.h"

using namespace std;

///
/// 输入一行字符串，检验其中括号是否匹配
///
bool match(const char *expr)
{
    // 匹配括号
    SqStack<char> s;
    InitStack(s);
    for(int i = 0; expr[i]; i++) {
        char c = expr[i];
        if(c=='(' || c=='[' || c=='{') {
            // 左括号入栈
            Push(s,c);
        } else if(c==')' || c==']' || c=='}') {
            // 右括号与栈顶括号进行匹配
            if(StackEmpty(s)) return false; // 栈空则匹配失败
            // 出栈
            char b;
            Pop(s,b);
            // 匹配失败则返回
            if(( c==')' && b!='(' ) ||
              ( c==']' && b!='[' ) ||
              ( c=='{' &&b !='}' ))
                return false;
        }
    }

    // 若栈空，则匹配成功
    return StackEmpty(s);
}

int main()
{
    const int N = 5;
    const char *expr[N] = {
        "([]())",
        "[([][])]",
        "[([][]]",
        "[([][])])",
        "(([][])]",
    };

    for(int i=0; i<N; i++) {
        cout << expr[i] << " match = "
            << boolalpha << match(expr[i]) << endl;
    }

    return 0;
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ManifestDefines.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: mtg $ $Date: 2001-04-27 14:56:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _MANIFEST_DEFINES_HXX
#define _MANIFEST_DEFINES_HXX

#define ELEMENT_MANIFEST "manifest:manifest"
#define ELEMENT_FILE_ENTRY "manifest:file-entry"
#define ELEMENT_ENCRYPTION_DATA "manifest:encryption-data"
#define ELEMENT_INITIALISATION_VECTOR "manifest:initialisation-vector"
#define ATTRIBUTE_FULL_PATH "manifest:full-path"
#define ATTRIBUTE_MEDIA_TYPE "manifest:media-type"
#define ATTRIBUTE_ALGORITHM "manifest:algorithm"
#define ATTRIBUTE_SALT "manifest:salt"
#define ATTRIBUTE_ITERATION_COUNT "manifest:iteration-count"
#define ATTRIBUTE_CDATA "CDATA"
#define ATTRIBUTE_XMLNS "xmlns:manifest"
#define MANIFEST_NAMESPACE "http://openoffice.org/2001/manifest"

#endif
<commit_msg>Update new defines to reflect new manifest file structure<commit_after>/*************************************************************************
 *
 *  $RCSfile: ManifestDefines.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: mtg $ $Date: 2001-05-08 13:53:48 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _MANIFEST_DEFINES_HXX
#define _MANIFEST_DEFINES_HXX

#define ELEMENT_MANIFEST "manifest:manifest"
#define ATTRIBUTE_XMLNS "xmlns:manifest"
#define MANIFEST_NAMESPACE "http://openoffice.org/2001/manifest"
#define MANIFEST_DOCTYPE "<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">"
#define ATTRIBUTE_CDATA "CDATA"

#define ELEMENT_FILE_ENTRY "manifest:file-entry"
#define ATTRIBUTE_FULL_PATH "manifest:full-path"
#define ATTRIBUTE_MEDIA_TYPE "manifest:media-type"
#define ATTRIBUTE_SIZE "manifest:size"

#define ELEMENT_ENCRYPTION_DATA "manifest:encryption-data"

#define ELEMENT_ALGORITHM "manifest:algorithm"
#define ATTRIBUTE_ALGORITHM_NAME "manifest:algorithm-name"
#define ATTRIBUTE_INITIALISATION_VECTOR "manifest:initialisation-vector"

#define ELEMENT_KEY_DERIVATION "manifest:key-derivation"
#define ATTRIBUTE_KEY_DERIVATION_NAME "manifest:key-derivation-name"
#define ATTRIBUTE_SALT "manifest:salt"
#define ATTRIBUTE_ITERATION_COUNT "manifest:iteration-count"

#endif
<|endoftext|>


<commit_before>//
//  main.cpp
//  literals
//
//  Created by Sunil on 2/21/17.
//  Copyright © 2017 Sunil. All rights reserved.
//

#include <iostream>
#include <string>

#include "Length.hpp"

using namespace std;

using LengthDouble = Length<double>;

// Ref: http://stackoverflow.com/questions/16596864/c11-operator-with-double-parameter
// The declaration of a literal operator shall have a parameter-declaration-clause e
// quivalent to one of the following:
//
// const char*
// unsigned long long int
// long double
// char
// wchar_t
// char16_t
// char32_t
// const char*, std::size_t
// const wchar_t*, std::size_t
// const char16_t*, std::size_t
// const char32_t*, std::size_t

LengthDouble operator"" _km(long double value) {
    return LengthDouble(value, Distance::Kilometers);
}

LengthDouble operator"" _mi(long double value) {
    return LengthDouble(value, Distance::Miles);
}

int main(int argc, const char * argv[]) {
    auto a = Length<int>(30);
    auto b = Length<int>(10);
    Length<int> total = a + b;
    cout << total.getMiles() << endl;

    // why can't i perform direct + operator
    // auto t1 = 12.12_km + 23.23_mi;
    // Because of missing operator+ with move semantics.

    auto k = 12.12_km;
    auto l = 23.23_mi;
    auto t1 = k + l;
    cout << t1.getMiles() << endl;

    auto t2 = 12.12_km + 23.23_mi;
    cout << Length<>(23.23).getMiles() << endl;

    return 0;
}
<commit_msg>pushed pending changes<commit_after>//
//  main.cpp
//  literals
//
//  Created by Sunil on 2/21/17.
//  Copyright © 2017 Sunil. All rights reserved.
//

#include <iostream>
#include <string>

#include "Length.hpp"

using namespace std;

using LengthDouble = Length<double>;

// Ref: http://stackoverflow.com/questions/16596864/c11-operator-with-double-parameter
// The declaration of a literal operator shall have a parameter-declaration-clause e
// quivalent to one of the following:
//
// const char*
// unsigned long long int
// long double
// char
// wchar_t
// char16_t
// char32_t
// const char*, std::size_t
// const wchar_t*, std::size_t
// const char16_t*, std::size_t
// const char32_t*, std::size_t

LengthDouble operator"" _km(long double value) {
    return LengthDouble(value, Distance::Kilometers);
}

LengthDouble operator"" _mi(long double value) {
    return LengthDouble(value, Distance::Miles);
}

unsigned long long int operator"" _b(const char* bits) {
    unsigned acc = 0;
    while(*bits) {
        if (*bits == '1' || *bits == '0') {
            acc  = (acc << 1) + (*bits-'0');
        } else {
            throw std::runtime_error("Invalid binary digits!");
        }
        bits++;
    }
    return acc;
}

void increment(int& x) {
    ++x;
}

template<typename T>
function<void(void)> callback(std::function<void(T&)> f, T&& val) {
    auto k = [&]() {
        f(val);
    };
    return k;
}

int main(int argc, const char * argv[]) {
    auto a = Length<int>(30);
    auto b = Length<int>(10);
    Length<int> total = a + b;
    cout << total.getMiles() << endl;

    // why can't i perform direct + operator
    // auto t1 = 12.12_km + 23.23_mi;
    // Because of missing operator+ with move semantics.

    auto k = 12.12_km;
    auto l = 23.23_mi;
    auto t1 = k + l;
    cout << t1.getMiles() << endl;

    auto t2 = 12.12_km + 23.23_mi;
    cout << Length<>(23.23).getMiles() << endl;

    std::cout << "Another example of user defined literal" << endl;
    {
        auto acc = 1111_b;
        // auto acc2 = 1411_b;  // runtime error
        cout << acc << endl;
    }

    std::cout << "std::ref usage" << endl;
    {
        int val = 34;
        int& rval = std::ref(val);
        rval = 45;
        cout << rval << " " << val << endl;

        int i = 9;
        auto f = std::bind(increment, std::ref(i));
        f();
        auto invoke = callback<int&>(increment, i);
        invoke();

        cout << i << endl;
    }

    return 0;
}
<|endoftext|>