<commit_before>

/******
 This example is not about CRUD. This is an implementation of key-value storage just like
 NSUserDefaults on iOS or SharedPreferences on Android.
 Here is the deal: we need to have `setValueForKey` and `getValueByKey` interface. All data must ba saved in sqlite
 database.
 To perform this we create schema with table `key_value` and two columns: key:string and value:string. There is no
 primary key so we are unable to use CRUD functions like `get`, `get_no_throw`, `remove`, `update`. And there is no need to use
 these functions actually. We use non-CRUD functions `remove_all`, `insert` (it is non-CRUSH cause it doesn't require a table to have a
 primary key column) and `get_all`. `setValue` function takes two string arguments: key and value. It creates a KeyValue
 object (KeyValue is a class mapped to storage) with arguments and performs a transaction. Within this transaction
 first we call `REMOVE FROM key_value WHERE key = '%key%'` and next `INSERT INTO key_value values (%key%, %value%)`.
 After this there is a row in the `key_value` table with key and value passed into `setValue` function.
 `getValue` performs `get_all` with specific condition: `SELECT * FROM key_value WHERE key = '%key%'` and returns a front value if result
 (std::vector<KeyValue>) is not empty or empty string if there is no row with specified key.
 ******/

#include "sqlite_orm.h"

#include <iostream>

using std::cout;
using std::cerr;
using std::endl;

/**
 *  This is just a mapped type. User doesn't have to interact with it directly.
 */
struct KeyValue {
    std::string key;
    std::string value;
};

auto& getStorage() {
    using namespace sqlite_orm;
    static auto storage = make_storage("key_value_example.sqlite",
                                       make_table("key_value",
                                                  make_column("key",
                                                              &KeyValue::key),
                                                  make_column("value",
                                                              &KeyValue::value)));;
    return storage;
}

void setValue(const std::string &key, const std::string &value) {
    using namespace sqlite_orm;
    KeyValue kv{key, value};
    getStorage().transaction([&] {
        getStorage().remove_all<KeyValue>(where(is_equal(&KeyValue::key, key)));
        getStorage().insert(kv);
        return true;
    });
}

std::string getValue(const std::string &key) {
    using namespace sqlite_orm;
    auto kvs = getStorage().get_all<KeyValue>(where(is_equal(&KeyValue::key, key)));
    if(kvs.size()){
        if(kvs.size() == 1){
            return kvs.front().value;
        }else{
            cerr << "kvs for key *" << key << "* is more that 1 (" << kvs.size() << ")" << endl;
            return kvs.front().value;
        }
    }else{
        return {};
    }
}

int storedKeysCount() {
    return getStorage().count<KeyValue>();
}

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

    cout << argv[0] << endl;    //  to know executable path in case if you need to access sqlite directly from sqlite client

    getStorage().sync_schema(); //  to create table if it doesn't exist

    struct {
        std::string userId = "userId";
        std::string userName = "userName";
        std::string userGender = "userGender";  //  this key will be missing
    } keys; //  to keep keys in one place

    setValue(keys.userId, "6");
    setValue(keys.userName, "Peter");

    auto userId = getValue(keys.userId);
    cout << "userId = " << userId << endl;  //  userId = 6

    auto userName = getValue(keys.userName);
    cout << "userName = " << userName << endl;  //  userName = Peter

    auto userGender = getValue(keys.userGender);
    cout << "userGender = " << userGender << endl;  //  userGender =

    auto kvsCount = storedKeysCount();
    cout << "kvsCount = " << kvsCount << endl;  //  kvsCount = 2

}
<commit_msg>Update key_value.cpp<commit_after>

/******
 This example is not about CRUD. This is an implementation of key-value storage just like
 NSUserDefaults on iOS or SharedPreferences on Android.
 Here is the deal: we need to have `setValueForKey` and `getValueByKey` interface. All data must ba saved in sqlite
 database.
 To perform this we create schema with table `key_value` and two columns: key:string and value:string. There is no
 primary key so we are unable to use CRUD functions like `get`, `get_no_throw`, `remove`, `update`. And there is no need to use
 these functions actually. We use non-CRUD functions `remove_all`, `insert` (it is non-CRUD cause it doesn't require a table to have a
 primary key column) and `get_all`. `setValue` function takes two string arguments: key and value. It creates a KeyValue
 object (KeyValue is a class mapped to the storage) with arguments and performs a transaction. Within this transaction
 first we call `REMOVE FROM key_value WHERE key = '%key%'` and next `INSERT INTO key_value values (%key%, %value%)`.
 After this there is a row in the `key_value` table with key and value passed into `setValue` function.
 `getValue` performs `get_all` with specific condition: `SELECT * FROM key_value WHERE key = '%key%'` and returns a front value if result
 (std::vector<KeyValue>) is not empty or empty string if there is no row with specified key.
 ******/

#include "sqlite_orm.h"

#include <iostream>

using std::cout;
using std::cerr;
using std::endl;

/**
 *  This is just a mapped type. User doesn't have to interact with it directly.
 */
struct KeyValue {
    std::string key;
    std::string value;
};

auto& getStorage() {
    using namespace sqlite_orm;
    static auto storage = make_storage("key_value_example.sqlite",
                                       make_table("key_value",
                                                  make_column("key",
                                                              &KeyValue::key),
                                                  make_column("value",
                                                              &KeyValue::value)));;
    return storage;
}

void setValue(const std::string &key, const std::string &value) {
    using namespace sqlite_orm;
    KeyValue kv{key, value};
    getStorage().transaction([&] {
        getStorage().remove_all<KeyValue>(where(is_equal(&KeyValue::key, key)));
        getStorage().insert(kv);
        return true;
    });
}

std::string getValue(const std::string &key) {
    using namespace sqlite_orm;
    auto kvs = getStorage().get_all<KeyValue>(where(is_equal(&KeyValue::key, key)));
    if(kvs.size()){
        if(kvs.size() == 1){
            return kvs.front().value;
        }else{
            cerr << "kvs for key *" << key << "* is more that 1 (" << kvs.size() << ")" << endl;
            return kvs.front().value;
        }
    }else{
        return {};
    }
}

int storedKeysCount() {
    return getStorage().count<KeyValue>();
}

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

    cout << argv[0] << endl;    //  to know executable path in case if you need to access sqlite directly from sqlite client

    getStorage().sync_schema(); //  to create table if it doesn't exist

    struct {
        std::string userId = "userId";
        std::string userName = "userName";
        std::string userGender = "userGender";  //  this key will be missing
    } keys; //  to keep keys in one place

    setValue(keys.userId, "6");
    setValue(keys.userName, "Peter");

    auto userId = getValue(keys.userId);
    cout << "userId = " << userId << endl;  //  userId = 6

    auto userName = getValue(keys.userName);
    cout << "userName = " << userName << endl;  //  userName = Peter

    auto userGender = getValue(keys.userGender);
    cout << "userGender = " << userGender << endl;  //  userGender =

    auto kvsCount = storedKeysCount();
    cout << "kvsCount = " << kvsCount << endl;  //  kvsCount = 2

}
<|endoftext|>


<commit_before>#pragma once

#include <sdbusplus/bus.hpp>
#include <sdbusplus/server/object.hpp>
#include <string>
#include <phosphor-logging/log.hpp>
#include "xyz/openbmc_project/Network/Client/server.hpp"

namespace phosphor
{
namespace rsyslog_config
{

using namespace phosphor::logging;
using NetworkClient = sdbusplus::xyz::openbmc_project::Network::server::Client;
using Iface = sdbusplus::server::object::object<NetworkClient>;

/** @class Server
 *  @brief Configuration for rsyslog server
 *  @details A concrete implementation of the
 *  xyz.openbmc_project.Network.Client API, in order to
 *  provide remote rsyslog server's address and port.
 */
class Server : public Iface
{
    public:
        Server() = delete;
        Server(const Server&) = delete;
        Server& operator=(const Server&) = delete;
        Server(Server&&) = delete;
        Server& operator=(Server&&) = delete;
        virtual ~Server() = default;

        /** @brief Constructor to put object onto bus at a dbus path.
         *  @param[in] bus - Bus to attach to.
         *  @param[in] path - Path to attach at.
         *  @param[in] filePath - rsyslog remote logging config file
         */
        Server(sdbusplus::bus::bus& bus,
               const std::string& path,
               const char* filePath) :
            Iface(bus, path.c_str(), true),
            configFilePath(filePath)
        {
            try
            {
                restore(configFilePath.c_str());
            }
            catch(const std::exception& e)
            {
                log<level::ERR>(e.what());
            }

            emit_object_added();
        }

        using NetworkClient::address;
        using NetworkClient::port;

        /** @brief Override that updates rsyslog config file as well
         *  @param[in] value - remote server address
         *  @returns value of changed address
         */
        virtual std::string address(std::string value) override;

        /** @brief Override that updates rsyslog config file as well
         *  @param[in] value - remote server port
         *  @returns value of changed port
         */
        virtual uint16_t port(uint16_t value) override;

        /** @brief Restart rsyslog's systemd unit
         */
        virtual void restart();

    private:
        /** @brief Update remote server address and port in
         *         rsyslog config file.
         *  @param[in] serverAddress - remote server address
         *  @param[in] serverPort - remote server port
         *  @param[in] filePath - rsyslog config file path
         */
        void writeConfig(
                 const std::string& serverAddress,
                 uint16_t serverPort,
                 const char* filePath);

        /** @brief Checks if input IP address is valid (uses getaddrinfo)
         *  @param[in] address - server address
         *  @returns true if valid, false otherwise
         */
        bool addressValid(const std::string& address);

        /** @brief Populate existing config into D-Bus properties
         *  @param[in] filePath - rsyslog config file path
         */
        void restore(const char* filePath);

        std::string configFilePath{};
};

} // namespace rsyslog_config
} // namespace phosphor
<commit_msg>phosphor-rsyslog-conf: react to hostname change<commit_after>#pragma once

#include <sdbusplus/bus.hpp>
#include <sdbusplus/server/object.hpp>
#include <string>
#include <phosphor-logging/log.hpp>
#include "xyz/openbmc_project/Network/Client/server.hpp"

namespace phosphor
{
namespace rsyslog_config
{

using namespace phosphor::logging;
using NetworkClient = sdbusplus::xyz::openbmc_project::Network::server::Client;
using Iface = sdbusplus::server::object::object<NetworkClient>;
namespace sdbusRule = sdbusplus::bus::match::rules;

/** @class Server
 *  @brief Configuration for rsyslog server
 *  @details A concrete implementation of the
 *  xyz.openbmc_project.Network.Client API, in order to
 *  provide remote rsyslog server's address and port.
 */
class Server : public Iface
{
    public:
        Server() = delete;
        Server(const Server&) = delete;
        Server& operator=(const Server&) = delete;
        Server(Server&&) = delete;
        Server& operator=(Server&&) = delete;
        virtual ~Server() = default;

        /** @brief Constructor to put object onto bus at a dbus path.
         *  @param[in] bus - Bus to attach to.
         *  @param[in] path - Path to attach at.
         *  @param[in] filePath - rsyslog remote logging config file
         */
        Server(sdbusplus::bus::bus& bus,
               const std::string& path,
               const char* filePath) :
            Iface(bus, path.c_str(), true),
            configFilePath(filePath),
            hostnameChange(
                bus,
                sdbusRule::propertiesChanged(
                    "/org/freedesktop/hostname1", "org.freedesktop.hostname1"),
                std::bind(std::mem_fn(&Server::hostnameChanged),
                    this, std::placeholders::_1))
        {
            try
            {
                restore(configFilePath.c_str());
            }
            catch(const std::exception& e)
            {
                log<level::ERR>(e.what());
            }

            emit_object_added();
        }

        using NetworkClient::address;
        using NetworkClient::port;

        /** @brief Override that updates rsyslog config file as well
         *  @param[in] value - remote server address
         *  @returns value of changed address
         */
        virtual std::string address(std::string value) override;

        /** @brief Override that updates rsyslog config file as well
         *  @param[in] value - remote server port
         *  @returns value of changed port
         */
        virtual uint16_t port(uint16_t value) override;

        /** @brief Restart rsyslog's systemd unit
         */
        virtual void restart();

    private:
        /** @brief Update remote server address and port in
         *         rsyslog config file.
         *  @param[in] serverAddress - remote server address
         *  @param[in] serverPort - remote server port
         *  @param[in] filePath - rsyslog config file path
         */
        void writeConfig(
                 const std::string& serverAddress,
                 uint16_t serverPort,
                 const char* filePath);

        /** @brief Checks if input IP address is valid (uses getaddrinfo)
         *  @param[in] address - server address
         *  @returns true if valid, false otherwise
         */
        bool addressValid(const std::string& address);

        /** @brief Populate existing config into D-Bus properties
         *  @param[in] filePath - rsyslog config file path
         */
        void restore(const char* filePath);

        std::string configFilePath{};

        /** @brief React to hostname change
         *  @param[in] msg - sdbusplus message
         */
        void hostnameChanged(sdbusplus::message::message& msg)
        {
            restart();
        }

        sdbusplus::bus::match_t hostnameChange;
};

} // namespace rsyslog_config
} // namespace phosphor
<|endoftext|>


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

#include <QObject>
#include <QSignalSpy>
#include <QTest>

#include <qmdnsengine/dns.h>
#include <qmdnsengine/cache.h>
#include <qmdnsengine/record.h>

Q_DECLARE_METATYPE(QMdnsEngine::Record)

class TestCache : public QObject
{
    Q_OBJECT

private Q_SLOTS:

    void initTestCase();
    void testExpiry();
    void testRemoval();
};

void TestCache::initTestCase()
{
    qRegisterMetaType<QMdnsEngine::Record>("Record");
}

void TestCache::testExpiry()
{
    QMdnsEngine::Record record;
    record.setName("Test");
    record.setType(QMdnsEngine::A);
    record.setTtl(1);

    QMdnsEngine::Cache cache;
    cache.addRecord(record);

    QSignalSpy recordExpiredSpy(&cache, SIGNAL(recordExpired(Record)));

    // The record should be in the cache
    QVERIFY(cache.lookupRecord(record.name(), record.type(), record));

    // This unfortunately delays the test but 1s is the smallest TTL
    QTest::qWait(1100);

    // After entering the event loop, the record should have been purged and
    // the recordExpired() signal emitted
    QVERIFY(!cache.lookupRecord(record.name(), record.type(), record));
    QCOMPARE(recordExpiredSpy.count(), 1);
}

void TestCache::testRemoval()
{
    QMdnsEngine::Record record;
    record.setName("Test");
    record.setType(QMdnsEngine::A);
    record.setTtl(10);

    QMdnsEngine::Cache cache;
    cache.addRecord(record);

    QSignalSpy recordExpiredSpy(&cache, SIGNAL(recordExpired(Record)));

    // Purge the record from the cache by setting its TTL to 0
    record.setTtl(0);
    cache.addRecord(record);

    // Verify that the record is gone
    QVERIFY(!cache.lookupRecord(record.name(), record.type(), record));
    QCOMPARE(recordExpiredSpy.count(), 1);
}

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

#include <QObject>
#include <QSignalSpy>
#include <QTest>

#include <qmdnsengine/dns.h>
#include <qmdnsengine/cache.h>
#include <qmdnsengine/record.h>

Q_DECLARE_METATYPE(QMdnsEngine::Record)

class TestCache : public QObject
{
    Q_OBJECT

private Q_SLOTS:

    void initTestCase();
    void testExpiry();
    void testRemoval();
};

void TestCache::initTestCase()
{
    qRegisterMetaType<QMdnsEngine::Record>("Record");
}

void TestCache::testExpiry()
{
    QMdnsEngine::Record record;
    record.setName("Test");
    record.setType(QMdnsEngine::A);
    record.setTtl(1);

    QMdnsEngine::Cache cache;
    cache.addRecord(record);

    QSignalSpy shouldQuerySpy(&cache, SIGNAL(shouldQuery(Record)));
    QSignalSpy recordExpiredSpy(&cache, SIGNAL(recordExpired(Record)));

    // The record should be in the cache
    QVERIFY(cache.lookupRecord(record.name(), record.type(), record));

    // This unfortunately delays the test but 1s is the smallest TTL
    QTest::qWait(1100);

    // After entering the event loop, the record should have been purged and
    // the recordExpired() signal emitted
    QVERIFY(!cache.lookupRecord(record.name(), record.type(), record));
    QVERIFY(shouldQuerySpy.count() > 0);
    QCOMPARE(recordExpiredSpy.count(), 1);
}

void TestCache::testRemoval()
{
    QMdnsEngine::Record record;
    record.setName("Test");
    record.setType(QMdnsEngine::A);
    record.setTtl(10);

    QMdnsEngine::Cache cache;
    cache.addRecord(record);

    QSignalSpy recordExpiredSpy(&cache, SIGNAL(recordExpired(Record)));

    // Purge the record from the cache by setting its TTL to 0
    record.setTtl(0);
    cache.addRecord(record);

    // Verify that the record is gone
    QVERIFY(!cache.lookupRecord(record.name(), record.type(), record));
    QCOMPARE(recordExpiredSpy.count(), 1);
}

QTEST_MAIN(TestCache)
#include "TestCache.moc"
<|endoftext|>


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

#include <vector>
#include <list>
#include <map>

#include <cstdlib>
#include <ctime>
#include <numeric>

#include "any_iterator.hpp"
#include "any_iterator_virtual.hpp"

template< class IterT, class ContainerT >
void benchmark_iteration(benchmark::State &state)
{
    using Iter = IterT;

    for (auto _ : state)
    {
        state.PauseTiming();
        ContainerT container(state.range(0));
        srand(static_cast<unsigned>(time(NULL)));
        for (auto& v : container)
            v = rand();
        volatile int result = 0;

        Iter it{ container.begin() };
        const Iter it_end{ container.end() };

        state.ResumeTiming();
        int intm = 0;
        for (; it != it_end; ++it)
            intm += *it;
        result = intm;
    }

    state.SetBytesProcessed(int64_t(state.iterations()) *
        int64_t(state.range(0))*sizeof(int));
}

template< class IterT, class ContainerT >
void benchmark_iteration_accumulate(benchmark::State &state)
{
    using Iter = IterT;

    for (auto _ : state)
    {
        state.PauseTiming();
        ContainerT container(state.range(0));
        srand(static_cast<unsigned>(time(NULL)));
        for (auto& v : container)
            v = rand();
        volatile int result = 0;

        Iter it{ container.begin() };
        const Iter it_end{ container.end() };

        state.ResumeTiming();
        result = std::accumulate(it, it_end, 0);
    }

    state.SetItemsProcessed(state.iterations() * int64_t(state.range(0)));
}

template< class IterT >
void benchmark_iteration_map(benchmark::State &state)
{
    using Iter = IterT;

    for (auto _ : state)
    {
        state.PauseTiming();
        std::map<int,int> container;
        srand(static_cast<unsigned>(time(NULL)));
        for (size_t i = 0; i < state.range(0); ++i)
            container.emplace(static_cast<int>(i), rand());
        volatile int result = 0;

        Iter it{ container.begin() };
        const Iter it_end{ container.end() };

        state.ResumeTiming();
        int intm = 0;
        for (; it != it_end; ++it)
            intm += it->second;
        result = intm;
    }

    state.SetItemsProcessed(state.iterations() *  int64_t(state.range(0)));
}

constexpr size_t MY_RANGE_START = 8 << 0;
constexpr size_t MY_RANGE_END = 8 << 20;
constexpr benchmark::TimeUnit tu = benchmark::kMicrosecond;
constexpr size_t range_multi = 2;

//BENCHMARK_TEMPLATE(benchmark_iteration, std::vector<int>::iterator, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
//BENCHMARK_TEMPLATE(benchmark_iteration, tyti::any_iterator<int>, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
//BENCHMARK_TEMPLATE(benchmark_iteration, tyti::any_iterator_virtual<int>, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);

BENCHMARK_TEMPLATE(benchmark_iteration, std::list<int>::iterator, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
BENCHMARK_TEMPLATE(benchmark_iteration, tyti::any_iterator<int>, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
BENCHMARK_TEMPLATE(benchmark_iteration, tyti::any_iterator_virtual<int>, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);

//BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, std::vector<int>::iterator, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END);
////BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, tyti::any_iterator<int>, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END);
//BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, std::list<int>::iterator, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu);
//BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, tyti::any_iterator<int>, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu);
//BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, tyti2::any_iterator<int>, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu);

BENCHMARK_TEMPLATE(benchmark_iteration_map, std::map<int, int>::iterator)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
BENCHMARK_TEMPLATE(benchmark_iteration_map, tyti::any_iterator<std::pair<const int, int>>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
BENCHMARK_TEMPLATE(benchmark_iteration_map, tyti::any_iterator_virtual<std::pair<const int,int>>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);

BENCHMARK_MAIN();<commit_msg>unified entities per second mesaurement<commit_after>#include <benchmark/benchmark.h>

#include <vector>
#include <list>
#include <map>

#include <cstdlib>
#include <ctime>
#include <numeric>

#include "any_iterator.hpp"
#include "any_iterator_virtual.hpp"

template< class IterT, class ContainerT >
void benchmark_iteration(benchmark::State &state)
{
    using Iter = IterT;

    for (auto _ : state)
    {
        state.PauseTiming();
        ContainerT container(state.range(0));
        srand(static_cast<unsigned>(time(NULL)));
        for (auto& v : container)
            v = rand();
        volatile int result = 0;

        Iter it{ container.begin() };
        const Iter it_end{ container.end() };

        state.ResumeTiming();
        int intm = 0;
        for (; it != it_end; ++it)
            intm += *it;
        result = intm;
    }

    state.SetItemsProcessed(state.iterations() * int64_t(state.range(0)));
}

template< class IterT, class ContainerT >
void benchmark_iteration_accumulate(benchmark::State &state)
{
    using Iter = IterT;

    for (auto _ : state)
    {
        state.PauseTiming();
        ContainerT container(state.range(0));
        srand(static_cast<unsigned>(time(NULL)));
        for (auto& v : container)
            v = rand();
        volatile int result = 0;

        Iter it{ container.begin() };
        const Iter it_end{ container.end() };

        state.ResumeTiming();
        result = std::accumulate(it, it_end, 0);
    }

    state.SetItemsProcessed(state.iterations() * int64_t(state.range(0)));
}

template< class IterT >
void benchmark_iteration_map(benchmark::State &state)
{
    using Iter = IterT;

    for (auto _ : state)
    {
        state.PauseTiming();
        std::map<int,int> container;
        srand(static_cast<unsigned>(time(NULL)));
        for (size_t i = 0; i < state.range(0); ++i)
            container.emplace(static_cast<int>(i), rand());
        volatile int result = 0;

        Iter it{ container.begin() };
        const Iter it_end{ container.end() };

        state.ResumeTiming();
        int intm = 0;
        for (; it != it_end; ++it)
            intm += it->second;
        result = intm;
    }

    state.SetItemsProcessed(state.iterations() *  int64_t(state.range(0)));
}

constexpr size_t MY_RANGE_START = 8 << 0;
constexpr size_t MY_RANGE_END = 8 << 20;
constexpr benchmark::TimeUnit tu = benchmark::kMicrosecond;
constexpr size_t range_multi = 2;

//BENCHMARK_TEMPLATE(benchmark_iteration, std::vector<int>::iterator, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
//BENCHMARK_TEMPLATE(benchmark_iteration, tyti::any_iterator<int>, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
//BENCHMARK_TEMPLATE(benchmark_iteration, tyti::any_iterator_virtual<int>, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);

BENCHMARK_TEMPLATE(benchmark_iteration, std::list<int>::iterator, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
BENCHMARK_TEMPLATE(benchmark_iteration, tyti::any_iterator<int>, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
BENCHMARK_TEMPLATE(benchmark_iteration, tyti::any_iterator_virtual<int>, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);

//BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, std::vector<int>::iterator, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END);
////BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, tyti::any_iterator<int>, std::vector<int>)->Range(MY_RANGE_START, MY_RANGE_END);
//BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, std::list<int>::iterator, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu);
//BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, tyti::any_iterator<int>, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu);
//BENCHMARK_TEMPLATE(benchmark_iteration_accumulate, tyti2::any_iterator<int>, std::list<int>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu);

BENCHMARK_TEMPLATE(benchmark_iteration_map, std::map<int, int>::iterator)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
BENCHMARK_TEMPLATE(benchmark_iteration_map, tyti::any_iterator<std::pair<const int, int>>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);
BENCHMARK_TEMPLATE(benchmark_iteration_map, tyti::any_iterator_virtual<std::pair<const int,int>>)->Range(MY_RANGE_START, MY_RANGE_END)->Unit(tu)->RangeMultiplier(range_multi);

BENCHMARK_MAIN();
<|endoftext|>


<commit_before>#include <sstream>
#include <cnctrq/cnctrqWorkspaceWorker.h>
#include <prtcl/core/pcSessionExport.H>
#include <cncSession.h>

#include <iostream>

namespace cnc {
  namespace cnctrq {
    using v8::Array;
    using v8::Context;
    using v8::Function;
    using v8::FunctionTemplate;
    using v8::Isolate;
    using v8::Handle;
    using v8::Local;
    using v8::Object;
    using v8::Persistent;
    using v8::Null;
    using v8::Number;
    using v8::String;
    using v8::Value;

	using frqu::prtcl::core::pcSessionExport;
    using cnc::cncSession;

    typedef pepsis::peer::cName::name_ptr name_ptr;
    typedef pString string_type;

    cnctrqWorkspaceWorker::cnctrqWorkspaceWorker(int trq_id
                                                 , path_type  path
                                                 , int operation
                                                 , Nan::Callback* callback)
      : AsyncWorker(callback)
      , _path(path)
      , _operation(operation)
      , _errcode(0)
      , _client(0)
    {
      //
      //  Obtain the TRQ's hostname from its TRQ ID.
      //
      name_ptr trq_hostname
        = pcSessionExport::self().HostnameByTrqID(trq_id);
      if (!trq_hostname) {
        _errcode = -EHOSTDOWN;
        return;
      }
      //
      //  Create the RPC client
      //
      _client = new frqu::prtcl::cnctrq::cnctrqClient(trq_hostname);
    }

    cnctrqWorkspaceWorker::cnctrqWorkspaceWorker(int trq_id
                                                 , path_type  path
                                                 , string_type spec
                                                 , bool overwrite
                                                 , bool push
                                                 , int operation
                                                 , Nan::Callback* callback)
      : AsyncWorker(callback)
      , _path(path)
      , _input_spec(spec)
      , _overwrite(overwrite)
      , _push(push)
      , _operation(operation)
      , _errcode(0)
      , _client(0)
    {
      //
      //  Obtain the TRQ's hostname from its TRQ ID.
      //
      name_ptr trq_hostname
        = pcSessionExport::self().HostnameByTrqID(trq_id);
      if (!trq_hostname) {
        _errcode = -EHOSTDOWN;
        return;
      }
      //
      //  Create the RPC client
      //
      _client = new frqu::prtcl::cnctrq::cnctrqClient(trq_hostname);
    }

    //
    //  Destructor.
    //
    cnctrqWorkspaceWorker::~cnctrqWorkspaceWorker() { delete _client; }
    //
    //  Execute
    //
    void cnctrqWorkspaceWorker::Execute() {
      if (_errcode)
        return;  // An error has occurred before we were called.
      switch (_operation) {
      case op_children:
        _errcode = _client->WorkspaceChildren(_path, _workspace_list);
        break;
      case op_delete:
        _errcode = _client->WorkspaceDelete(_path
                                            , true  // recursive
                                            , _push);
        break;
      case op_get:
        _errcode = _client->WorkspaceGet(_path, _workspace);
        break;
      case op_set:
        if (_workspace.ImportJson(_input_spec)) {
          _errcode = -EINVAL;
          std::cerr << "cnctrqWorkspaceWorker: Invalid JSON: " << _input_spec << std::endl;
          return;
        }
        _errcode = _client->WorkspaceSet(_path
                                         , _workspace
                                         , _overwrite
                                         , _push);
        break;
      default:
        std::cerr << "cnctrqWorkspaceWorker: unexpected default switch: " << std::endl;
        _errcode = -EINVAL;
      }
    }
    //
    //  HandleOKCallback
    //
    void cnctrqWorkspaceWorker::HandleOKCallback() {
      //
      //  Elaborate the error code.
      //
      int http_status;
      string_type error_sym;
      string_type error_description_brief;
      cncSession::self().RpcToHttpStatus(_errcode
                                        , http_status
                                        , error_sym
                                        , error_description_brief);
      std::ostringstream buffer;
      std::cout << "http_status=" << http_status <<"\n";
      std::cout << "_errcode=" << _errcode <<"\n";
      std::cout << "error_sym=" << error_sym <<"\n";
      std::cout << "error_description_brief=" << error_description_brief <<"\n";
      std::cout << "_errcode=" << _errcode <<"\n";
      //
      //  Allocate the return object
      //
      Local<Object> rtn = Nan::New<Object>();
      Nan::Set(rtn
               , Nan::New("errcode").ToLocalChecked()
               , Nan::New(_errcode));
      Nan::Set(rtn
               , Nan::New("http_status").ToLocalChecked()
               , Nan::New(http_status));
      Nan::Set(rtn
               , Nan::New("error_sym").ToLocalChecked()
               , Nan::New(error_sym.c_str()).ToLocalChecked());
      Nan::Set(rtn
               , Nan::New("error_description_brief").ToLocalChecked()
               , Nan::New(error_description_brief.c_str()).ToLocalChecked());
      if (!_errcode) {
        switch (_operation) {
        case op_children:
        {
//          std::cout << "Workspace children\n";
          string_type arr_ws;
          _workspace_list.ExportJson(arr_ws, true);
//          std::cout << "arr_ws: " << arr_ws << "\n";
          Nan::Set(rtn
                   , Nan::New("ws_children").ToLocalChecked()
                   , Nan::New(arr_ws.c_str()).ToLocalChecked());
        }
        break;
        case op_delete:
          // intentionally empty
          break;
        case op_get:
        {
          Nan::Set(rtn
                   , Nan::New("ws").ToLocalChecked()
                   , Nan::New(_workspace.ExportJson(true).c_str()).ToLocalChecked());
        }
        break;
        case op_set:
          break;
        default:
          std::cerr << "cnctrqWorkspaceWorker: ASSERTION" << std::endl;
          assert(0);
        }
      }
      //
      //  Prepare for callback
      //
      const unsigned argc = 1;
      Local<Value> argv[argc] = { rtn };
      callback->Call(argc, argv);
    }
    //
  } // namespace 'cnctrq'
} // namespace 'cnc'
<commit_msg>Perforce-side fix for <FRQU-211><commit_after>#include <sstream>
#include <cnctrq/cnctrqWorkspaceWorker.h>
#include <prtcl/core/pcSessionExport.H>
#include <cncSession.h>

#include <iostream>

namespace cnc {
  namespace cnctrq {
    using v8::Array;
    using v8::Context;
    using v8::Function;
    using v8::FunctionTemplate;
    using v8::Isolate;
    using v8::Handle;
    using v8::Local;
    using v8::Object;
    using v8::Persistent;
    using v8::Null;
    using v8::Number;
    using v8::String;
    using v8::Value;

	using frqu::prtcl::core::pcSessionExport;
    using cnc::cncSession;

    typedef pepsis::peer::cName::name_ptr name_ptr;
    typedef pString string_type;

    cnctrqWorkspaceWorker::cnctrqWorkspaceWorker(int trq_id
                                                 , path_type  path
                                                 , int operation
                                                 , Nan::Callback* callback)
      : AsyncWorker(callback)
      , _path(path)
      , _operation(operation)
      , _errcode(0)
      , _client(0)
    {
      //
      //  Obtain the TRQ's hostname from its TRQ ID.
      //
      name_ptr trq_hostname
        = pcSessionExport::self().HostnameByTrqID(trq_id);
      if (!trq_hostname) {
        _errcode = -EHOSTDOWN;
        return;
      }
      //
      //  Create the RPC client
      //
      _client = new frqu::prtcl::cnctrq::cnctrqClient(trq_hostname);
    }

    cnctrqWorkspaceWorker::cnctrqWorkspaceWorker(int trq_id
                                                 , path_type  path
                                                 , string_type spec
                                                 , bool overwrite
                                                 , bool push
                                                 , int operation
                                                 , Nan::Callback* callback)
      : AsyncWorker(callback)
      , _path(path)
      , _input_spec(spec)
      , _overwrite(overwrite)
      , _push(push)
      , _operation(operation)
      , _errcode(0)
      , _client(0)
    {
      //
      //  Obtain the TRQ's hostname from its TRQ ID.
      //
      name_ptr trq_hostname
        = pcSessionExport::self().HostnameByTrqID(trq_id);
      if (!trq_hostname) {
        _errcode = -EHOSTDOWN;
        return;
      }
      //
      //  Create the RPC client
      //
      _client = new frqu::prtcl::cnctrq::cnctrqClient(trq_hostname);
    }

    //
    //  Destructor.
    //
    cnctrqWorkspaceWorker::~cnctrqWorkspaceWorker() { delete _client; }
    //
    //  Execute
    //
    void cnctrqWorkspaceWorker::Execute() {
      if (_errcode)
        return;  // An error has occurred before we were called.
      switch (_operation) {
      case op_children:
        _errcode = _client->WorkspaceChildren(_path, _workspace_list);
        break;
      case op_delete:
        _errcode = _client->WorkspaceDelete(_path
                                            , true  // recursive
                                            , _push);
        break;
      case op_get:
        _errcode = _client->WorkspaceGet(_path, _workspace);
        break;
      case op_set:
        if (_workspace.ImportJson(_input_spec)) {
          _errcode = -EINVAL;
          std::cerr << "cnctrqWorkspaceWorker: Invalid JSON: " << _input_spec << std::endl;
          return;
        }
        _errcode = _client->WorkspaceSet(_path
                                         , _workspace
                                         , _overwrite
                                         , _push);
        break;
      default:
        std::cerr << "cnctrqWorkspaceWorker: unexpected default switch: " << std::endl;
        _errcode = -EINVAL;
      }
    }
    //
    //  HandleOKCallback
    //
    void cnctrqWorkspaceWorker::HandleOKCallback() {
      //
      //  Elaborate the error code.
      //
      int http_status;
      string_type error_sym;
      string_type error_description_brief;
      cncSession::self().RpcToHttpStatus(_errcode
                                        , http_status
                                        , error_sym
                                        , error_description_brief);
      std::ostringstream buffer;
      std::cout << "http_status=" << http_status <<"\n";
      std::cout << "_errcode=" << _errcode <<"\n";
      std::cout << "error_sym=" << error_sym <<"\n";
      std::cout << "error_description_brief=" << error_description_brief <<"\n";
      std::cout << "_errcode=" << _errcode <<"\n";
      //
      //  Allocate the return object
      //
      Local<Object> rtn = Nan::New<Object>();
      Nan::Set(rtn
               , Nan::New("errcode").ToLocalChecked()
               , Nan::New(_errcode));
      Nan::Set(rtn
               , Nan::New("http_status").ToLocalChecked()
               , Nan::New(http_status));
      Nan::Set(rtn
               , Nan::New("error_sym").ToLocalChecked()
               , Nan::New(error_sym.c_str()).ToLocalChecked());
      Nan::Set(rtn
               , Nan::New("error_description_brief").ToLocalChecked()
               , Nan::New(error_description_brief.c_str()).ToLocalChecked());
      switch (_operation) {
      case op_children:
      {
//          std::cout << "Workspace children\n";
        string_type arr_ws;
        _workspace_list.ExportJson(arr_ws, true);
//          std::cout << "arr_ws: " << arr_ws << "\n";
        Nan::Set(rtn
                 , Nan::New("ws_children").ToLocalChecked()
                 , Nan::New(arr_ws.c_str()).ToLocalChecked());
      }
      break;
      case op_delete:
        // intentionally empty
        break;
      case op_get:
      {
        Nan::Set(rtn
                 , Nan::New("ws").ToLocalChecked()
                 , Nan::New(_workspace.ExportJson(true).c_str()).ToLocalChecked());
      }
      break;
      case op_set:
        break;
      default:
        std::cerr << "cnctrqWorkspaceWorker: ASSERTION" << std::endl;
        assert(0);
      }
      //
      //  Prepare for callback
      //
      const unsigned argc = 1;
      Local<Value> argv[argc] = { rtn };
      callback->Call(argc, argv);
    }
    //
  } // namespace 'cnctrq'
} // namespace 'cnc'
<|endoftext|>


<commit_before>/*****************************************************************************
** Includes
*****************************************************************************/

#include <gtest/gtest.h>
#include <iostream>
#include <string>

#include "costmap_2d_ros.hpp"

/*****************************************************************************
** Helpers
*****************************************************************************/

void broadcastCostmap2DROSTestSuiteTransforms(TransformBroadcaster& broadcaster)
{
  broadcaster.add("base_link_5x5", tf::Vector3(1.0, 1.0, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.add("base_link_4x4", tf::Vector3(1.0, -3.0, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.add("base_link_5x5_3x3_offset", tf::Vector3(-3.7, 2.4, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.add("base_link_5x5_3x3_centre", tf::Vector3(-3.5, -3.5, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.add("base_link_5x5_2_5x2_5_offset", tf::Vector3(-9.7, 2.4, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.startBroadCastingThread();
}

/*****************************************************************************
** ROS Costmap Server
*****************************************************************************/

ROSCostmapServer::ROSCostmapServer(const std::string& name,
                                   const std::string& baseLinkTransformName,
                                   const grid_map::Position& origin, const double& width,
                                   const double& height)
    : tfBuffer_(ros::Duration(1.0)),
      tfListener_(tfBuffer_)

{
  ros::NodeHandle privateNodeHandle("~");
  // lots of parameters here affect the construction ( e.g. rolling window)
  // if you don't have any parameters set, then this
  //  - alot of defaults which get dumped on the ros param server
  //  - fires up an obstacle layer and an inflation layer
  //  - creates a publisher for an occupancy grid
  privateNodeHandle.setParam(name + "/robot_base_frame", baseLinkTransformName);
  privateNodeHandle.setParam(name + "/origin_x", origin.x());
  privateNodeHandle.setParam(name + "/origin_y", origin.y());
  privateNodeHandle.setParam(name + "/width", width);
  privateNodeHandle.setParam(name + "/height", height);
  privateNodeHandle.setParam(name + "/plugins", std::vector<std::string>());
  privateNodeHandle.setParam(name + "/resolution", 0.5);
  privateNodeHandle.setParam(name + "/robot_radius", 0.03); // clears 1 cell if inside, up to 4 cells on a vertex
  costmap_ = std::make_shared<ROSCostmap>(name, tfListener_);

  for ( unsigned int index = 0; index < costmap_->getCostmap()->getSizeInCellsY(); ++index ) {
    unsigned int dimension = costmap_->getCostmap()->getSizeInCellsX();
    // @todo assert dimension > 1
    // set the first row to costmap_2d::FREE_SPACE? but it shows up invisibly in rviz, so don't bother
    for ( unsigned int fill_index = 0; fill_index < dimension - 2; ++fill_index )
    {
      double fraction = static_cast<double>(fill_index + 1) / static_cast<double>(costmap_->getCostmap()->getSizeInCellsX());
      costmap_->getCostmap()->setCost(fill_index, index, fraction*costmap_2d::INSCRIBED_INFLATED_OBSTACLE );
    }
    costmap_->getCostmap()->setCost(dimension - 2, index, costmap_2d::LETHAL_OBSTACLE);
    costmap_->getCostmap()->setCost(dimension - 1, index, costmap_2d::NO_INFORMATION);
  }
}

/*****************************************************************************
** TransformBroadcaster
*****************************************************************************/

TransformBroadcaster::~TransformBroadcaster()
{
  broadcastingThread_.join();
}

void TransformBroadcaster::shutdown()
{
  shutdownFlag_ = true;
}

void TransformBroadcaster::add(const std::string& name, tf::Vector3 origin,
                               const tf::Quaternion& orientation)
{
  tf::Transform transform;
  transform.setOrigin(origin);
  transform.setRotation(orientation);
  transforms_.insert(std::pair<std::string, tf::Transform>(name, transform));
}

void TransformBroadcaster::startBroadCastingThread() {
  broadcastingThread_ = std::thread(&TransformBroadcaster::broadcast, this);
}

void TransformBroadcaster::broadcast()
{
  tf::TransformBroadcaster tf_broadcaster;
  while (ros::ok() && !shutdownFlag_) {
    for (std::pair<std::string, tf::Transform> p : transforms_) {
      tf::StampedTransform stamped_transform(p.second, ros::Time::now(), "map", p.first);
      tf_broadcaster.sendTransform(stamped_transform);
    }
    ros::Duration(0.1).sleep();
  }
}

/*****************************************************************************
** Converter Functions
*****************************************************************************/

bool fromCostmap2DROS(costmap_2d::Costmap2DROS& ros_costmap, const std::string& layer_name,
                      grid_map::GridMap& grid_map)
{

  grid_map::Costmap2DConverter<grid_map::GridMap> converter;
  boost::lock_guard<costmap_2d::Costmap2D::mutex_t> lock(*(ros_costmap.getCostmap()->getMutex()));
  converter.initializeFromCostmap2D(ros_costmap, grid_map);
  if (!converter.addLayerFromCostmap2D(ros_costmap, layer_name, grid_map)) {
    return false;
  }
  return true;
}

bool fromCostmap2DROSAtRobotPose(costmap_2d::Costmap2DROS& ros_costmap,
                                 const grid_map::Length& geometry, const std::string& layer_name,
                                 grid_map::GridMap& grid_map)
{
  grid_map::Costmap2DConverter<grid_map::GridMap> converter;
  boost::lock_guard<costmap_2d::Costmap2D::mutex_t> lock(*(ros_costmap.getCostmap()->getMutex()));
  if (!converter.initializeFromCostmap2DAtRobotPose(ros_costmap, geometry, grid_map)) {
    return false;
  }
  if (!converter.addLayerFromCostmap2DAtRobotPose(ros_costmap, layer_name, grid_map)) {
    return false;
  }
  return true;
}

/*****************************************************************************
** Tests
*****************************************************************************/

TEST(Costmap2DROSConversion, full_window)
{
  std::cout << std::endl;
  ROS_INFO("***********************************************************");
  ROS_INFO("                 Copy Full Window");
  ROS_INFO("***********************************************************");
  // preparation
  std::string layer_name =  "obstacle_costs";
  ROSCostmapServer ros_costmap_5x5("five_by_five", "base_link_5x5", grid_map::Position(0.0, 0.0), 5.0, 5.0);
  grid_map::GridMap grid_map_5x5;
  fromCostmap2DROS(*(ros_costmap_5x5.getROSCostmap()), layer_name, grid_map_5x5);
  // assert map properties
  ASSERT_EQ(grid_map_5x5.getFrameId(), ros_costmap_5x5.getROSCostmap()->getGlobalFrameID());
  ASSERT_EQ(
      grid_map_5x5.getLength().x(),
      ros_costmap_5x5.getROSCostmap()->getCostmap()->getSizeInCellsX()
          * ros_costmap_5x5.getROSCostmap()->getCostmap()->getResolution());
  ASSERT_EQ(
      grid_map_5x5.getLength().y(),
      ros_costmap_5x5.getROSCostmap()->getCostmap()->getSizeInCellsY()
          * ros_costmap_5x5.getROSCostmap()->getCostmap()->getResolution());
  ASSERT_EQ(grid_map_5x5.getSize()[0], ros_costmap_5x5.getROSCostmap()->getCostmap()->getSizeInCellsX());
  ASSERT_EQ(grid_map_5x5.getSize()[1], ros_costmap_5x5.getROSCostmap()->getCostmap()->getSizeInCellsY());
  grid_map::Length position = grid_map_5x5.getPosition() - 0.5 * grid_map_5x5.getLength().matrix();
  ASSERT_EQ(position.x(), ros_costmap_5x5.getROSCostmap()->getCostmap()->getOriginX());
  ASSERT_EQ(position.y(), ros_costmap_5x5.getROSCostmap()->getCostmap()->getOriginY());

  // assert map data
  for (unsigned int i = 0; i < 5; ++i) {
    for (unsigned int j = 0; j < 5; ++j) {
      std::cout << static_cast<int>(ros_costmap_5x5.getROSCostmap()->getCostmap()->getCost(i, j))
                << " ";
    }
    std::cout << std::endl;
  }
  for (unsigned int i = 0; i < 5; ++i) {
    for (unsigned int j = 0; j < 5; ++j) {
      std::cout << static_cast<int>(grid_map_5x5.at(layer_name, grid_map::Index(i, j))) << " ";
    }
    std::cout << std::endl;
  }
  // TODO a function which does the index conversion

  std::cout << "Original cost: " << static_cast<int>(ros_costmap_5x5.getROSCostmap()->getCostmap()->getCost(8,0)) << std::endl;
  std::cout << "New Cost: " << grid_map_5x5.at(layer_name, grid_map::Index(1,9)) << std::endl;
  std::vector<float> cost_translation_table;
  grid_map::Costmap2DCenturyTranslationTable::create(cost_translation_table);
  unsigned char cost = ros_costmap_5x5.getROSCostmap()->getCostmap()->getCost(8,0);
  ASSERT_EQ(grid_map_5x5.at(layer_name, grid_map::Index(1,9)), cost_translation_table[cost]);
  std::cout << std::endl;
}

TEST(Costmap2DROSConversion, cost_map_centres)
{
  std::cout << std::endl;
  ROS_INFO("***********************************************************");
  ROS_INFO("                 Check Subwindow Centres");
  ROS_INFO("***********************************************************");
  ROS_INFO("Subwindows are centred as closely as possible to the robot");
  ROS_INFO("pose, though not exactly. They still need to align with");
  ROS_INFO("the underlying ros costmap so that they don't introduce a");
  ROS_INFO("new kind of error. As a result, the centre is shifted from");
  ROS_INFO("the robot pose to the nearest appropriate point which aligns");
  ROS_INFO("the new cost map exactly on top of the original ros costmap.");
  std::cout << std::endl;
  std::string layer_name =  "obstacle_costs";
  ROSCostmapServer ros_costmap_5x5_3x3_offset("five_by_five_three_by_three_offset", "base_link_5x5_3x3_offset", grid_map::Position(-6.0, 0.0), 5.0, 5.0);
  ROSCostmapServer ros_costmap_5x5_3x3_centre("five_by_five_three_by_three_centre", "base_link_5x5_3x3_centre", grid_map::Position(-6.0, -6.0), 5.0, 5.0);
  ROSCostmapServer ros_costmap_5x5_2_5x2_5_offset("five_by_five_twohalf_by_twohalf_offset", "base_link_5x5_2_5x2_5_offset", grid_map::Position(-12.0, 0.0), 5.0, 5.0);
  grid_map::GridMap grid_map_5x5_3x3_offset, grid_map_5x5_3x3_centre, grid_map_5x5_2_5x2_5_offset;
  grid_map::Length geometry_3x3(3.0, 3.0);
  fromCostmap2DROSAtRobotPose(*(ros_costmap_5x5_3x3_offset.getROSCostmap()), geometry_3x3, layer_name, grid_map_5x5_3x3_offset);
  fromCostmap2DROSAtRobotPose(*(ros_costmap_5x5_3x3_centre.getROSCostmap()), geometry_3x3, layer_name, grid_map_5x5_3x3_centre);
  grid_map::Length geometry_2_5x2_5(2.5, 2.5);
  fromCostmap2DROSAtRobotPose(*(ros_costmap_5x5_2_5x2_5_offset.getROSCostmap()), geometry_2_5x2_5, layer_name, grid_map_5x5_2_5x2_5_offset);
  ROS_INFO_STREAM("  grid_map_5x5_3x3_offset : " << grid_map_5x5_3x3_offset.getPosition().transpose());
  ROS_INFO_STREAM("  grid_map_5x5_3x3_offset : " << grid_map_5x5_3x3_centre.getPosition().transpose());
  ROS_INFO_STREAM("  grid_map_5x5_3x3_offset : " << grid_map_5x5_2_5x2_5_offset.getPosition().transpose());
  ASSERT_EQ(-3.5, grid_map_5x5_3x3_offset.getPosition().x());
  ASSERT_EQ(2.5, grid_map_5x5_3x3_offset.getPosition().y());
  ASSERT_EQ(-3.5, grid_map_5x5_3x3_centre.getPosition().x());
  ASSERT_EQ(-3.5, grid_map_5x5_3x3_centre.getPosition().y());
  ASSERT_EQ(-9.75, grid_map_5x5_2_5x2_5_offset.getPosition().x());
  ASSERT_EQ(2.25, grid_map_5x5_2_5x2_5_offset.getPosition().y());
  std::cout << std::endl;
}

/*****************************************************************************
** Main program
*****************************************************************************/

int main(int argc, char **argv)
{
  ros::init(argc, argv, "test_from_ros_costmaps");

  TransformBroadcaster broadcaster;
  broadcastCostmap2DROSTestSuiteTransforms(broadcaster);

  testing::InitGoogleTest(&argc, argv);
  int result = RUN_ALL_TESTS();
  broadcaster.shutdown();
  return result;
}
<commit_msg>Initializing ROSCostmap with tf buffer.<commit_after>/*****************************************************************************
** Includes
*****************************************************************************/

#include <gtest/gtest.h>
#include <iostream>
#include <string>

#include "costmap_2d_ros.hpp"

/*****************************************************************************
** Helpers
*****************************************************************************/

void broadcastCostmap2DROSTestSuiteTransforms(TransformBroadcaster& broadcaster)
{
  broadcaster.add("base_link_5x5", tf::Vector3(1.0, 1.0, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.add("base_link_4x4", tf::Vector3(1.0, -3.0, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.add("base_link_5x5_3x3_offset", tf::Vector3(-3.7, 2.4, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.add("base_link_5x5_3x3_centre", tf::Vector3(-3.5, -3.5, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.add("base_link_5x5_2_5x2_5_offset", tf::Vector3(-9.7, 2.4, 0.0), tf::Quaternion(0, 0, 0, 1));
  broadcaster.startBroadCastingThread();
}

/*****************************************************************************
** ROS Costmap Server
*****************************************************************************/

ROSCostmapServer::ROSCostmapServer(const std::string& name,
                                   const std::string& baseLinkTransformName,
                                   const grid_map::Position& origin, const double& width,
                                   const double& height)
    : tfBuffer_(ros::Duration(1.0)),
      tfListener_(tfBuffer_)

{
  ros::NodeHandle privateNodeHandle("~");
  // lots of parameters here affect the construction ( e.g. rolling window)
  // if you don't have any parameters set, then this
  //  - alot of defaults which get dumped on the ros param server
  //  - fires up an obstacle layer and an inflation layer
  //  - creates a publisher for an occupancy grid
  privateNodeHandle.setParam(name + "/robot_base_frame", baseLinkTransformName);
  privateNodeHandle.setParam(name + "/origin_x", origin.x());
  privateNodeHandle.setParam(name + "/origin_y", origin.y());
  privateNodeHandle.setParam(name + "/width", width);
  privateNodeHandle.setParam(name + "/height", height);
  privateNodeHandle.setParam(name + "/plugins", std::vector<std::string>());
  privateNodeHandle.setParam(name + "/resolution", 0.5);
  privateNodeHandle.setParam(name + "/robot_radius", 0.03); // clears 1 cell if inside, up to 4 cells on a vertex
  costmap_ = std::make_shared<ROSCostmap>(name, tfBuffer_);

  for ( unsigned int index = 0; index < costmap_->getCostmap()->getSizeInCellsY(); ++index ) {
    unsigned int dimension = costmap_->getCostmap()->getSizeInCellsX();
    // @todo assert dimension > 1
    // set the first row to costmap_2d::FREE_SPACE? but it shows up invisibly in rviz, so don't bother
    for ( unsigned int fill_index = 0; fill_index < dimension - 2; ++fill_index )
    {
      double fraction = static_cast<double>(fill_index + 1) / static_cast<double>(costmap_->getCostmap()->getSizeInCellsX());
      costmap_->getCostmap()->setCost(fill_index, index, fraction*costmap_2d::INSCRIBED_INFLATED_OBSTACLE );
    }
    costmap_->getCostmap()->setCost(dimension - 2, index, costmap_2d::LETHAL_OBSTACLE);
    costmap_->getCostmap()->setCost(dimension - 1, index, costmap_2d::NO_INFORMATION);
  }
}

/*****************************************************************************
** TransformBroadcaster
*****************************************************************************/

TransformBroadcaster::~TransformBroadcaster()
{
  broadcastingThread_.join();
}

void TransformBroadcaster::shutdown()
{
  shutdownFlag_ = true;
}

void TransformBroadcaster::add(const std::string& name, tf::Vector3 origin,
                               const tf::Quaternion& orientation)
{
  tf::Transform transform;
  transform.setOrigin(origin);
  transform.setRotation(orientation);
  transforms_.insert(std::pair<std::string, tf::Transform>(name, transform));
}

void TransformBroadcaster::startBroadCastingThread() {
  broadcastingThread_ = std::thread(&TransformBroadcaster::broadcast, this);
}

void TransformBroadcaster::broadcast()
{
  tf::TransformBroadcaster tf_broadcaster;
  while (ros::ok() && !shutdownFlag_) {
    for (std::pair<std::string, tf::Transform> p : transforms_) {
      tf::StampedTransform stamped_transform(p.second, ros::Time::now(), "map", p.first);
      tf_broadcaster.sendTransform(stamped_transform);
    }
    ros::Duration(0.1).sleep();
  }
}

/*****************************************************************************
** Converter Functions
*****************************************************************************/

bool fromCostmap2DROS(costmap_2d::Costmap2DROS& ros_costmap, const std::string& layer_name,
                      grid_map::GridMap& grid_map)
{

  grid_map::Costmap2DConverter<grid_map::GridMap> converter;
  boost::lock_guard<costmap_2d::Costmap2D::mutex_t> lock(*(ros_costmap.getCostmap()->getMutex()));
  converter.initializeFromCostmap2D(ros_costmap, grid_map);
  if (!converter.addLayerFromCostmap2D(ros_costmap, layer_name, grid_map)) {
    return false;
  }
  return true;
}

bool fromCostmap2DROSAtRobotPose(costmap_2d::Costmap2DROS& ros_costmap,
                                 const grid_map::Length& geometry, const std::string& layer_name,
                                 grid_map::GridMap& grid_map)
{
  grid_map::Costmap2DConverter<grid_map::GridMap> converter;
  boost::lock_guard<costmap_2d::Costmap2D::mutex_t> lock(*(ros_costmap.getCostmap()->getMutex()));
  if (!converter.initializeFromCostmap2DAtRobotPose(ros_costmap, geometry, grid_map)) {
    return false;
  }
  if (!converter.addLayerFromCostmap2DAtRobotPose(ros_costmap, layer_name, grid_map)) {
    return false;
  }
  return true;
}

/*****************************************************************************
** Tests
*****************************************************************************/

TEST(Costmap2DROSConversion, full_window)
{
  std::cout << std::endl;
  ROS_INFO("***********************************************************");
  ROS_INFO("                 Copy Full Window");
  ROS_INFO("***********************************************************");
  // preparation
  std::string layer_name =  "obstacle_costs";
  ROSCostmapServer ros_costmap_5x5("five_by_five", "base_link_5x5", grid_map::Position(0.0, 0.0), 5.0, 5.0);
  grid_map::GridMap grid_map_5x5;
  fromCostmap2DROS(*(ros_costmap_5x5.getROSCostmap()), layer_name, grid_map_5x5);
  // assert map properties
  ASSERT_EQ(grid_map_5x5.getFrameId(), ros_costmap_5x5.getROSCostmap()->getGlobalFrameID());
  ASSERT_EQ(
      grid_map_5x5.getLength().x(),
      ros_costmap_5x5.getROSCostmap()->getCostmap()->getSizeInCellsX()
          * ros_costmap_5x5.getROSCostmap()->getCostmap()->getResolution());
  ASSERT_EQ(
      grid_map_5x5.getLength().y(),
      ros_costmap_5x5.getROSCostmap()->getCostmap()->getSizeInCellsY()
          * ros_costmap_5x5.getROSCostmap()->getCostmap()->getResolution());
  ASSERT_EQ(grid_map_5x5.getSize()[0], ros_costmap_5x5.getROSCostmap()->getCostmap()->getSizeInCellsX());
  ASSERT_EQ(grid_map_5x5.getSize()[1], ros_costmap_5x5.getROSCostmap()->getCostmap()->getSizeInCellsY());
  grid_map::Length position = grid_map_5x5.getPosition() - 0.5 * grid_map_5x5.getLength().matrix();
  ASSERT_EQ(position.x(), ros_costmap_5x5.getROSCostmap()->getCostmap()->getOriginX());
  ASSERT_EQ(position.y(), ros_costmap_5x5.getROSCostmap()->getCostmap()->getOriginY());

  // assert map data
  for (unsigned int i = 0; i < 5; ++i) {
    for (unsigned int j = 0; j < 5; ++j) {
      std::cout << static_cast<int>(ros_costmap_5x5.getROSCostmap()->getCostmap()->getCost(i, j))
                << " ";
    }
    std::cout << std::endl;
  }
  for (unsigned int i = 0; i < 5; ++i) {
    for (unsigned int j = 0; j < 5; ++j) {
      std::cout << static_cast<int>(grid_map_5x5.at(layer_name, grid_map::Index(i, j))) << " ";
    }
    std::cout << std::endl;
  }
  // TODO a function which does the index conversion

  std::cout << "Original cost: " << static_cast<int>(ros_costmap_5x5.getROSCostmap()->getCostmap()->getCost(8,0)) << std::endl;
  std::cout << "New Cost: " << grid_map_5x5.at(layer_name, grid_map::Index(1,9)) << std::endl;
  std::vector<float> cost_translation_table;
  grid_map::Costmap2DCenturyTranslationTable::create(cost_translation_table);
  unsigned char cost = ros_costmap_5x5.getROSCostmap()->getCostmap()->getCost(8,0);
  ASSERT_EQ(grid_map_5x5.at(layer_name, grid_map::Index(1,9)), cost_translation_table[cost]);
  std::cout << std::endl;
}

TEST(Costmap2DROSConversion, cost_map_centres)
{
  std::cout << std::endl;
  ROS_INFO("***********************************************************");
  ROS_INFO("                 Check Subwindow Centres");
  ROS_INFO("***********************************************************");
  ROS_INFO("Subwindows are centred as closely as possible to the robot");
  ROS_INFO("pose, though not exactly. They still need to align with");
  ROS_INFO("the underlying ros costmap so that they don't introduce a");
  ROS_INFO("new kind of error. As a result, the centre is shifted from");
  ROS_INFO("the robot pose to the nearest appropriate point which aligns");
  ROS_INFO("the new cost map exactly on top of the original ros costmap.");
  std::cout << std::endl;
  std::string layer_name =  "obstacle_costs";
  ROSCostmapServer ros_costmap_5x5_3x3_offset("five_by_five_three_by_three_offset", "base_link_5x5_3x3_offset", grid_map::Position(-6.0, 0.0), 5.0, 5.0);
  ROSCostmapServer ros_costmap_5x5_3x3_centre("five_by_five_three_by_three_centre", "base_link_5x5_3x3_centre", grid_map::Position(-6.0, -6.0), 5.0, 5.0);
  ROSCostmapServer ros_costmap_5x5_2_5x2_5_offset("five_by_five_twohalf_by_twohalf_offset", "base_link_5x5_2_5x2_5_offset", grid_map::Position(-12.0, 0.0), 5.0, 5.0);
  grid_map::GridMap grid_map_5x5_3x3_offset, grid_map_5x5_3x3_centre, grid_map_5x5_2_5x2_5_offset;
  grid_map::Length geometry_3x3(3.0, 3.0);
  fromCostmap2DROSAtRobotPose(*(ros_costmap_5x5_3x3_offset.getROSCostmap()), geometry_3x3, layer_name, grid_map_5x5_3x3_offset);
  fromCostmap2DROSAtRobotPose(*(ros_costmap_5x5_3x3_centre.getROSCostmap()), geometry_3x3, layer_name, grid_map_5x5_3x3_centre);
  grid_map::Length geometry_2_5x2_5(2.5, 2.5);
  fromCostmap2DROSAtRobotPose(*(ros_costmap_5x5_2_5x2_5_offset.getROSCostmap()), geometry_2_5x2_5, layer_name, grid_map_5x5_2_5x2_5_offset);
  ROS_INFO_STREAM("  grid_map_5x5_3x3_offset : " << grid_map_5x5_3x3_offset.getPosition().transpose());
  ROS_INFO_STREAM("  grid_map_5x5_3x3_offset : " << grid_map_5x5_3x3_centre.getPosition().transpose());
  ROS_INFO_STREAM("  grid_map_5x5_3x3_offset : " << grid_map_5x5_2_5x2_5_offset.getPosition().transpose());
  ASSERT_EQ(-3.5, grid_map_5x5_3x3_offset.getPosition().x());
  ASSERT_EQ(2.5, grid_map_5x5_3x3_offset.getPosition().y());
  ASSERT_EQ(-3.5, grid_map_5x5_3x3_centre.getPosition().x());
  ASSERT_EQ(-3.5, grid_map_5x5_3x3_centre.getPosition().y());
  ASSERT_EQ(-9.75, grid_map_5x5_2_5x2_5_offset.getPosition().x());
  ASSERT_EQ(2.25, grid_map_5x5_2_5x2_5_offset.getPosition().y());
  std::cout << std::endl;
}

/*****************************************************************************
** Main program
*****************************************************************************/

int main(int argc, char **argv)
{
  ros::init(argc, argv, "test_from_ros_costmaps");

  TransformBroadcaster broadcaster;
  broadcastCostmap2DROSTestSuiteTransforms(broadcaster);

  testing::InitGoogleTest(&argc, argv);
  int result = RUN_ALL_TESTS();
  broadcaster.shutdown();
  return result;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
 */

#include "test.h"
#include <bx/hash.h>

void makeCrcTable(uint32_t _poly)
{
	for (uint32_t ii = 0; ii < 256; ++ii)
	{
		uint32_t crc = ii;
		for (uint32_t jj = 0; jj < 8; ++jj)
		{
			if (1 == (crc & 1) )
			{
				crc = (crc >> 1) ^ _poly;
			}
			else
			{
				crc >>= 1;
			}
		}

		printf("0x%08x,%c", crc, 7 == (ii & 7) ? '\n' : ' ');
	}
}

struct HashTest
{
	uint32_t crc32;
	uint32_t adler32;
	const char* input;
};

const HashTest s_hashTest[] =
{
	{ 0,          1,          ""       },
	{ 0xe8b7be43, 0x00620062, "a"      },
	{ 0x9e83486d, 0x012600c4, "ab"     },
	{ 0xc340daab, 0x06060205, "abvgd"  },
	{ 0x07642fe2, 0x020a00d6, "1389"   },
	{ 0x26d75737, 0x04530139, "555333" },
};

TEST_CASE("HashCrc32", "")
{
#if 0
	makeCrcTable(0xedb88320);
	printf("\n");
	makeCrcTable(0x82f63b78);
	printf("\n");
	makeCrcTable(0xeb31d82e);
#endif // 0

	for (uint32_t ii = 0; ii < BX_COUNTOF(s_hashTest); ++ii)
	{
		const HashTest& test = s_hashTest[ii];

		bx::HashCrc32 hash;
		hash.begin();
		hash.add(test.input, bx::strLen(test.input) );
		REQUIRE(test.crc32 == hash.end() );
	}
}

TEST_CASE("HashAdler32", "")
{
	for (uint32_t ii = 0; ii < BX_COUNTOF(s_hashTest); ++ii)
	{
		const HashTest& test = s_hashTest[ii];

		bx::HashAdler32 hash;
		hash.begin();
		hash.add(test.input, bx::strLen(test.input) );
		REQUIRE(test.adler32 == hash.end() );
	}
}
<commit_msg>Added MurmurHash2A test.<commit_after>/*
 * Copyright 2010-2022 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx/blob/master/LICENSE
 */

#include "test.h"
#include <bx/hash.h>

void makeCrcTable(uint32_t _poly)
{
	for (uint32_t ii = 0; ii < 256; ++ii)
	{
		uint32_t crc = ii;
		for (uint32_t jj = 0; jj < 8; ++jj)
		{
			if (1 == (crc & 1) )
			{
				crc = (crc >> 1) ^ _poly;
			}
			else
			{
				crc >>= 1;
			}
		}

		printf("0x%08x,%c", crc, 7 == (ii & 7) ? '\n' : ' ');
	}
}

struct HashTest
{
	uint32_t crc32;
	uint32_t adler32;
	uint32_t murmur2a;
	const char* input;
};

const HashTest s_hashTest[] =
{
	{ 0,          1,          0,          ""       },
	{ 0xe8b7be43, 0x00620062, 0x803888b,  "a"      },
	{ 0x9e83486d, 0x012600c4, 0x618515af, "ab"     },
	{ 0xc340daab, 0x06060205, 0x94e3dc4d, "abvgd"  },
	{ 0x07642fe2, 0x020a00d6, 0xe602fc07, "1389"   },
	{ 0x26d75737, 0x04530139, 0x58d37863, "555333" },
};

TEST_CASE("HashCrc32", "")
{
#if 0
	makeCrcTable(0xedb88320);
	printf("\n");
	makeCrcTable(0x82f63b78);
	printf("\n");
	makeCrcTable(0xeb31d82e);
#endif // 0

	for (uint32_t ii = 0; ii < BX_COUNTOF(s_hashTest); ++ii)
	{
		const HashTest& test = s_hashTest[ii];

		bx::HashCrc32 hash;
		hash.begin();
		hash.add(test.input, bx::strLen(test.input) );
		REQUIRE(test.crc32 == hash.end() );
	}
}

TEST_CASE("HashAdler32", "")
{
	for (uint32_t ii = 0; ii < BX_COUNTOF(s_hashTest); ++ii)
	{
		const HashTest& test = s_hashTest[ii];

		bx::HashAdler32 hash;
		hash.begin();
		hash.add(test.input, bx::strLen(test.input) );
		REQUIRE(test.adler32 == hash.end() );
	}
}

/*-----------------------------------------------------------------------------
// MurmurHash2A, by Austin Appleby
//
// This is a variant of MurmurHash2 modified to use the Merkle-Damgard
// construction. Bulk speed should be identical to Murmur2, small-key speed
// will be 10%-20% slower due to the added overhead at the end of the hash.
//
// This variant fixes a minor issue where null keys were more likely to
// collide with each other than expected, and also makes the function
// more amenable to incremental implementations.
*/

#define mmix(h,k) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }

uint32_t MurmurHash2A ( const void * key, int len, uint32_t seed )
{
	const uint32_t m = 0x5bd1e995;
	const int r = 24;
	uint32_t l = len;

	const unsigned char * data = (const unsigned char *)key;

	uint32_t h = seed;

	while(len >= 4)
	{
		uint32_t k = *(uint32_t*)data;

		mmix(h,k);

		data += 4;
		len -= 4;
	}

	uint32_t t = 0;

	switch(len)
	{
	case 3: t ^= data[2] << 16;
	case 2: t ^= data[1] << 8;
	case 1: t ^= data[0];
	};

	mmix(h,t);
	mmix(h,l);

	h ^= h >> 13;
	h *= m;
	h ^= h >> 15;

	return h;
}

TEST_CASE("HashMurmur2A", "")
{
	uint32_t seed = 0;

	for (uint32_t ii = 0; ii < BX_COUNTOF(s_hashTest); ++ii)
	{
		const HashTest& test = s_hashTest[ii];

		bx::HashMurmur2A hash;
		hash.begin(seed);
		hash.add(test.input, bx::strLen(test.input) );
		REQUIRE(test.murmur2a == hash.end() );

		REQUIRE(test.murmur2a == MurmurHash2A(test.input, bx::strLen(test.input), seed) );
	}
}
<|endoftext|>


<commit_before>// C++ program for implementation of Aho Corasick algorithm
// for string matching
#include <queue>
#include <vector>
//#include <list>
#include <string>
#include <cstring>
#include <iostream>
#include <fstream>
#include <time.h>
//#include <malloc.h>

#define DEBUG       1

using namespace std;

// Max number of states in the matching machine.
// Should be equal to the sum of the length of all keywords.
//const int MAXS = 2000000;
int maxs;

// Maximum number of characters in input alphabet
const int MAXC = 26;

const int MAXM = 512;
const int ONE_MB = 1000000;

struct output {
    int value;
    struct output * next;
};

// OUTPUT FUNCTION IS IMPLEMENTED USING out[]
// Bit i in this mask is one if the word with index i
// appears when the machine enters this state.
//vector<int> out[MAXS];
struct output * * out;
struct output * mem[MAXM];

// FAILURE FUNCTION IS IMPLEMENTED USING f[]
int * f;

// GOTO FUNCTION (OR TRIE) IS IMPLEMENTED USING g[][]
//int g[MAXS][MAXC];
int * * g;

int index_in_mem = 0;
int index_in_1mb = 0;

struct output * getOneOutput() {
    struct output * ret = NULL;

    if (ONE_MB == index_in_1mb) {
        index_in_mem ++;
    }

    if (MAXM > index_in_mem)  {
        if (NULL == mem[index_in_mem]) {
            mem[index_in_mem] = (struct output *)malloc(ONE_MB * sizeof(struct output));
            index_in_1mb = 0;
        }

        ret = &mem[index_in_mem][index_in_1mb];
        ret->value = 0;
        ret->next = 0;
        index_in_1mb ++;
    }

    return ret;
}

//void addToOutput(struct output * * l, int value) {
void addToOutput(int index, int value) {
    struct output * tmp = getOneOutput();
    tmp->value = value;
    if (NULL == out[index]) {
        out[index] = tmp;
    }
    else {
        if (value < out[index]->value) {
            tmp->next = out[index];
            out[index] = tmp;
        }
        else {
            struct output * p = out[index];
            while (p) {
                if (NULL == p->next) {
                    p->next = tmp;
                    break;
                }
                else {
                    if (value < p->next->value) {
                        tmp->next = p->next;
                        p->next = tmp;
                        break;
                    }
                    else {
                        p = p->next;
                    }
                }
            }
        }
    }
}

void mergeOutput(struct output * * l_a, struct output * * l_b) {
    if (*l_b) {
        struct output * p_a = * l_a;
        struct output * pp_a = NULL;
        struct output * p_b = * l_b;

        if (NULL == (*l_a)) {
            *l_a = getOneOutput();
            (*l_a)->value = p_b->value;

            p_a = *l_a;
            p_b = p_b->next;
        }

        while (p_a && p_b) {
            if (p_b->value == p_a->value) {
                p_a = p_a->next;
                p_b = p_b->next;
                if (pp_a) {
                    pp_a = pp_a->next;
                }
                else {
                    pp_a = *l_a;
                }
            }
            else if (p_b->value < p_a->value) {
                struct output * tmp = getOneOutput();
                tmp->value = p_b->value;
                tmp->next = p_a;

                if (pp_a) {
                    pp_a->next = tmp;
                }
                else {
                    * l_a = tmp;
                }
                pp_a = tmp;
                p_b = p_b->next;
            }
            else {
                p_a = p_a->next;
                if (pp_a) {
                    pp_a = pp_a->next;
                }
                else {
                    pp_a = *l_a;
                }

            }
        }

        while (p_b){
            struct output * tmp = getOneOutput();
            tmp->value = p_b->value;

            pp_a->next = tmp;
            pp_a = tmp;

            p_b = p_b->next;
        }
    }
}

// Builds the string matching machine.
// arr -   array of words. The index of each keyword is important:
//         "out[state] & (1 << i)" is > 0 if we just found word[i]
//         in the text.
// Returns the number of states that the built machine has.
// States are numbered 0 up to the return value - 1, inclusive.
int buildMatchingMachine(vector<string>& arr, int k)
{
    // Initialize all values in output function as 0.
    //    memset(out, 0, sizeof out);

    // Initially, we just have the 0 state
    int states = 1;

    // Construct values for goto function, i.e., fill g[][]
    // This is same as building a Trie for arr[]
    for (int i = 0; i < k; ++i)
    {
        const string &word = arr[i];
        int currentState = 0;

        // Insert all characters of current word in arr[]
        for (int j = 0; j < word.size(); ++j)
        {
            int ch = word[j] - 'a';

            // Allocate a new node (create a new state) if a
            // node for ch doesn't exist.
            if (g[currentState][ch] == -1)
            g[currentState][ch] = states++;

            currentState = g[currentState][ch];
        }

        // Add current word in output function
        //        out[currentState] |= (1 << i);
//        addToOutput(&out[currentState], i);
        addToOutput(currentState, i);
    }

    // For all characters which don't have an edge from
    // root (or state 0) in Trie, add a goto edge to state
    // 0 itself
    for (int ch = 0; ch < MAXC; ++ch)
    if (g[0][ch] == -1)
    g[0][ch] = 0;

    // Now, let's build the failure function

    // Failure function is computed in breadth first order
    // using a queue
    queue<int> q;

    // Iterate over every possible input
    for (int ch = 0; ch < MAXC; ++ch)
    {
        // All nodes of depth 1 have failure function value
        // as 0. For example, in above diagram we move to 0
        // from states 1 and 3.
        if (g[0][ch] != 0)
        {
            f[g[0][ch]] = 0;
            q.push(g[0][ch]);
        }
    }

    // Now queue has states 1 and 3
    while (q.size())
    {
        // Remove the front state from queue
        int state = q.front();
        q.pop();

        // For the removed state, find failure function for
        // all those characters for which goto function is
        // not defined.
        for (int ch = 0; ch < MAXC; ++ch)
        {
            // If goto function is defined for character 'ch'
            // and 'state'
            if (g[state][ch] != -1)
            {
                // Find failure state of removed state
                int failure = f[state];

                // Find the deepest node labeled by proper
                // suffix of string from root to current
                // state.
                while (g[failure][ch] == -1)
                failure = f[failure];

                failure = g[failure][ch];
                f[g[state][ch]] = failure;

                // Merge output values
                mergeOutput(&out[g[state][ch]], &out[failure]);
                //                out[g[state][ch]] |= out[failure];

                // Insert the next level node (of Trie) in Queue
                q.push(g[state][ch]);
            }
        }
    }

    return states;
}

// Returns the next state the machine will transition to using goto
// and failure functions.
// currentState - The current state of the machine. Must be between
//                0 and the Nnumber of states - 1, inclusive.
// nextInput - The next character that enters into the machine.
int findNextState(int currentState, char nextInput)
{
    int answer = currentState;
    int ch = nextInput - 'a';

    // If goto is not defined, use failure function
    while (g[answer][ch] == -1)
    answer = f[answer];

    return g[answer][ch];
}

// This function finds all occurrences of all array words
// in text.
unsigned long long searchWords(string text, int start, int end, vector<int>& health)
{
    unsigned long long ret = 0;
    // Preprocess patterns.
    // Build machine with goto, failure and output functions

    // Initialize current state
    int currentState = 0;

    // Traverse the text through the nuilt machine to find
    // all occurrences of words in arr[]
    for (int i = 0; i < text.size(); ++i)
    {
        currentState = findNextState(currentState, text[i]);

        // Match found, print all matching words of arr[]
        // using output function.
        if (out[currentState]) {
            struct output * p = out[currentState];

            while (p) {
                if (start > p->value) {
                }
                else if (p->value <= end) {
                    ret += health[p->value];
                }
                else {
                    break;
                }

                p = p->next;
            }
        }
    }

    return ret;
}

// Driver program to test above
int main()
{
    long long min = -1;
    long long max = 0;

    int n;

#if DEBUG
    ifstream fin("input.txt");
    if (!fin.is_open()) {
        printf("open file error!\n");
        return -1;
    }
    fin >> n;
#else
    cin >> n;
#endif

    maxs = 0;
    vector<string> genes(n);
    for(int genes_i = 0; genes_i < n; genes_i++){
#if DEBUG
        fin >> genes[genes_i];
#else
        cin >> genes[genes_i];
#endif
        maxs += genes[genes_i].length();
    }

    f = (int *)malloc(maxs * sizeof(int));
    memset(f, -1, sizeof(maxs * sizeof(int)));

    g = (int * *)malloc(maxs * sizeof(int *));
    for (size_t i = 0; i < maxs; i++) {
        g[i] = (int *)malloc(MAXC * sizeof(int));
        memset(g[i], -1, MAXC * sizeof(int));
    }

    out = (struct output * *)malloc(maxs * sizeof(struct output *));
    memset(out, 0 , maxs * sizeof(struct output *));

    vector<int> health(n);
    for(int health_i = 0; health_i < n; health_i++){
#if DEBUG
        fin >> health[health_i];
#else
        cin >> health[health_i];
#endif
    }

    clock_t start,finish;
    double TheTimes;
#if DEBUG
    start=clock();
#endif
    buildMatchingMachine(genes, n);
#if DEBUG
    finish=clock();
    TheTimes=(double)(finish-start)/CLOCKS_PER_SEC;
    printf("buildMatchingMachine consume %fs\n",TheTimes);
#endif

    int s;

#if DEBUG
    fin >> s;
#else
    cin >> s;
#endif

    for(int a0 = 0; a0 < s; a0++){
        int first;
        int last;
        string d;

#if DEBUG
        fin >> first >> last >> d;
#else
        cin >> first >> last >> d;
#endif
        // your code goes here

#if DEBUG
        start=clock();
#endif
        unsigned long long ret = searchWords(d, first, last, health);
#if DEBUG
        finish=clock();
        TheTimes=(double)(finish-start)/CLOCKS_PER_SEC;
#endif
        if (ret > max) {
            max = ret;
        }

        if (0 > min || ret < min) {
            min = ret;
        }
    }

    printf("%lld %lld\n", min, max);

    return 0;
}
<commit_msg>优化 addToOutput 方法。<commit_after>// C++ program for implementation of Aho Corasick algorithm
// for string matching
#include <queue>
#include <vector>
//#include <list>
#include <string>
#include <cstring>
#include <iostream>
#include <fstream>
#include <time.h>
//#include <malloc.h>

#define DEBUG       1

using namespace std;

// Max number of states in the matching machine.
// Should be equal to the sum of the length of all keywords.
//const int MAXS = 2000000;
int maxs;

// Maximum number of characters in input alphabet
const int MAXC = 26;

const int MAXM = 512;
const int ONE_MB = 1000000;

struct output {
    int value;
    struct output * next;
};

// OUTPUT FUNCTION IS IMPLEMENTED USING out[]
// Bit i in this mask is one if the word with index i
// appears when the machine enters this state.
//vector<int> out[MAXS];
struct output * * out;
struct output * * last;
struct output * mem[MAXM];

// FAILURE FUNCTION IS IMPLEMENTED USING f[]
int * f;

// GOTO FUNCTION (OR TRIE) IS IMPLEMENTED USING g[][]
//int g[MAXS][MAXC];
int * * g;

int index_in_mem = 0;
int index_in_1mb = 0;

struct output * getOneOutput() {
    struct output * ret = NULL;

    if (ONE_MB == index_in_1mb) {
        index_in_mem ++;
    }

    if (MAXM > index_in_mem)  {
        if (NULL == mem[index_in_mem]) {
            mem[index_in_mem] = (struct output *)malloc(ONE_MB * sizeof(struct output));
            index_in_1mb = 0;
        }

        ret = &mem[index_in_mem][index_in_1mb];
        ret->value = 0;
        ret->next = 0;
        index_in_1mb ++;
    }

    return ret;
}

//void addToOutput(struct output * * l, int value) {
void addToOutput(int index, int value) {
	struct output * tmp = getOneOutput();
	tmp->value = value;
	if (NULL == out[index]) {
		out[index] = tmp;
	}
	else {
		last[index]->next = tmp;
	}
	last[index] = tmp;
}

void mergeOutput(struct output * * l_a, struct output * * l_b) {
    if (*l_b) {
        struct output * p_a = * l_a;
        struct output * pp_a = NULL;
        struct output * p_b = * l_b;

        if (NULL == (*l_a)) {
            *l_a = getOneOutput();
            (*l_a)->value = p_b->value;

            p_a = *l_a;
            p_b = p_b->next;
        }

        while (p_a && p_b) {
            if (p_b->value == p_a->value) {
                p_a = p_a->next;
                p_b = p_b->next;
                if (pp_a) {
                    pp_a = pp_a->next;
                }
                else {
                    pp_a = *l_a;
                }
            }
            else if (p_b->value < p_a->value) {
                struct output * tmp = getOneOutput();
                tmp->value = p_b->value;
                tmp->next = p_a;

                if (pp_a) {
                    pp_a->next = tmp;
                }
                else {
                    * l_a = tmp;
                }
                pp_a = tmp;
                p_b = p_b->next;
            }
            else {
                p_a = p_a->next;
                if (pp_a) {
                    pp_a = pp_a->next;
                }
                else {
                    pp_a = *l_a;
                }

            }
        }

        while (p_b){
            struct output * tmp = getOneOutput();
            tmp->value = p_b->value;

            pp_a->next = tmp;
            pp_a = tmp;

            p_b = p_b->next;
        }
    }
}

// Builds the string matching machine.
// arr -   array of words. The index of each keyword is important:
//         "out[state] & (1 << i)" is > 0 if we just found word[i]
//         in the text.
// Returns the number of states that the built machine has.
// States are numbered 0 up to the return value - 1, inclusive.
int buildMatchingMachine(vector<string>& arr, int k)
{
    // Initialize all values in output function as 0.
    //    memset(out, 0, sizeof out);

    // Initially, we just have the 0 state
    int states = 1;

    // Construct values for goto function, i.e., fill g[][]
    // This is same as building a Trie for arr[]
    for (int i = 0; i < k; ++i)
    {
        const string &word = arr[i];
        int currentState = 0;

        // Insert all characters of current word in arr[]
        for (int j = 0; j < word.size(); ++j)
        {
            int ch = word[j] - 'a';

            // Allocate a new node (create a new state) if a
            // node for ch doesn't exist.
            if (g[currentState][ch] == -1)
            g[currentState][ch] = states++;

            currentState = g[currentState][ch];
        }

        // Add current word in output function
        //        out[currentState] |= (1 << i);
//        addToOutput(&out[currentState], i);
        addToOutput(currentState, i);
    }

    // For all characters which don't have an edge from
    // root (or state 0) in Trie, add a goto edge to state
    // 0 itself
    for (int ch = 0; ch < MAXC; ++ch)
    if (g[0][ch] == -1)
    g[0][ch] = 0;

    // Now, let's build the failure function

    // Failure function is computed in breadth first order
    // using a queue
    queue<int> q;

    // Iterate over every possible input
    for (int ch = 0; ch < MAXC; ++ch)
    {
        // All nodes of depth 1 have failure function value
        // as 0. For example, in above diagram we move to 0
        // from states 1 and 3.
        if (g[0][ch] != 0)
        {
            f[g[0][ch]] = 0;
            q.push(g[0][ch]);
        }
    }

    // Now queue has states 1 and 3
    while (q.size())
    {
        // Remove the front state from queue
        int state = q.front();
        q.pop();

        // For the removed state, find failure function for
        // all those characters for which goto function is
        // not defined.
        for (int ch = 0; ch < MAXC; ++ch)
        {
            // If goto function is defined for character 'ch'
            // and 'state'
            if (g[state][ch] != -1)
            {
                // Find failure state of removed state
                int failure = f[state];

                // Find the deepest node labeled by proper
                // suffix of string from root to current
                // state.
                while (g[failure][ch] == -1)
                failure = f[failure];

                failure = g[failure][ch];
                f[g[state][ch]] = failure;

                // Merge output values
                mergeOutput(&out[g[state][ch]], &out[failure]);
                //                out[g[state][ch]] |= out[failure];

                // Insert the next level node (of Trie) in Queue
                q.push(g[state][ch]);
            }
        }
    }

    return states;
}

// Returns the next state the machine will transition to using goto
// and failure functions.
// currentState - The current state of the machine. Must be between
//                0 and the Nnumber of states - 1, inclusive.
// nextInput - The next character that enters into the machine.
int findNextState(int currentState, char nextInput)
{
    int answer = currentState;
    int ch = nextInput - 'a';

    // If goto is not defined, use failure function
    while (g[answer][ch] == -1)
    answer = f[answer];

    return g[answer][ch];
}

// This function finds all occurrences of all array words
// in text.
unsigned long long searchWords(string text, int start, int end, vector<int>& health)
{
    unsigned long long ret = 0;
    // Preprocess patterns.
    // Build machine with goto, failure and output functions

    // Initialize current state
    int currentState = 0;

    // Traverse the text through the nuilt machine to find
    // all occurrences of words in arr[]
    for (int i = 0; i < text.size(); ++i)
	{
		currentState = findNextState(currentState, text[i]);

		// Match found, print all matching words of arr[]
		// using output function.
		struct output * p = out[currentState];

		while (p) {
			if (start > p->value) {
			}
			else if (p->value <= end) {
				ret += health[p->value];
			}
			else {
				break;
			}

			p = p->next;
		}
	}

    return ret;
}

// Driver program to test above
int main()
{
    long long min = -1;
    long long max = 0;

    int n;

#if DEBUG
    ifstream fin("input.txt");
    if (!fin.is_open()) {
        printf("open file error!\n");
        return -1;
    }
    fin >> n;
#else
    cin >> n;
#endif

    maxs = 0;
    vector<string> genes(n);
    for(int genes_i = 0; genes_i < n; genes_i++){
#if DEBUG
        fin >> genes[genes_i];
#else
        cin >> genes[genes_i];
#endif
        maxs += genes[genes_i].length();
    }

    f = (int *)malloc(maxs * sizeof(int));
    memset(f, -1, sizeof(maxs * sizeof(int)));

    g = (int * *)malloc(maxs * sizeof(int *));
    for (size_t i = 0; i < maxs; i++) {
        g[i] = (int *)malloc(MAXC * sizeof(int));
        memset(g[i], -1, MAXC * sizeof(int));
    }

    out = (struct output * *)malloc(maxs * sizeof(struct output *));
    memset(out, 0 , maxs * sizeof(struct output *));

    last = (struct output * *)malloc(maxs * sizeof(struct output *));
    memset(last, 0 , maxs * sizeof(struct output *));

    vector<int> health(n);
    for(int health_i = 0; health_i < n; health_i++){
#if DEBUG
        fin >> health[health_i];
#else
        cin >> health[health_i];
#endif
    }

    clock_t start,finish;
    double TheTimes;
#if DEBUG
    start=clock();
#endif
    buildMatchingMachine(genes, n);
#if DEBUG
    finish=clock();
    TheTimes=(double)(finish-start)/CLOCKS_PER_SEC;
    printf("buildMatchingMachine consume %fs\n",TheTimes);
#endif

    int s;

#if DEBUG
    fin >> s;
#else
    cin >> s;
#endif

    for(int a0 = 0; a0 < s; a0++){
        int first;
        int last;
        string d;

#if DEBUG
        fin >> first >> last >> d;
#else
        cin >> first >> last >> d;
#endif
        // your code goes here

#if DEBUG
        start=clock();
#endif
        unsigned long long ret = searchWords(d, first, last, health);
#if DEBUG
        finish=clock();
        TheTimes=(double)(finish-start)/CLOCKS_PER_SEC;
#endif
        if (ret > max) {
            max = ret;
        }

        if (0 > min || ret < min) {
            min = ret;
        }
    }

    printf("%lld %lld\n", min, max);

    return 0;
}
<|endoftext|>


<commit_before>#include "wiHelper.h"
#include "wiRenderer.h"
#include "wiBackLog.h"

namespace wiHelper
{

	std::string toUpper(const std::string& s)
	{
		std::string result;
		std::locale loc;
		for (unsigned int i = 0; i < s.length(); ++i)
		{
			result += std::toupper(s.at(i), loc);
		}
		return result;
	}

	bool readByteData(const string& fileName, BYTE** data, size_t& dataSize){
		ifstream file(fileName, ios::binary | ios::ate);
		if (file.is_open()){

			dataSize = (size_t)file.tellg();
			file.seekg(0, file.beg);
			*data = new BYTE[dataSize];
			file.read((char*)*data, dataSize);
			file.close();

			return true;
		}
		stringstream ss("");
		ss << "File not found: " << fileName;
		messageBox(ss.str());
		return false;
	}

	void messageBox(const string& msg, const string& caption, HWND hWnd){
#ifndef WINSTORE_SUPPORT
		MessageBoxA(hWnd, msg.c_str(), caption.c_str(), 0);
#else
		//Windows::UI::Popups::MessageDialog("ASD").ShowAsync();
#endif
	}

	void screenshot(const string& name)
	{
//#ifndef WINSTORE_SUPPORT
//		CreateDirectoryA("screenshots", 0);
//		stringstream ss("");
//		if (name.length() <= 0)
//			ss << "screenshots/sc_" << getCurrentDateTimeAsString() << ".png";
//		else
//			ss << name;
//		wstringstream wss(L"");
//		wss << ss.str().c_str();
//		APIResource res = nullptr;
//		wiRenderer::renderTargetView->GetResource(&res);
//		HRESULT h = SaveWICTextureToFile(wiRenderer::immediateContext, res, GUID_ContainerFormatPng, wss.str().c_str());
//		if (FAILED(h))
//			wiBackLog::post("Screenshot failed");
//		else
//		{
//			ss << " Saved successfully!";
//			wiBackLog::post(ss.str().c_str());
//		}
//		res->Release();
//#endif
		CreateDirectoryA("screenshots", 0);
		stringstream ss("");
		if (name.length() <= 0)
			ss << "screenshots/sc_" << getCurrentDateTimeAsString() << ".png";
		else
			ss << name;
		wstringstream wss(L"");
		wss << ss.str().c_str();
		if (SUCCEEDED(wiRenderer::GetDevice()->SaveTexturePNG(wss.str(), &wiRenderer::GetDevice()->GetBackBuffer())))
		{
			ss << " Saved successfully!";
			wiBackLog::post(ss.str().c_str());
		}
		else
		{
			wiBackLog::post("Screenshot failed");
		}
	}

	string getCurrentDateTimeAsString()
	{
		time_t t = std::time(nullptr);
		struct tm time_info;
		localtime_s(&time_info, &t);
		stringstream ss("");
		ss << std::put_time(&time_info, "%d-%m-%Y %H-%M-%S");
		return ss.str();
	}
}
<commit_msg>uwp messagebox added<commit_after>#include "wiHelper.h"
#include "wiRenderer.h"
#include "wiBackLog.h"

namespace wiHelper
{

	std::string toUpper(const std::string& s)
	{
		std::string result;
		std::locale loc;
		for (unsigned int i = 0; i < s.length(); ++i)
		{
			result += std::toupper(s.at(i), loc);
		}
		return result;
	}

	bool readByteData(const string& fileName, BYTE** data, size_t& dataSize){
		ifstream file(fileName, ios::binary | ios::ate);
		if (file.is_open()){

			dataSize = (size_t)file.tellg();
			file.seekg(0, file.beg);
			*data = new BYTE[dataSize];
			file.read((char*)*data, dataSize);
			file.close();

			return true;
		}
		stringstream ss("");
		ss << "File not found: " << fileName;
		messageBox(ss.str());
		return false;
	}

	void messageBox(const string& msg, const string& caption, HWND hWnd){
#ifndef WINSTORE_SUPPORT
		MessageBoxA(hWnd, msg.c_str(), caption.c_str(), 0);
#else
		wstring wmsg(msg.begin(), msg.end());
		wstring wcaption(caption.begin(), caption.end());
		Windows::UI::Popups::MessageDialog(ref new Platform::String(wmsg.c_str()), ref new Platform::String(wcaption.c_str())).ShowAsync();
#endif
	}

	void screenshot(const string& name)
	{
		CreateDirectoryA("screenshots", 0);
		stringstream ss("");
		if (name.length() <= 0)
			ss << "screenshots/sc_" << getCurrentDateTimeAsString() << ".png";
		else
			ss << name;
		wstringstream wss(L"");
		wss << ss.str().c_str();
		if (SUCCEEDED(wiRenderer::GetDevice()->SaveTexturePNG(wss.str(), &wiRenderer::GetDevice()->GetBackBuffer())))
		{
			ss << " Saved successfully!";
			wiBackLog::post(ss.str().c_str());
		}
		else
		{
			wiBackLog::post("Screenshot failed");
		}
	}

	string getCurrentDateTimeAsString()
	{
		time_t t = std::time(nullptr);
		struct tm time_info;
		localtime_s(&time_info, &t);
		stringstream ss("");
		ss << std::put_time(&time_info, "%d-%m-%Y %H-%M-%S");
		return ss.str();
	}
}
<|endoftext|>