<commit_before>#include <cassert>
#include <cstring>
#include <pprintpp.hpp>

#define TEST(correct_str, ...) \
    assert(!strcmp(AUTOFORMAT(__VA_ARGS__), correct_str))

int main()
{
    TEST("", "");

    TEST(" { ", " \\{ ");
    TEST("{}", "\\{}");
    TEST(" { %d } ", " \\{ {} } ", 123);

    TEST("%p", "{}", nullptr);
    TEST("%p", "{}", reinterpret_cast<void*>(0));

    // For safety reasons:
    // Only print strings as strings, if the user also writes {s}
    TEST("%p", "{}", "str");
    TEST("%s", "{s}", "str");

    TEST("%c",   "{}", static_cast<char>(123));

    TEST("%d",   "{}", static_cast<short>(123));
    TEST("%d",   "{}", 123);
    TEST("%ld",  "{}", 123l);
    TEST("%lld", "{}", 123ll);

    TEST("%u",   "{}", 123u);
    TEST("%lu",  "{}", 123ul);
    TEST("%llu", "{}", 123ull);

    TEST("%x",   "{x}", 123u);
    TEST("%lx",  "{x}", 123ul);
    TEST("%llx", "{x}", 123ull);

    TEST("%f",  "{}", 1.0f);
    TEST("%lf", "{}", 1.0);

    TEST("%10d", "{10}", 123);
    TEST("%10x", "{10x}", 123u);
    TEST("%#10x", "{#10x}", 123u);

    pprintf("Green, green, green! All tests passed.\n");

    pprintf("{s} {} {1} {} {} {} {} {} {} {} {} {} {} {} {} {#x}\n",
            "1",2u,3.0,4.0f,5ull,'6',7ul,8,9,10,11,12,13,14,15,16u);

    return 0;
}
<commit_msg>Add <cstdio> to unit test<commit_after>#include <cassert>
#include <cstring>
#include <cstdio>
#include <pprintpp.hpp>

#define TEST(correct_str, ...) \
    assert(!strcmp(AUTOFORMAT(__VA_ARGS__), correct_str))

int main()
{
    TEST("", "");

    TEST(" { ", " \\{ ");
    TEST("{}", "\\{}");
    TEST(" { %d } ", " \\{ {} } ", 123);

    TEST("%p", "{}", nullptr);
    TEST("%p", "{}", reinterpret_cast<void*>(0));

    // For safety reasons:
    // Only print strings as strings, if the user also writes {s}
    TEST("%p", "{}", "str");
    TEST("%s", "{s}", "str");

    TEST("%c",   "{}", static_cast<char>(123));

    TEST("%d",   "{}", static_cast<short>(123));
    TEST("%d",   "{}", 123);
    TEST("%ld",  "{}", 123l);
    TEST("%lld", "{}", 123ll);

    TEST("%u",   "{}", 123u);
    TEST("%lu",  "{}", 123ul);
    TEST("%llu", "{}", 123ull);

    TEST("%x",   "{x}", 123u);
    TEST("%lx",  "{x}", 123ul);
    TEST("%llx", "{x}", 123ull);

    TEST("%f",  "{}", 1.0f);
    TEST("%lf", "{}", 1.0);

    TEST("%10d", "{10}", 123);
    TEST("%10x", "{10x}", 123u);
    TEST("%#10x", "{#10x}", 123u);

    pprintf("Green, green, green! All tests passed.\n");

    pprintf("{s} {} {1} {} {} {} {} {} {} {} {} {} {} {} {} {#x}\n",
            "1",2u,3.0,4.0f,5ull,'6',7ul,8,9,10,11,12,13,14,15,16u);

    return 0;
}
<|endoftext|>


<commit_before>#define CATCH_CONFIG_RUNNER
#include "./catch.hpp"
#include "./ReQL.hpp"

int
main(int argc, char **argv) {
  int result = Catch::Session().run(argc, argv);

  try {
    ReQL::Connection conn;

    ReQL::db_list({}).filter({
      ReQL::func({
        1.0,
        ReQL::var({1.0}).ne({std::string("rethinkdb")})
      })
    }).for_each({
      ReQL::func({
        2.0,
        ReQL::var({2.0}).db({}).wait({})
        .funcall({
          ReQL::func({
            3.0,
            ReQL::var({2.0}).db_drop({})
          })
        })
      })
    })
    .run(conn).toVector().clear();

    conn.close();
  } catch (ReQL::ReQLError &e) {
    (void)e;
  }

  return result;
}
<commit_msg>Make query explicit.<commit_after>#define CATCH_CONFIG_RUNNER
#include "./catch.hpp"
#include "./ReQL.hpp"

int
main(int argc, char **argv) {
  int result = Catch::Session().run(argc, argv);

  try {
    ReQL::Connection conn;

    ReQL::db_list(std::vector<ReQL::Query>())
    .filter(std::vector<ReQL::Query>({
      ReQL::func(std::vector<ReQL::Query>({
        ReQL::Query(std::vector<ReQL::Query>({ReQL::Query(1.0)})),
        ReQL::var(std::vector<ReQL::Query>({ReQL::Query(1.0)}))
        .ne(std::vector<ReQL::Query>({
          ReQL::Query(std::string("rethinkdb"))
        }))
      }))
    }))
    .for_each(std::vector<ReQL::Query>({
      ReQL::func(std::vector<ReQL::Query>({
        ReQL::Query(std::vector<ReQL::Query>({ReQL::Query(2.0)})),
        ReQL::func(std::vector<ReQL::Query>({
          ReQL::Query(std::vector<ReQL::Query>()),
          ReQL::db_drop(std::vector<ReQL::Query>({
            ReQL::var(std::vector<ReQL::Query>({ReQL::Query(2.0)}))
          }))
        }))
        .funcall(std::vector<ReQL::Query>({
          ReQL::db(std::vector<ReQL::Query>({
            ReQL::var(std::vector<ReQL::Query>({ReQL::Query(2.0)}))
          }))
          .wait(std::vector<ReQL::Query>())
        }))
      }))
    }))
    .run(conn).toVector().clear();

    conn.close();
  } catch (ReQL::ReQLError &e) {
    (void)e;
  }

  return result;
}
<|endoftext|>


<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "lid_allocator.h"
#include <vespa/searchlib/common/bitvectoriterator.h>
#include <vespa/searchlib/fef/termfieldmatchdataarray.h>
#include <vespa/searchlib/fef/matchdata.h>
#include <mutex>

#include <vespa/log/log.h>
LOG_SETUP(".proton.documentmetastore.lid_allocator");

using search::fef::TermFieldMatchDataArray;
using search::queryeval::Blueprint;
using search::queryeval::FieldSpecBaseList;
using search::queryeval::SearchIterator;
using search::queryeval::SimpleLeafBlueprint;
using vespalib::GenerationHolder;

namespace proton::documentmetastore {

LidAllocator::LidAllocator(uint32_t size,
                           uint32_t capacity,
                           GenerationHolder &genHolder)
    : _holdLids(),
      _freeLids(size, capacity, genHolder, true, false),
      _usedLids(size, capacity, genHolder, false, true),
      _pendingHoldLids(size, capacity, genHolder, false, false),
      _lidFreeListConstructed(false),
      _activeLids(size, capacity, genHolder, false, false),
      _numActiveLids(0u)
{

}

LidAllocator::~LidAllocator() = default;

LidAllocator::DocId
LidAllocator::getFreeLid(DocId lidLimit)
{
    DocId lid = _freeLids.getLowest();
    if (lid >= lidLimit) {
        lid = lidLimit;
    } else {
        _freeLids.clearBit(lid);
    }
    return lid;
}

LidAllocator::DocId
LidAllocator::peekFreeLid(DocId lidLimit)
{
    DocId lid = _freeLids.getLowest();
    if (lid >= lidLimit) {
        lid = lidLimit;
    }
    return lid;
}

void
LidAllocator::ensureSpace(uint32_t newSize, uint32_t newCapacity)
{
    _freeLids.resizeVector(newSize, newCapacity);
    _usedLids.resizeVector(newSize, newCapacity);
    _pendingHoldLids.resizeVector(newSize, newCapacity);
    _activeLids.resizeVector(newSize, newCapacity);
}

void
LidAllocator::unregisterLid(DocId lid)
{
    assert(!_pendingHoldLids.testBit(lid));
    if (isFreeListConstructed()) {
        _pendingHoldLids.setBit(lid);
    }
    _usedLids.clearBit(lid);
    if (_activeLids.testBit(lid)) {
        _activeLids.clearBit(lid);
        _numActiveLids.store(_activeLids.count(), std::memory_order_relaxed);
    }
}

void
LidAllocator::unregister_lids(const std::vector<DocId>& lids)
{
    if (lids.empty()) {
        return;
    }
    auto high = isFreeListConstructed() ? _pendingHoldLids.set_bits(lids) : _pendingHoldLids.assert_not_set_bits(lids);
    assert(high < _usedLids.size());
    _usedLids.clear_bits(lids);
    assert(high < _activeLids.size());
    _activeLids.consider_clear_bits(lids);
    _numActiveLids.store(_activeLids.count(), std::memory_order_relaxed);
}

void
LidAllocator::moveLidBegin(DocId fromLid, DocId toLid)
{
    (void) fromLid;
    assert(!_pendingHoldLids.testBit(fromLid));
    assert(!_pendingHoldLids.testBit(toLid));
    if (isFreeListConstructed()) {
        assert(!_freeLids.testBit(fromLid));
        assert(_freeLids.testBit(toLid));
        _freeLids.clearBit(toLid);
    }
}

void
LidAllocator::moveLidEnd(DocId fromLid, DocId toLid)
{
    if (isFreeListConstructed()) {
        // old lid must be scheduled for hold by caller
        _pendingHoldLids.setBit(fromLid);
    }
    _usedLids.setBit(toLid);
    _usedLids.clearBit(fromLid);
    if (_activeLids.testBit(fromLid)) {
        _activeLids.setBit(toLid);
        _activeLids.clearBit(fromLid);
    }
}

void
LidAllocator::holdLids(const std::vector<DocId> &lids,
                       DocId lidLimit,
                       generation_t currentGeneration)
{
    (void) lidLimit;
    for (const auto &lid : lids) {
        assert(lid > 0);
        assert(holdLidOK(lid, lidLimit));
        _pendingHoldLids.clearBit(lid);
        _holdLids.add(lid, currentGeneration);
    }
}

bool
LidAllocator::holdLidOK(DocId lid, DocId lidLimit) const
{
    if (_lidFreeListConstructed &&
        lid != 0 &&
        lid < lidLimit &&
        lid < _usedLids.size() &&
        lid < _pendingHoldLids.size() &&
        _pendingHoldLids.testBit(lid))
    {
        return true;
    }
    LOG(error,
        "LidAllocator::holdLidOK(%u, %u): "
        "_lidFreeListConstructed=%s, "
        "_usedLids.size()=%d, "
        "_pendingHoldLids.size()=%d, "
        "_pendingHoldLids bit=%s",
        lid, lidLimit,
        _lidFreeListConstructed ? "true" : "false",
        (int) _usedLids.size(),
        (int) _pendingHoldLids.size(),
        lid < _pendingHoldLids.size() ?
        (_pendingHoldLids.testBit(lid) ?
         "true" : "false" ) : "invalid"
        );
    return false;
}

void
LidAllocator::constructFreeList(DocId lidLimit)
{
    assert(!isFreeListConstructed());
    _holdLids.clear();
    for (uint32_t lid = 1; lid < lidLimit; ++lid) {
        if (!validLid(lid)) {
            _freeLids.setBit(lid);
        }
    }
}

namespace {

class WhiteListBlueprint : public SimpleLeafBlueprint
{
private:
    const search::BitVector &_activeLids;
    mutable std::mutex _lock;
    mutable std::vector<search::fef::TermFieldMatchData *> _matchDataVector;

    SearchIterator::UP
    createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override
    {
        assert(tfmda.size() == 0);
        (void) tfmda;
        return createFilterSearch(strict, FilterConstraint::UPPER_BOUND);
    }
public:
    WhiteListBlueprint(const search::BitVector &activeLids)
        : SimpleLeafBlueprint(FieldSpecBaseList()),
          _activeLids(activeLids),
          _matchDataVector()
    {
        size_t numHits = _activeLids.countTrueBits();
        setEstimate(HitEstimate(numHits, (numHits == 0)));
    }

    bool isWhiteList() const override { return true; }

    SearchIterator::UP createFilterSearch(bool strict, FilterConstraint) const override {
        auto tfmd = new search::fef::TermFieldMatchData;
        {
            std::lock_guard<std::mutex> lock(_lock);
            _matchDataVector.push_back(tfmd);
        }
        return search::BitVectorIterator::create(&_activeLids, get_docid_limit(), *tfmd, strict);
    }

    ~WhiteListBlueprint() {
        for (auto matchData : _matchDataVector) {
            delete matchData;
        }
    }
};

}

Blueprint::UP
LidAllocator::createWhiteListBlueprint() const
{
    return std::make_unique<WhiteListBlueprint>(_activeLids.getBitVector());
}

void
LidAllocator::updateActiveLids(DocId lid, bool active)
{
    bool oldActive = _activeLids.testBit(lid);
    if (oldActive != active) {
        if (active) {
            _activeLids.setBit(lid);
        } else {
            _activeLids.clearBit(lid);
        }
        _numActiveLids.store(_activeLids.count(), std::memory_order_relaxed);
    }
}

void
LidAllocator::clearDocs(DocId lidLow, DocId lidLimit)
{
    (void) lidLow;
    (void) lidLimit;
    assert(_usedLids.getNextTrueBit(lidLow) >= lidLimit);
}

void
LidAllocator::shrinkLidSpace(DocId committedDocIdLimit)
{
    ensureSpace(committedDocIdLimit, committedDocIdLimit);
}

}
<commit_msg>Revert "Count number of bits to create a better estimate of number of hits it…"<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "lid_allocator.h"
#include <vespa/searchlib/common/bitvectoriterator.h>
#include <vespa/searchlib/fef/termfieldmatchdataarray.h>
#include <vespa/searchlib/fef/matchdata.h>
#include <mutex>

#include <vespa/log/log.h>
LOG_SETUP(".proton.documentmetastore.lid_allocator");

using search::fef::TermFieldMatchDataArray;
using search::queryeval::Blueprint;
using search::queryeval::FieldSpecBaseList;
using search::queryeval::SearchIterator;
using search::queryeval::SimpleLeafBlueprint;
using vespalib::GenerationHolder;

namespace proton::documentmetastore {

LidAllocator::LidAllocator(uint32_t size,
                           uint32_t capacity,
                           GenerationHolder &genHolder)
    : _holdLids(),
      _freeLids(size, capacity, genHolder, true, false),
      _usedLids(size, capacity, genHolder, false, true),
      _pendingHoldLids(size, capacity, genHolder, false, false),
      _lidFreeListConstructed(false),
      _activeLids(size, capacity, genHolder, false, false),
      _numActiveLids(0u)
{

}

LidAllocator::~LidAllocator() = default;

LidAllocator::DocId
LidAllocator::getFreeLid(DocId lidLimit)
{
    DocId lid = _freeLids.getLowest();
    if (lid >= lidLimit) {
        lid = lidLimit;
    } else {
        _freeLids.clearBit(lid);
    }
    return lid;
}

LidAllocator::DocId
LidAllocator::peekFreeLid(DocId lidLimit)
{
    DocId lid = _freeLids.getLowest();
    if (lid >= lidLimit) {
        lid = lidLimit;
    }
    return lid;
}

void
LidAllocator::ensureSpace(uint32_t newSize, uint32_t newCapacity)
{
    _freeLids.resizeVector(newSize, newCapacity);
    _usedLids.resizeVector(newSize, newCapacity);
    _pendingHoldLids.resizeVector(newSize, newCapacity);
    _activeLids.resizeVector(newSize, newCapacity);
}

void
LidAllocator::unregisterLid(DocId lid)
{
    assert(!_pendingHoldLids.testBit(lid));
    if (isFreeListConstructed()) {
        _pendingHoldLids.setBit(lid);
    }
    _usedLids.clearBit(lid);
    if (_activeLids.testBit(lid)) {
        _activeLids.clearBit(lid);
        _numActiveLids.store(_activeLids.count(), std::memory_order_relaxed);
    }
}

void
LidAllocator::unregister_lids(const std::vector<DocId>& lids)
{
    if (lids.empty()) {
        return;
    }
    auto high = isFreeListConstructed() ? _pendingHoldLids.set_bits(lids) : _pendingHoldLids.assert_not_set_bits(lids);
    assert(high < _usedLids.size());
    _usedLids.clear_bits(lids);
    assert(high < _activeLids.size());
    _activeLids.consider_clear_bits(lids);
    _numActiveLids.store(_activeLids.count(), std::memory_order_relaxed);
}

void
LidAllocator::moveLidBegin(DocId fromLid, DocId toLid)
{
    (void) fromLid;
    assert(!_pendingHoldLids.testBit(fromLid));
    assert(!_pendingHoldLids.testBit(toLid));
    if (isFreeListConstructed()) {
        assert(!_freeLids.testBit(fromLid));
        assert(_freeLids.testBit(toLid));
        _freeLids.clearBit(toLid);
    }
}

void
LidAllocator::moveLidEnd(DocId fromLid, DocId toLid)
{
    if (isFreeListConstructed()) {
        // old lid must be scheduled for hold by caller
        _pendingHoldLids.setBit(fromLid);
    }
    _usedLids.setBit(toLid);
    _usedLids.clearBit(fromLid);
    if (_activeLids.testBit(fromLid)) {
        _activeLids.setBit(toLid);
        _activeLids.clearBit(fromLid);
    }
}

void
LidAllocator::holdLids(const std::vector<DocId> &lids,
                       DocId lidLimit,
                       generation_t currentGeneration)
{
    (void) lidLimit;
    for (const auto &lid : lids) {
        assert(lid > 0);
        assert(holdLidOK(lid, lidLimit));
        _pendingHoldLids.clearBit(lid);
        _holdLids.add(lid, currentGeneration);
    }
}

bool
LidAllocator::holdLidOK(DocId lid, DocId lidLimit) const
{
    if (_lidFreeListConstructed &&
        lid != 0 &&
        lid < lidLimit &&
        lid < _usedLids.size() &&
        lid < _pendingHoldLids.size() &&
        _pendingHoldLids.testBit(lid))
    {
        return true;
    }
    LOG(error,
        "LidAllocator::holdLidOK(%u, %u): "
        "_lidFreeListConstructed=%s, "
        "_usedLids.size()=%d, "
        "_pendingHoldLids.size()=%d, "
        "_pendingHoldLids bit=%s",
        lid, lidLimit,
        _lidFreeListConstructed ? "true" : "false",
        (int) _usedLids.size(),
        (int) _pendingHoldLids.size(),
        lid < _pendingHoldLids.size() ?
        (_pendingHoldLids.testBit(lid) ?
         "true" : "false" ) : "invalid"
        );
    return false;
}

void
LidAllocator::constructFreeList(DocId lidLimit)
{
    assert(!isFreeListConstructed());
    _holdLids.clear();
    for (uint32_t lid = 1; lid < lidLimit; ++lid) {
        if (!validLid(lid)) {
            _freeLids.setBit(lid);
        }
    }
}

namespace {

class WhiteListBlueprint : public SimpleLeafBlueprint
{
private:
    const search::BitVector &_activeLids;
    mutable std::mutex _lock;
    mutable std::vector<search::fef::TermFieldMatchData *> _matchDataVector;

    SearchIterator::UP
    createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override
    {
        assert(tfmda.size() == 0);
        (void) tfmda;
        return createFilterSearch(strict, FilterConstraint::UPPER_BOUND);
    }
public:
    WhiteListBlueprint(const search::BitVector &activeLids)
        : SimpleLeafBlueprint(FieldSpecBaseList()),
          _activeLids(activeLids),
          _matchDataVector()
    {
        setEstimate(HitEstimate(_activeLids.size(), false));
    }

    bool isWhiteList() const override { return true; }

    SearchIterator::UP createFilterSearch(bool strict, FilterConstraint) const override {
        auto tfmd = new search::fef::TermFieldMatchData;
        {
            std::lock_guard<std::mutex> lock(_lock);
            _matchDataVector.push_back(tfmd);
        }
        return search::BitVectorIterator::create(&_activeLids, get_docid_limit(), *tfmd, strict);
    }

    ~WhiteListBlueprint() {
        for (auto matchData : _matchDataVector) {
            delete matchData;
        }
    }
};

}

Blueprint::UP
LidAllocator::createWhiteListBlueprint() const
{
    return std::make_unique<WhiteListBlueprint>(_activeLids.getBitVector());
}

void
LidAllocator::updateActiveLids(DocId lid, bool active)
{
    bool oldActive = _activeLids.testBit(lid);
    if (oldActive != active) {
        if (active) {
            _activeLids.setBit(lid);
        } else {
            _activeLids.clearBit(lid);
        }
        _numActiveLids.store(_activeLids.count(), std::memory_order_relaxed);
    }
}

void
LidAllocator::clearDocs(DocId lidLow, DocId lidLimit)
{
    (void) lidLow;
    (void) lidLimit;
    assert(_usedLids.getNextTrueBit(lidLow) >= lidLimit);
}

void
LidAllocator::shrinkLidSpace(DocId committedDocIdLimit)
{
    ensureSpace(committedDocIdLimit, committedDocIdLimit);
}

}
<|endoftext|>


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

/*
 * Description:
 *     a simple version of meta state service for development
 *
 * Revision history:
 *     2015-11-04, @imzhenyu (Zhenyu.Guo@microsoft.com), setup the sketch
 *     2015-11-11, Tianyi WANG, first version done
 *     xxxx-xx-xx, author, fix bug about xxx
 */

# include "meta_state_service_simple.h"
# include <dsn/internal/task.h>

# include <stack>
# include <utility>

namespace dsn
{
    namespace dist
    {
        // path: /, /n1/n2, /n1/n2/, /n2/n2/n3
        std::string meta_state_service_simple::normalize_path(const std::string& s)
        {
            if (s.empty() || s[0] != '/')
                return "";
            if (s.length() > 1 && *s.rbegin() == '/')
                return s.substr(0, s.length() - 1);
            return s;
        }

        error_code meta_state_service_simple::extract_name_parent_from_path(
            const std::string& s,
            /*out*/ std::string& name,
            /*out*/ std::string& parent
            )
        {
            auto pos = s.find_last_of('/');
            if (pos == std::string::npos)
                return ERR_INVALID_PARAMETERS;

            name = s.substr(pos + 1);
            if (pos > 0)
                parent = s.substr(0, pos);
            else
                parent = "/";
            return ERR_OK;
        }

        static void __err_cb_bind_and_enqueue(
            task_ptr lock_task,
            error_code err,
            int delay_milliseconds = 0
            )
        {
            auto t = dynamic_cast<safe_late_task<meta_state_service::err_callback>*>(lock_task.get());

            t->bind_and_enqueue(
                [&](meta_state_service::err_callback& cb)
                {
                    return bind(cb, err);
                },
                delay_milliseconds
                );
        }

        void meta_state_service_simple::write_log(blob&& log_blob, std::function<error_code()> internal_operation, task_ptr task)
        {
            _log_lock.lock();
            uint64_t log_offset = _offset;
            _offset += log_blob.length();
            auto continuation_task = std::unique_ptr<operation>(new operation(false, [=](bool log_succeed)
            {
                dassert(log_succeed, "we cannot handle logging failure now");
                __err_cb_bind_and_enqueue(task, internal_operation(), 0);
            }));
            auto continuation_task_ptr = continuation_task.get();
            _task_queue.emplace(move(continuation_task));
            _log_lock.unlock();

            file::write(
                _log,
                log_blob.buffer_ptr(),
                log_blob.length(),
                log_offset,
                LPC_META_STATE_SERVICE_SIMPLE_INTERNAL,
                this,
                [=](error_code err, size_t bytes)
                {
                    dassert(err == ERR_OK && bytes == log_blob.length(), "we cannot handle logging failure now");
                    _log_lock.lock();
                    continuation_task_ptr->done = true;
                    while (!_task_queue.empty())
                    {
                        if (!_task_queue.front()->done)
                        {
                            break;
                        }
                        _task_queue.front()->cb(true);
                        _task_queue.pop();
                    }
                    _log_lock.unlock();
                }
                );
        }

        error_code meta_state_service_simple::create_node_internal(const std::string& node, const blob& value)
        {
            auto path = normalize_path(node);
            zauto_lock _(_state_lock);
            auto me_it = _quick_map.find(path);
            if (me_it != _quick_map.end())
                return ERR_NODE_ALREADY_EXIST;

            std::string name, parent;
            auto err = extract_name_parent_from_path(path, name, parent);
            if (err != ERR_OK)
            {
                return err;
            }

            auto parent_it = _quick_map.find(parent);
            if (parent_it == _quick_map.end())
                return ERR_OBJECT_NOT_FOUND;

            state_node* n = new state_node(name, parent_it->second, value);
            parent_it->second->children.insert(quick_map::value_type(name, n));
            _quick_map.insert(quick_map::value_type(path, n));
            return ERR_OK;
        }

        error_code meta_state_service_simple::delete_node_internal(const std::string& node, bool recursive)
        {
            auto path = normalize_path(node);
            if (path == "/")
                return ERR_INVALID_PARAMETERS; // cannot delete root
            zauto_lock _(_state_lock);
            auto me_it = _quick_map.find(path);
            if (me_it == _quick_map.end())
                return ERR_OBJECT_NOT_FOUND;
            if (!recursive && !me_it->second->children.empty())
                return ERR_INVALID_PARAMETERS;

            struct delete_state
            {
                std::string path;
                state_node *node;
                decltype(state_node::children)::iterator next_child_to_delete;
            };
            std::stack<delete_state> delete_stack;
            delete_stack.push({ path, me_it->second, me_it->second->children.begin() });
            for (; !delete_stack.empty();)
            {
                auto &node_pair = delete_stack.top();
                if (node_pair.node->children.end() == node_pair.next_child_to_delete)
                {
                    auto delnum = _quick_map.erase(node_pair.path);
                    dassert(delnum == 1, "inconsistent state between quick map and tree");
                    delete node_pair.node;
                    delete_stack.pop();
                }
                else
                {
                    auto child_it = node_pair.next_child_to_delete;
                    delete_stack.push({ node_pair.path + "/" + child_it->second->name, child_it->second, child_it->second->children.begin() });
                    ++node_pair.next_child_to_delete;
                }
            }

            std::string name, parent;
            auto err = extract_name_parent_from_path(path, name, parent);
            if (err != ERR_OK)
            {
                return err;
            }

            auto parent_it = _quick_map.find(parent);
            dassert(parent_it != _quick_map.end(), "unable to find parent node");
            //XXX we cannot delete root, right?

            auto erase_num = parent_it->second->children.erase(name);
            dassert(erase_num == 1, "inconsistent state between quick map and tree");
            return ERR_OK;
        }

        error_code meta_state_service_simple::set_data_internal(const std::string& node, const blob& value)
        {
            auto path = normalize_path(node);
            zauto_lock _(_state_lock);
            auto it = _quick_map.find(path);
            if (it == _quick_map.end())
                return ERR_OBJECT_NOT_FOUND;
            it->second->data = value;
            return ERR_OK;
        }

        error_code meta_state_service_simple::initialize(const char* dir)
        {
            _offset = 0;
            std::string log_path = dsn::utils::filesystem::path_combine(dir, "meta_state_service.log");
            if (utils::filesystem::file_exists(log_path))
            {
                if (FILE* fd = fopen(log_path.c_str(), "rb"))
                {
                    for (;;)
                    {
                        log_header header;
                        if (fread(&header, sizeof(log_header), 1, fd) != 1)
                        {
                            break;
                        }
                        if (header.magic != log_header::default_magic)
                        {
                            break;
                        }
                        std::shared_ptr<char> buffer(new char[header.size]);
                        if (fread(buffer.get(), header.size, 1, fd) != 1)
                        {
                            break;
                        }
                        _offset += sizeof(header) + header.size;
                        blob blob_wrapper(buffer, (int)header.size);
                        binary_reader reader(blob_wrapper);
                        int op_type;
                        unmarshall(reader, op_type);
                        switch (static_cast<operation_type>(op_type))
                        {
                        case operation_type::create_node:
                        {
                            std::string node;
                            blob data;
                            create_node_log::parse(reader, node, data);
                            create_node_internal(node, data).end_tracking();
                            break;
                        }
                        case operation_type::delete_node:
                        {
                            std::string node;
                            bool recursively_delete;
                            delete_node_log::parse(reader, node, recursively_delete);
                            delete_node_internal(node, recursively_delete).end_tracking();
                            break;
                        }
                        case operation_type::set_data:
                        {
                            std::string node;
                            blob data;
                            set_data_log::parse(reader, node, data);
                            set_data_internal(node, data).end_tracking();
                            break;
                        }
                        default:
                            //The log is complete but its content is modified by cosmic ray. This is unacceptable
                            dassert(false, "meta state server log corrupted");
                        }
                    }
                    fclose(fd);
                }
            }

            _log = dsn_file_open(log_path.c_str(), O_RDWR | O_CREAT | O_BINARY, 0666);
            if (!_log)
            {
                derror("open file failed: %s", log_path.c_str());
                return ERR_FILE_OPERATION_FAILED;
            }
            return ERR_OK;
        }

        task_ptr meta_state_service_simple::create_node(
            const std::string& node,
            task_code cb_code,
            const err_callback& cb_create,
            const blob& value,
            clientlet* tracker )
        {
            auto task = tasking::create_late_task(cb_code, cb_create, 0, tracker);
            write_log(
                create_node_log::get_log(node, value),
                [=]{
                    return create_node_internal(node, value);
                },
                task
                );
            return task;
        }

        task_ptr meta_state_service_simple::delete_node(
            const std::string& node,
            bool recursively_delete,
            task_code cb_code,
            const err_callback& cb_delete,
            clientlet* tracker)
        {
            auto task = tasking::create_late_task(cb_code, cb_delete, 0, tracker);
            write_log(
                delete_node_log::get_log(node, recursively_delete),
                [=] {
                    return delete_node_internal(node, recursively_delete);
                },
                task
                );
            return task;
        }

        task_ptr meta_state_service_simple::node_exist(
            const std::string& node,
            task_code cb_code,
            const err_callback& cb_exist,
            clientlet* tracker)
        {
            error_code err;
            {
                zauto_lock _(_state_lock);
                err = _quick_map.find(normalize_path(node)) != _quick_map.end() ? ERR_OK : ERR_PATH_NOT_FOUND;
            }
            return tasking::enqueue(
                cb_code,
                tracker,
                [=]()
                {
                    cb_exist(err);
                }
                );
        }

        task_ptr meta_state_service_simple::get_data(
            const std::string& node,
            task_code cb_code,
            const err_value_callback& cb_get_data,
            clientlet* tracker)
        {
            auto path = normalize_path(node);
            zauto_lock _(_state_lock);
            auto me_it = _quick_map.find(path);
            if (me_it == _quick_map.end())
            {
                return tasking::enqueue(
                    cb_code,
                    tracker,
                    [=]()
                    {
                        cb_get_data(ERR_OBJECT_NOT_FOUND, {});
                    }
                    );
            }
            else
            {
                auto data_copy = me_it->second->data;
                return tasking::enqueue(
                    cb_code,
                    tracker,
                    [=]() mutable
                    {
                        cb_get_data(ERR_OK, std::move(data_copy));
                    }
                    );
            }
        }

        task_ptr meta_state_service_simple::set_data(
            const std::string& node,
            const blob& value,
            task_code cb_code,
            const err_callback& cb_set_data,
            clientlet* tracker)
        {
            auto task = tasking::create_late_task(cb_code, cb_set_data, 0, tracker);
            write_log(
                set_data_log::get_log(node, value),
                [=] {
                    return set_data_internal(node, value);
                },
                task
                );
            return task;
        }

        task_ptr meta_state_service_simple::get_children(
            const std::string& node,
            task_code cb_code,
            const err_stringv_callback& cb_get_children,
            clientlet* tracker)
        {
            auto path = normalize_path(node);
            zauto_lock _(_state_lock);
            auto me_it = _quick_map.find(path);
            if (me_it == _quick_map.end())
            {
                return tasking::enqueue(
                    cb_code,
                    tracker,
                    [=]()
                    {
                        cb_get_children(ERR_OBJECT_NOT_FOUND, {});
                    }
                    );
            }
            else
            {
                std::vector<std::string> result;
                for (auto &child_pair : me_it->second->children)
                {
                    result.push_back(child_pair.first);
                }
                return tasking::enqueue(
                    cb_code,
                    tracker,
                    [=]() mutable
                    {
                        cb_get_children(ERR_OK, move(result));
                    }
                    );
            }
        }

        meta_state_service_simple::~meta_state_service_simple()
        {
            dsn_file_close(_log);
        }
    }
}
<commit_msg>using task_ptr instead of auto for return value from create_late_task to avoid non-referenced object<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Microsoft Corporation
 *
 * -=- Robust Distributed System Nucleus (rDSN) -=-
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*
 * Description:
 *     a simple version of meta state service for development
 *
 * Revision history:
 *     2015-11-04, @imzhenyu (Zhenyu.Guo@microsoft.com), setup the sketch
 *     2015-11-11, Tianyi WANG, first version done
 *     xxxx-xx-xx, author, fix bug about xxx
 */

# include "meta_state_service_simple.h"
# include <dsn/internal/task.h>

# include <stack>
# include <utility>

namespace dsn
{
    namespace dist
    {
        // path: /, /n1/n2, /n1/n2/, /n2/n2/n3
        std::string meta_state_service_simple::normalize_path(const std::string& s)
        {
            if (s.empty() || s[0] != '/')
                return "";
            if (s.length() > 1 && *s.rbegin() == '/')
                return s.substr(0, s.length() - 1);
            return s;
        }

        error_code meta_state_service_simple::extract_name_parent_from_path(
            const std::string& s,
            /*out*/ std::string& name,
            /*out*/ std::string& parent
            )
        {
            auto pos = s.find_last_of('/');
            if (pos == std::string::npos)
                return ERR_INVALID_PARAMETERS;

            name = s.substr(pos + 1);
            if (pos > 0)
                parent = s.substr(0, pos);
            else
                parent = "/";
            return ERR_OK;
        }

        static void __err_cb_bind_and_enqueue(
            task_ptr lock_task,
            error_code err,
            int delay_milliseconds = 0
            )
        {
            auto t = dynamic_cast<safe_late_task<meta_state_service::err_callback>*>(lock_task.get());

            t->bind_and_enqueue(
                [&](meta_state_service::err_callback& cb)
                {
                    return bind(cb, err);
                },
                delay_milliseconds
                );
        }

        void meta_state_service_simple::write_log(blob&& log_blob, std::function<error_code()> internal_operation, task_ptr task)
        {
            _log_lock.lock();
            uint64_t log_offset = _offset;
            _offset += log_blob.length();
            auto continuation_task = std::unique_ptr<operation>(new operation(false, [=](bool log_succeed)
            {
                dassert(log_succeed, "we cannot handle logging failure now");
                __err_cb_bind_and_enqueue(task, internal_operation(), 0);
            }));
            auto continuation_task_ptr = continuation_task.get();
            _task_queue.emplace(move(continuation_task));
            _log_lock.unlock();

            file::write(
                _log,
                log_blob.buffer_ptr(),
                log_blob.length(),
                log_offset,
                LPC_META_STATE_SERVICE_SIMPLE_INTERNAL,
                this,
                [=](error_code err, size_t bytes)
                {
                    dassert(err == ERR_OK && bytes == log_blob.length(), "we cannot handle logging failure now");
                    _log_lock.lock();
                    continuation_task_ptr->done = true;
                    while (!_task_queue.empty())
                    {
                        if (!_task_queue.front()->done)
                        {
                            break;
                        }
                        _task_queue.front()->cb(true);
                        _task_queue.pop();
                    }
                    _log_lock.unlock();
                }
                );
        }

        error_code meta_state_service_simple::create_node_internal(const std::string& node, const blob& value)
        {
            auto path = normalize_path(node);
            zauto_lock _(_state_lock);
            auto me_it = _quick_map.find(path);
            if (me_it != _quick_map.end())
                return ERR_NODE_ALREADY_EXIST;

            std::string name, parent;
            auto err = extract_name_parent_from_path(path, name, parent);
            if (err != ERR_OK)
            {
                return err;
            }

            auto parent_it = _quick_map.find(parent);
            if (parent_it == _quick_map.end())
                return ERR_OBJECT_NOT_FOUND;

            state_node* n = new state_node(name, parent_it->second, value);
            parent_it->second->children.insert(quick_map::value_type(name, n));
            _quick_map.insert(quick_map::value_type(path, n));
            return ERR_OK;
        }

        error_code meta_state_service_simple::delete_node_internal(const std::string& node, bool recursive)
        {
            auto path = normalize_path(node);
            if (path == "/")
                return ERR_INVALID_PARAMETERS; // cannot delete root
            zauto_lock _(_state_lock);
            auto me_it = _quick_map.find(path);
            if (me_it == _quick_map.end())
                return ERR_OBJECT_NOT_FOUND;
            if (!recursive && !me_it->second->children.empty())
                return ERR_INVALID_PARAMETERS;

            struct delete_state
            {
                std::string path;
                state_node *node;
                decltype(state_node::children)::iterator next_child_to_delete;
            };
            std::stack<delete_state> delete_stack;
            delete_stack.push({ path, me_it->second, me_it->second->children.begin() });
            for (; !delete_stack.empty();)
            {
                auto &node_pair = delete_stack.top();
                if (node_pair.node->children.end() == node_pair.next_child_to_delete)
                {
                    auto delnum = _quick_map.erase(node_pair.path);
                    dassert(delnum == 1, "inconsistent state between quick map and tree");
                    delete node_pair.node;
                    delete_stack.pop();
                }
                else
                {
                    auto child_it = node_pair.next_child_to_delete;
                    delete_stack.push({ node_pair.path + "/" + child_it->second->name, child_it->second, child_it->second->children.begin() });
                    ++node_pair.next_child_to_delete;
                }
            }

            std::string name, parent;
            auto err = extract_name_parent_from_path(path, name, parent);
            if (err != ERR_OK)
            {
                return err;
            }

            auto parent_it = _quick_map.find(parent);
            dassert(parent_it != _quick_map.end(), "unable to find parent node");
            //XXX we cannot delete root, right?

            auto erase_num = parent_it->second->children.erase(name);
            dassert(erase_num == 1, "inconsistent state between quick map and tree");
            return ERR_OK;
        }

        error_code meta_state_service_simple::set_data_internal(const std::string& node, const blob& value)
        {
            auto path = normalize_path(node);
            zauto_lock _(_state_lock);
            auto it = _quick_map.find(path);
            if (it == _quick_map.end())
                return ERR_OBJECT_NOT_FOUND;
            it->second->data = value;
            return ERR_OK;
        }

        error_code meta_state_service_simple::initialize(const char* dir)
        {
            _offset = 0;
            std::string log_path = dsn::utils::filesystem::path_combine(dir, "meta_state_service.log");
            if (utils::filesystem::file_exists(log_path))
            {
                if (FILE* fd = fopen(log_path.c_str(), "rb"))
                {
                    for (;;)
                    {
                        log_header header;
                        if (fread(&header, sizeof(log_header), 1, fd) != 1)
                        {
                            break;
                        }
                        if (header.magic != log_header::default_magic)
                        {
                            break;
                        }
                        std::shared_ptr<char> buffer(new char[header.size]);
                        if (fread(buffer.get(), header.size, 1, fd) != 1)
                        {
                            break;
                        }
                        _offset += sizeof(header) + header.size;
                        blob blob_wrapper(buffer, (int)header.size);
                        binary_reader reader(blob_wrapper);
                        int op_type;
                        unmarshall(reader, op_type);
                        switch (static_cast<operation_type>(op_type))
                        {
                        case operation_type::create_node:
                        {
                            std::string node;
                            blob data;
                            create_node_log::parse(reader, node, data);
                            create_node_internal(node, data).end_tracking();
                            break;
                        }
                        case operation_type::delete_node:
                        {
                            std::string node;
                            bool recursively_delete;
                            delete_node_log::parse(reader, node, recursively_delete);
                            delete_node_internal(node, recursively_delete).end_tracking();
                            break;
                        }
                        case operation_type::set_data:
                        {
                            std::string node;
                            blob data;
                            set_data_log::parse(reader, node, data);
                            set_data_internal(node, data).end_tracking();
                            break;
                        }
                        default:
                            //The log is complete but its content is modified by cosmic ray. This is unacceptable
                            dassert(false, "meta state server log corrupted");
                        }
                    }
                    fclose(fd);
                }
            }

            _log = dsn_file_open(log_path.c_str(), O_RDWR | O_CREAT | O_BINARY, 0666);
            if (!_log)
            {
                derror("open file failed: %s", log_path.c_str());
                return ERR_FILE_OPERATION_FAILED;
            }
            return ERR_OK;
        }

        task_ptr meta_state_service_simple::create_node(
            const std::string& node,
            task_code cb_code,
            const err_callback& cb_create,
            const blob& value,
            clientlet* tracker )
        {
            task_ptr task = tasking::create_late_task(cb_code, cb_create, 0, tracker);
            write_log(
                create_node_log::get_log(node, value),
                [=]{
                    return create_node_internal(node, value);
                },
                task
                );
            return task;
        }

        task_ptr meta_state_service_simple::delete_node(
            const std::string& node,
            bool recursively_delete,
            task_code cb_code,
            const err_callback& cb_delete,
            clientlet* tracker)
        {
            task_ptr task = tasking::create_late_task(cb_code, cb_delete, 0, tracker);
            write_log(
                delete_node_log::get_log(node, recursively_delete),
                [=] {
                    return delete_node_internal(node, recursively_delete);
                },
                task
                );
            return task;
        }

        task_ptr meta_state_service_simple::node_exist(
            const std::string& node,
            task_code cb_code,
            const err_callback& cb_exist,
            clientlet* tracker)
        {
            error_code err;
            {
                zauto_lock _(_state_lock);
                err = _quick_map.find(normalize_path(node)) != _quick_map.end() ? ERR_OK : ERR_PATH_NOT_FOUND;
            }
            return tasking::enqueue(
                cb_code,
                tracker,
                [=]()
                {
                    cb_exist(err);
                }
                );
        }

        task_ptr meta_state_service_simple::get_data(
            const std::string& node,
            task_code cb_code,
            const err_value_callback& cb_get_data,
            clientlet* tracker)
        {
            auto path = normalize_path(node);
            zauto_lock _(_state_lock);
            auto me_it = _quick_map.find(path);
            if (me_it == _quick_map.end())
            {
                return tasking::enqueue(
                    cb_code,
                    tracker,
                    [=]()
                    {
                        cb_get_data(ERR_OBJECT_NOT_FOUND, {});
                    }
                    );
            }
            else
            {
                auto data_copy = me_it->second->data;
                return tasking::enqueue(
                    cb_code,
                    tracker,
                    [=]() mutable
                    {
                        cb_get_data(ERR_OK, std::move(data_copy));
                    }
                    );
            }
        }

        task_ptr meta_state_service_simple::set_data(
            const std::string& node,
            const blob& value,
            task_code cb_code,
            const err_callback& cb_set_data,
            clientlet* tracker)
        {
            task_ptr task = tasking::create_late_task(cb_code, cb_set_data, 0, tracker);
            write_log(
                set_data_log::get_log(node, value),
                [=] {
                    return set_data_internal(node, value);
                },
                task
                );
            return task;
        }

        task_ptr meta_state_service_simple::get_children(
            const std::string& node,
            task_code cb_code,
            const err_stringv_callback& cb_get_children,
            clientlet* tracker)
        {
            auto path = normalize_path(node);
            zauto_lock _(_state_lock);
            auto me_it = _quick_map.find(path);
            if (me_it == _quick_map.end())
            {
                return tasking::enqueue(
                    cb_code,
                    tracker,
                    [=]()
                    {
                        cb_get_children(ERR_OBJECT_NOT_FOUND, {});
                    }
                    );
            }
            else
            {
                std::vector<std::string> result;
                for (auto &child_pair : me_it->second->children)
                {
                    result.push_back(child_pair.first);
                }
                return tasking::enqueue(
                    cb_code,
                    tracker,
                    [=]() mutable
                    {
                        cb_get_children(ERR_OK, move(result));
                    }
                    );
            }
        }

        meta_state_service_simple::~meta_state_service_simple()
        {
            dsn_file_close(_log);
        }
    }
}
<|endoftext|>


<commit_before>#include "profile.hpp"
#include "../../rdb/rdb.hpp"
#include "../../utils/utils.hpp"
#include <cerrno>

static unsigned long nsols;

static void dfline(std::vector<std::string>&, void*);

int main(int argc, const char *argv[]) {
	if (argc < 4)
		fatal("usage: mkprof: <rdb root> <cost bins> <time bins> [key=value*]");

	const char *root = argv[1];
	printf("root: %s\n", root);

	errno = 0;
	char *end;
	unsigned int ncost = strtol(argv[2], &end, 10);
	if (end == argv[2])
		fatal("Invalid number of cost bins: %s", argv[2]);
	printf("%u cost bins\n", ncost);

	unsigned int ntime = strtol(argv[3], &end, 10);
	if (end == argv[3])
		fatal("Invalid number of time bins: %s", argv[3]);
	printf("%u time bins\n", ntime);

	RdbAttrs attrs = attrargs(argc-4, argv+4);
	printf("attributes:\n");
	for (auto k = attrs.getkeys().begin(); k != attrs.getkeys().end(); k++)
		printf("\t%s=%s\n", k->c_str(), attrs.lookup(*k).c_str());
	if (!attrs.mem("alg"))
		fatal("alg attribute must be specified");

	std::vector<std::string> paths = withattrs(root, attrs);
	printf("%lu data files\n", paths.size());

	std::vector<AnytimeProfile::SolutionStream> stream;
	for (auto p = paths.begin(); p != paths.end(); p++) {
		FILE *f = fopen(p->c_str(), "r");
		if (!f) {
			warnx(errno, "failed to open %s for reading", p->c_str());
			continue;
		}

		AnytimeProfile::SolutionStream sols;
		dfread(f, dfline, &sols, NULL);
		stream.push_back(sols);

		fclose(f);
	}
	printf("%lu solutions\n", nsols);

	AnytimeProfile prof(ncost, ntime, stream);

	std::string alg = attrs.lookup("alg");
	attrs.rm("alg");
	attrs.push_back("alg", alg+".profile");
	attrs.push_back("cost bins", argv[2]);
	attrs.push_back("time bins", argv[3]);
	std::string opath = pathfor(root, attrs);
	printf("saving profile to %s\n", opath.c_str());

	FILE *f = fopen(opath.c_str(), "w");
	if (!f)
		fatal("failed to open %s for writing", opath.c_str());
	prof.save(f);
	fclose(f);

	return 0;
}

static void dfline(std::vector<std::string> &line, void *aux) {
	AnytimeProfile::SolutionStream *sols = static_cast<AnytimeProfile::SolutionStream*>(aux);

	// sol is the deprecated altrow name for ARA*
	// incumbent solutions, incumbent is the new
	// name.
	if (line[0] != "#altrow" || (line[1] != "sol" && line[1] != "incumbent"))
		return;

	AnytimeProfile::Solution sol;
	sol.cost = strtod(line[7].c_str(), NULL);
	sol.time = strtod(line[8].c_str(), NULL);
	sols->push_back(sol);
	nsols++;
}<commit_msg>mkprof: exit gracefully if there are no solutions.<commit_after>#include "profile.hpp"
#include "../../rdb/rdb.hpp"
#include "../../utils/utils.hpp"
#include <cerrno>

static unsigned long nsols;

static void dfline(std::vector<std::string>&, void*);

int main(int argc, const char *argv[]) {
	if (argc < 4)
		fatal("usage: mkprof: <rdb root> <cost bins> <time bins> [key=value*]");

	const char *root = argv[1];
	printf("root: %s\n", root);

	errno = 0;
	char *end;
	unsigned int ncost = strtol(argv[2], &end, 10);
	if (end == argv[2])
		fatal("Invalid number of cost bins: %s", argv[2]);
	printf("%u cost bins\n", ncost);

	unsigned int ntime = strtol(argv[3], &end, 10);
	if (end == argv[3])
		fatal("Invalid number of time bins: %s", argv[3]);
	printf("%u time bins\n", ntime);

	RdbAttrs attrs = attrargs(argc-4, argv+4);
	printf("attributes:\n");
	for (auto k = attrs.getkeys().begin(); k != attrs.getkeys().end(); k++)
		printf("\t%s=%s\n", k->c_str(), attrs.lookup(*k).c_str());
	if (!attrs.mem("alg"))
		fatal("alg attribute must be specified");

	std::vector<std::string> paths = withattrs(root, attrs);
	printf("%lu data files\n", paths.size());

	std::vector<AnytimeProfile::SolutionStream> stream;
	for (auto p = paths.begin(); p != paths.end(); p++) {
		FILE *f = fopen(p->c_str(), "r");
		if (!f) {
			warnx(errno, "failed to open %s for reading", p->c_str());
			continue;
		}

		AnytimeProfile::SolutionStream sols;
		dfread(f, dfline, &sols, NULL);
		stream.push_back(sols);

		fclose(f);
	}
	printf("%lu solutions\n", nsols);
	if (nsols == 0) {
		puts("No solutions");
		return 1;
	}

	AnytimeProfile prof(ncost, ntime, stream);

	std::string alg = attrs.lookup("alg");
	attrs.rm("alg");
	attrs.push_back("alg", alg+".profile");
	attrs.push_back("cost bins", argv[2]);
	attrs.push_back("time bins", argv[3]);
	std::string opath = pathfor(root, attrs);
	printf("saving profile to %s\n", opath.c_str());

	FILE *f = fopen(opath.c_str(), "w");
	if (!f)
		fatal("failed to open %s for writing", opath.c_str());
	prof.save(f);
	fclose(f);

	return 0;
}

static void dfline(std::vector<std::string> &line, void *aux) {
	AnytimeProfile::SolutionStream *sols = static_cast<AnytimeProfile::SolutionStream*>(aux);

	// sol is the deprecated altrow name for ARA*
	// incumbent solutions, incumbent is the new
	// name.
	if (line[0] != "#altrow" || (line[1] != "sol" && line[1] != "incumbent"))
		return;

	AnytimeProfile::Solution sol;
	sol.cost = strtod(line[7].c_str(), NULL);
	sol.time = strtod(line[8].c_str(), NULL);
	sols->push_back(sol);
	nsols++;
}<|endoftext|>


<commit_before>
#include "lest.hpp"
#include "z85.h"
#include "z85.hpp"

using namespace std;

void test_nopadding(const char* data, size_t dataSize, const char* text)
{
   const size_t bufSize = 32 * 1024;
   if (dataSize > bufSize * 0.7)
   {
      EXPECT(false);
      return;
   }

   EXPECT(dataSize % 4 == 0);
   char encodedBuf[bufSize] = {0};
   const size_t encodedBytes = Z85_encode(data, encodedBuf, dataSize);
   EXPECT(encodedBytes % 5 == 0);
   EXPECT(encodedBytes == (dataSize * 5 / 4));
   EXPECT(!strcmp(text, encodedBuf));

   char decodedBuf[bufSize] = {0};
   const size_t decodedBytes = Z85_decode(encodedBuf, decodedBuf, encodedBytes);
   EXPECT(decodedBytes % 4 == 0);
   EXPECT(decodedBytes == dataSize);
   EXPECT(!memcmp(data, decodedBuf, dataSize));

   char encodedBufWithPadding[bufSize] = {0};
   const size_t encodedBytesWithPadding = Z85_encode_with_padding(data, encodedBufWithPadding, dataSize);
   EXPECT(encodedBytes + (encodedBytes ? 1 : 0) == encodedBytesWithPadding); // +one byte for padding count
   EXPECT(encodedBytesWithPadding == 0 || encodedBufWithPadding[0] == '4');  // nothing should be padded, so 4 count
   EXPECT(!memcmp(encodedBuf, encodedBufWithPadding + 1, encodedBytes));

   char decodedBufWithPadding[bufSize] = {0};
   const size_t decodedBytesWithPadding = Z85_decode_with_padding(encodedBufWithPadding, decodedBufWithPadding, encodedBytesWithPadding);
   EXPECT(decodedBytesWithPadding % 4 == 0);
   EXPECT(decodedBytesWithPadding == dataSize);
   EXPECT(!memcmp(data, decodedBufWithPadding, dataSize));
}

const lest::test specification[] =
{
   "Hello world!", []
   {
      EXPECT(z85::encode(string("\x86\x4F\xD2\x6F\xB5\x59\xF7\x5B")) == "HelloWorld");
   },

   "Test unsafe", []
   {
      test_nopadding("", 0, "");
      test_nopadding("\x86\x4F\xD2\x6F\xB5\x59\xF7\x5B", 8, "HelloWorld");
      test_nopadding("\x8E\x0B\xDD\x69\x76\x28\xB9\x1D\x8F\x24\x55\x87\xEE\x95\xC5\xB0"
                     "\x4D\x48\x96\x3F\x79\x25\x98\x77\xB4\x9C\xD9\x06\x3A\xEA\xD3\xB7",
                     32, "JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6");
   },
};

int main()
{
   return lest::run(specification);
}

<commit_msg>build fix for gcc<commit_after>
#include <cstring>

#include "lest.hpp"
#include "z85.h"
#include "z85.hpp"

using namespace std;

void test_nopadding(const char* data, size_t dataSize, const char* text)
{
   const size_t bufSize = 32 * 1024;
   if (dataSize > bufSize * 0.7)
   {
      EXPECT(false);
      return;
   }

   EXPECT(dataSize % 4 == 0);
   char encodedBuf[bufSize] = {0};
   const size_t encodedBytes = Z85_encode(data, encodedBuf, dataSize);
   EXPECT(encodedBytes % 5 == 0);
   EXPECT(encodedBytes == (dataSize * 5 / 4));
   EXPECT(!strcmp(text, encodedBuf));

   char decodedBuf[bufSize] = {0};
   const size_t decodedBytes = Z85_decode(encodedBuf, decodedBuf, encodedBytes);
   EXPECT(decodedBytes % 4 == 0);
   EXPECT(decodedBytes == dataSize);
   EXPECT(!memcmp(data, decodedBuf, dataSize));

   char encodedBufWithPadding[bufSize] = {0};
   const size_t encodedBytesWithPadding = Z85_encode_with_padding(data, encodedBufWithPadding, dataSize);
   EXPECT(encodedBytes + (encodedBytes ? 1 : 0) == encodedBytesWithPadding); // +one byte for padding count
   EXPECT(encodedBytesWithPadding == 0 || encodedBufWithPadding[0] == '4');  // nothing should be padded, so 4 count
   EXPECT(!memcmp(encodedBuf, encodedBufWithPadding + 1, encodedBytes));

   char decodedBufWithPadding[bufSize] = {0};
   const size_t decodedBytesWithPadding = Z85_decode_with_padding(encodedBufWithPadding, decodedBufWithPadding, encodedBytesWithPadding);
   EXPECT(decodedBytesWithPadding % 4 == 0);
   EXPECT(decodedBytesWithPadding == dataSize);
   EXPECT(!memcmp(data, decodedBufWithPadding, dataSize));
}

const lest::test specification[] =
{
   "Hello world!", []
   {
      EXPECT(z85::encode(string("\x86\x4F\xD2\x6F\xB5\x59\xF7\x5B")) == "HelloWorld");
   },

   "Test unsafe", []
   {
      test_nopadding("", 0, "");
      test_nopadding("\x86\x4F\xD2\x6F\xB5\x59\xF7\x5B", 8, "HelloWorld");
      test_nopadding("\x8E\x0B\xDD\x69\x76\x28\xB9\x1D\x8F\x24\x55\x87\xEE\x95\xC5\xB0"
                     "\x4D\x48\x96\x3F\x79\x25\x98\x77\xB4\x9C\xD9\x06\x3A\xEA\xD3\xB7",
                     32, "JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6");
   },
};

int main()
{
   return lest::run(specification);
}

<|endoftext|>


<commit_before><commit_msg>added initial tests for convergence for FinalFluxOrN<commit_after><|endoftext|>


<commit_before>#include "nanovg_addon.h"
#include <stb_image.h>
#include <iostream>
#include <cstring>

NanoVGAddon::NanoVGAddon() {
	name_ = "nanovg";
	version_ = "0.0.1";
	// TODO: have bootstrap.t prepend the standard truss_message struct onto all addon headers?
	header_ = R"(
		/* NanoVG Addon Embedded Header */

		typedef struct Addon Addon;
		typedef struct {
			unsigned int message_type;
			unsigned int data_length;
			unsigned char* data;
			unsigned int refcount;
		} truss_message;

		truss_message* truss_nanovg_load_image(Addon* addon, const char* filename, int* w, int* h, int* n);
	)";
}

const std::string& NanoVGAddon::getName() {
	return name_;
}

const std::string& NanoVGAddon::getHeader() {
	return header_;
}

const std::string& NanoVGAddon::getVersion() {
	return version_;
}

void NanoVGAddon::init(truss::Interpreter* owner) {
	// nothing special to do
}

void NanoVGAddon::shutdown() {
	// nothing to do here either
}

void NanoVGAddon::update(double dt) {
	// no updates
}

// loads an image
truss_message* NanoVGAddon::loadImage(const char* filename, int& width, int& height, int& numChannels) {
	std::cout << "Loading " << filename << std::endl;
	unsigned char* img;
	stbi_set_unpremultiply_on_load(1);
	stbi_convert_iphone_png_to_rgb(1);
	// always request 4 channels (rgba) from stbi
	// stbi will return 4 channels, but the number reported will be
	// the actual number of channels in the source image. Since we
	// don't care about that, load that into a dummy variable and
	// return 4 channels always.
	int dummy;
	numChannels = 4;
	img = stbi_load(filename, &width, &height, &dummy, 4);
	if (img == NULL) {
		std::cout << "Failed to load " << filename
				  << ": " << stbi_failure_reason() << std::endl;
		return NULL;
	}
	std::cout << "w: " << width << ", h: " << height << ", n: " << numChannels << std::endl;
	unsigned int datalength = width * height * numChannels;
	truss_message* ret = truss_create_message(datalength);
	std::memcpy(ret->data, img, datalength);
	stbi_image_free(img);

	return ret;
}

NanoVGAddon::~NanoVGAddon() {
	// nothing to do here either really
}

TRUSS_C_API truss_message* truss_nanovg_load_image(NanoVGAddon* addon, const char* filename, int* w, int* h, int* n) {
	return addon->loadImage(filename, *w, *h, *n);
}<commit_msg>have loadimage go through physfs<commit_after>#include "nanovg_addon.h"
#include <stb_image.h>
#include <iostream>
#include <cstring>

NanoVGAddon::NanoVGAddon() {
	name_ = "nanovg";
	version_ = "0.0.1";
	// TODO: have bootstrap.t prepend the standard truss_message struct onto all addon headers?
	header_ = R"(
		/* NanoVG Addon Embedded Header */

		typedef struct Addon Addon;
		typedef struct {
			unsigned int message_type;
			unsigned int data_length;
			unsigned char* data;
			unsigned int refcount;
		} truss_message;

		truss_message* truss_nanovg_load_image(Addon* addon, const char* filename, int* w, int* h, int* n);
	)";
}

const std::string& NanoVGAddon::getName() {
	return name_;
}

const std::string& NanoVGAddon::getHeader() {
	return header_;
}

const std::string& NanoVGAddon::getVersion() {
	return version_;
}

void NanoVGAddon::init(truss::Interpreter* owner) {
	// nothing special to do
}

void NanoVGAddon::shutdown() {
	// nothing to do here either
}

void NanoVGAddon::update(double dt) {
	// no updates
}

// loads an image
truss_message* NanoVGAddon::loadImage(const char* filename, int& width, int& height, int& numChannels) {
	unsigned char* img;
	stbi_set_unpremultiply_on_load(1);
	stbi_convert_iphone_png_to_rgb(1);
	// always request 4 channels (rgba) from stbi
	// stbi will return 4 channels, but the number reported will be
	// the actual number of channels in the source image. Since we
	// don't care about that, load that into a dummy variable and
	// return 4 channels always.
	int dummy;
	truss_message* rawfile = truss_load_file(filename);
	if (rawfile == NULL) {
		return NULL;
	}
	numChannels = 4;
	img = stbi_load_from_memory(rawfile->data, rawfile->data_length, &width, &height, &dummy, 4);
	if (img == NULL) {
		truss_log(TRUSS_LOG_ERROR, "Image loading error.");
		truss_log(TRUSS_LOG_ERROR, stbi_failure_reason());
		truss_release_message(rawfile);
		return NULL;
	}
	unsigned int datalength = width * height * numChannels;
	truss_message* ret = truss_create_message(datalength);
	std::memcpy(ret->data, img, datalength);
	stbi_image_free(img);
	truss_release_message(rawfile);

	return ret;
}

NanoVGAddon::~NanoVGAddon() {
	// nothing to do here either really
}

TRUSS_C_API truss_message* truss_nanovg_load_image(NanoVGAddon* addon, const char* filename, int* w, int* h, int* n) {
	return addon->loadImage(filename, *w, *h, *n);
}<|endoftext|>


<commit_before><commit_msg>fix build on older compilers<commit_after><|endoftext|>


<commit_before>#include <gtest/gtest.h>

#include "gtplib/gtpfrontend.hpp"
#include "dummyengine.hpp"

#include <iostream>
#include <sstream>
#include <tuple>

using namespace std;
using namespace gtp;

template<typename Command, typename ...Params>
WhateverCommand Cmd(Params... params)
{
  Command c;
  typedef decltype(c.params) Tuple;
  return WhateverCommand(Command{Tuple(params...)});
}

std::map<string, WhateverCommand> buildPairs()
{
  std::map<string, WhateverCommand> result;
  result["protocol_version"] = Cmd<CmdProtocolVersion>();
  result["name"] = Cmd<CmdName>();
  result["known_command"] = Cmd<CmdKnownCommand>();
  result["list_commands"] = Cmd<CmdListCommands>();
  result["boardsize 19"] = Cmd<CmdBoardSize>(19);
  result["clear_board"] = Cmd<CmdClearBoard>();
  result["komi 0.5"] = Cmd<CmdKomi>(0.5);
  result["play b a12"] = Cmd<CmdPlay>(Move{Color::black, Vertex{0, 12}});
  result["genmove w"] = Cmd<CmdGenmove>(Color::white);
  result["fixed_handicap 4"] = Cmd<CmdFixedHandicap>(4);
  result["version"] = Cmd<CmdVersion>();
  return result;
}

TEST(DirectConversion, OneAfterAnother)
{
  std::map<string, WhateverCommand> pairs = buildPairs();

  std::vector<WhateverCommand> expected;
  std::stringstream inputBuffer;

  for (auto pair : pairs)
  {
    inputBuffer << pair.first << "\n";
    expected.push_back (pair.second);
  }

  inputBuffer << "quit\n";
  expected.push_back(CmdQuit{});

  inputBuffer.flush();

  std::stringstream outputDummyBuffer;

  DummyEngine engine;
  gtp::EngineFrontend<DummyEngine> frontend (inputBuffer, outputDummyBuffer, engine);
  frontend.start();

  size_t expectedCommandCount = expected.size();
  size_t parsedCommandCount = engine.commands_.size();
  size_t min = std::min(expectedCommandCount, parsedCommandCount);

  for (size_t k = 0; k < min; ++k)
  {
    EXPECT_EQ(engine.commands_[k], expected[k]);
  }

  EXPECT_EQ(expectedCommandCount, parsedCommandCount);
}

TEST(ReverseConversion, OneAfterAnother)
{
  std::map<string, WhateverCommand> pairs = buildPairs();

  std::vector<WhateverCommand> expected;
  std::stringstream inputBuffer;

  for (auto pair : pairs)
  {
    inputBuffer << pair.first << "\n";
    expected.push_back (pair.second);
  }

  inputBuffer << "quit\n";
  expected.push_back(CmdQuit{});

  inputBuffer.flush();

  std::stringstream outputDummyBuffer;

  DummyEngine engine;
  gtp::EngineFrontend<DummyEngine> frontend (inputBuffer, outputDummyBuffer, engine);
  frontend.start();

  size_t expectedCommandCount = expected.size();
  size_t parsedCommandCount = engine.commands_.size();
  size_t min = std::min(expectedCommandCount, parsedCommandCount);

  for (auto  c : engine.commands_)
  {
    cout << "AGGG: " << c << endl;
  }

  for (size_t k = 0; k < min; ++k)
  {
    cout << "Testing " << expected[k] << "..." << endl;
    EXPECT_EQ(engine.commands_[k], expected[k]);
  }

  EXPECT_EQ(expectedCommandCount, parsedCommandCount);
}
<commit_msg>Remove dummy test<commit_after>#include <gtest/gtest.h>

#include "gtplib/gtpfrontend.hpp"
#include "dummyengine.hpp"

#include <iostream>
#include <sstream>
#include <tuple>

using namespace std;
using namespace gtp;

template<typename Command, typename ...Params>
WhateverCommand Cmd(Params... params)
{
  Command c;
  typedef decltype(c.params) Tuple;
  return WhateverCommand(Command{Tuple(params...)});
}

std::map<string, WhateverCommand> buildPairs()
{
  std::map<string, WhateverCommand> result;
  result["protocol_version"] = Cmd<CmdProtocolVersion>();
  result["name"] = Cmd<CmdName>();
  result["known_command"] = Cmd<CmdKnownCommand>();
  result["list_commands"] = Cmd<CmdListCommands>();
  result["boardsize 19"] = Cmd<CmdBoardSize>(19);
  result["clear_board"] = Cmd<CmdClearBoard>();
  result["komi 0.5"] = Cmd<CmdKomi>(0.5);
  result["play b a12"] = Cmd<CmdPlay>(Move{Color::black, Vertex{0, 12}});
  result["genmove w"] = Cmd<CmdGenmove>(Color::white);
  result["fixed_handicap 4"] = Cmd<CmdFixedHandicap>(4);
  result["version"] = Cmd<CmdVersion>();
  return result;
}

TEST(DirectConversion, OneAfterAnother)
{
  std::map<string, WhateverCommand> pairs = buildPairs();

  std::vector<WhateverCommand> expected;
  std::stringstream inputBuffer;

  for (auto pair : pairs)
  {
    inputBuffer << pair.first << "\n";
    expected.push_back (pair.second);
  }

  inputBuffer << "quit\n";
  expected.push_back(CmdQuit{});

  inputBuffer.flush();

  std::stringstream outputDummyBuffer;

  DummyEngine engine;
  gtp::EngineFrontend<DummyEngine> frontend (inputBuffer, outputDummyBuffer, engine);
  frontend.start();

  size_t expectedCommandCount = expected.size();
  size_t parsedCommandCount = engine.commands_.size();
  size_t min = std::min(expectedCommandCount, parsedCommandCount);

  for (size_t k = 0; k < min; ++k)
  {
    EXPECT_EQ(engine.commands_[k], expected[k]);
  }

  EXPECT_EQ(expectedCommandCount, parsedCommandCount);
}

<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchange_OptionsFile_inl_
#define _Stroika_Foundation_DataExchange_OptionsFile_inl_  1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Characters/Format.h"
#include    "../Streams/BasicBinaryInputOutputStream.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchange {

            /*
             ********************************************************************************
             ************************** DataExchange::OptionsFile ***************************
             ********************************************************************************
             */
            template    <typename T>
            Optional<T>   OptionsFile::Read ()
            {
                Optional<VariantValue>  tmp = Read<VariantValue> ();
                if (tmp.IsMissing ()) {
                    return Optional<T> ();
                }
                try {
                    return fMapper_.ToObject<T> (*tmp);
                }
                catch (const BadFormatException& bf) {
                    fLogger_ (Execution::Logger::Priority::eCriticalError, Characters::Format (L"Error analyzing configuration file (bad format) '%s' - using defaults.", GetFilePath_ ().c_str ()));
                    return Optional<T> ();
                }
                catch (...) {
                    // if this fails, its probably because somehow the data in the config file was bad.
                    // So at least log that, and continue without reading anything (as if empty file)
                    fLogger_ (Execution::Logger::Priority::eCriticalError, Characters::Format (L"Error analyzing configuration file '%s' - using defaults.", GetFilePath_ ().c_str ()));
                    return Optional<T> ();
                }
            }
            template    <typename T>
            T   OptionsFile::Read (const T& defaultObj, ReadFlags readFlags)
            {
                Optional<T> eltRead = Read<T> ();
                Optional<T> elt2Write;              // only if needed
                String      msgAugment;
                if (eltRead.IsMissing ()) {
                    if (readFlags == ReadFlags::eWriteIfChanged) {
                        elt2Write = defaultObj;
                        msgAugment = L"default";
                    }
                }
                else {
                    if (readFlags == ReadFlags::eWriteIfChanged) {
                        try {
                            // See if re-persisting the item would change it.
                            // This is useful if your data model adds or removes fields. It updates the file contents written to the
                            // upgraded/latest form
                            Memory::BLOB    oldData =   ReadRaw (); // @todo could have saved from previous Read<T>
                            Memory::BLOB    newData;
                            {
                                Streams::BasicBinaryOutputStream outStream;
                                WriteRaw (outStream, fMapper_.FromObject (*eltRead));
                                // not sure needed? outStream.Flush();
                                newData = outStream.As<Memory::BLOB> ();
                            }
                            if (oldData != newData) {
                                elt2Write = eltRead;
                                msgAugment = L"(because something changed)";
                            }
                        }
                        catch (...) {
                            fLogger_ (Execution::Logger::Priority::eError, Characters::Format (L"Failed to compare configuration file: %s", GetFilePath_ ().c_str ()));
                        }
                    }
                }
                if (elt2Write.IsPresent ()) {
                    fLogger_ (Execution::Logger::Priority::eInfo, Characters::Format (L"Writing %s '%s' configuration file.", msgAugment.c_str (), GetFilePath_ ().c_str ()));
                    try {
                        Write (*elt2Write);
                    }
                    catch (...) {
                        fLogger_ (Execution::Logger::Priority::eError, Characters::Format (L"Failed to write default values to file: %s", GetFilePath_ ().c_str ()));
                    }
                    return *elt2Write;
                }
                else if (eltRead.IsPresent ()) {
                    return *eltRead;
                }
                else {
                    return defaultObj;
                }
            }
            template    <typename T>
            void    OptionsFile::Write (const T& optionsObject)
            {
                Write<VariantValue> (fMapper_.FromObject<T> (optionsObject));
            }

        }

    }
}
#endif  /*_Stroika_Foundation_DataExchange_OptionsFile_inl_*/
<commit_msg>minor fix to OptionsFile<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2014.  All rights reserved
 */
#ifndef _Stroika_Foundation_DataExchange_OptionsFile_inl_
#define _Stroika_Foundation_DataExchange_OptionsFile_inl_  1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Characters/Format.h"
#include    "../Streams/BasicBinaryOutputStream.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   DataExchange {

            /*
             ********************************************************************************
             ************************** DataExchange::OptionsFile ***************************
             ********************************************************************************
             */
            template    <typename T>
            Optional<T>   OptionsFile::Read ()
            {
                Optional<VariantValue>  tmp = Read<VariantValue> ();
                if (tmp.IsMissing ()) {
                    return Optional<T> ();
                }
                try {
                    return fMapper_.ToObject<T> (*tmp);
                }
                catch (const BadFormatException& bf) {
                    fLogger_ (Execution::Logger::Priority::eCriticalError, Characters::Format (L"Error analyzing configuration file (bad format) '%s' - using defaults.", GetFilePath_ ().c_str ()));
                    return Optional<T> ();
                }
                catch (...) {
                    // if this fails, its probably because somehow the data in the config file was bad.
                    // So at least log that, and continue without reading anything (as if empty file)
                    fLogger_ (Execution::Logger::Priority::eCriticalError, Characters::Format (L"Error analyzing configuration file '%s' - using defaults.", GetFilePath_ ().c_str ()));
                    return Optional<T> ();
                }
            }
            template    <typename T>
            T   OptionsFile::Read (const T& defaultObj, ReadFlags readFlags)
            {
                Optional<T> eltRead = Read<T> ();
                Optional<T> elt2Write;              // only if needed
                String      msgAugment;
                if (eltRead.IsMissing ()) {
                    if (readFlags == ReadFlags::eWriteIfChanged) {
                        elt2Write = defaultObj;
                        msgAugment = L"default";
                    }
                }
                else {
                    if (readFlags == ReadFlags::eWriteIfChanged) {
                        try {
                            // See if re-persisting the item would change it.
                            // This is useful if your data model adds or removes fields. It updates the file contents written to the
                            // upgraded/latest form
                            Memory::BLOB    oldData =   ReadRaw (); // @todo could have saved from previous Read<T>
                            Memory::BLOB    newData;
                            {
                                Streams::BasicBinaryOutputStream outStream;
                                WriteRaw (outStream, fMapper_.FromObject (*eltRead));
                                // not sure needed? outStream.Flush();
                                newData = outStream.As<Memory::BLOB> ();
                            }
                            if (oldData != newData) {
                                elt2Write = eltRead;
                                msgAugment = L"(because something changed)";
                            }
                        }
                        catch (...) {
                            fLogger_ (Execution::Logger::Priority::eError, Characters::Format (L"Failed to compare configuration file: %s", GetFilePath_ ().c_str ()));
                        }
                    }
                }
                if (elt2Write.IsPresent ()) {
                    fLogger_ (Execution::Logger::Priority::eInfo, Characters::Format (L"Writing %s '%s' configuration file.", msgAugment.c_str (), GetFilePath_ ().c_str ()));
                    try {
                        Write (*elt2Write);
                    }
                    catch (...) {
                        fLogger_ (Execution::Logger::Priority::eError, Characters::Format (L"Failed to write default values to file: %s", GetFilePath_ ().c_str ()));
                    }
                    return *elt2Write;
                }
                else if (eltRead.IsPresent ()) {
                    return *eltRead;
                }
                else {
                    return defaultObj;
                }
            }
            template    <typename T>
            void    OptionsFile::Write (const T& optionsObject)
            {
                Write<VariantValue> (fMapper_.FromObject<T> (optionsObject));
            }

        }

    }
}
#endif  /*_Stroika_Foundation_DataExchange_OptionsFile_inl_*/
<|endoftext|>