text:
#include <iostream>
#include <string>
#include <set>
#include <cmath>

#include <sys/stat.h>
#include <unistd.h>

#include <boost/algorithm/string.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include "akumuli.h"

const std::string DEFAULT_DIR = "/tmp";

void print_help() {
    std::cout << "Storage engine functional tests" << std::endl;
    std::cout << "-------------------------------" << std::endl;
    std::cout << "param: working directory (default: /tmp)" << std::endl;
    std::cout << "example: ./storage_test ./home/work" << std::endl;
}

bool check_path_exists(std::string path) {
    struct stat s = {0};
    if (!stat(path.c_str(), &s)) {
        return S_ISDIR(s.st_mode);
    }
    return false;
}

/** Row iterator interface
  */
struct Cursor {
    struct RowT {
        std::string timestamp;
        std::string seriesname;
        double value;
        // raw values
        aku_ParamId rawid;
        aku_Timestamp rawts;
    };

    virtual ~Cursor() = default;

    //! Check completion
    virtual bool done() = 0;
    //! Get next row
    virtual bool get_next_row(RowT& row) = 0;
};

/** Storage wrapper class. Allows to test seamlessly local libakumuli instance and akumulid daemon
  * deployed on AWS instance.
  */
struct Storage {
    virtual ~Storage() = default;
    //! Create new storage (create file on disk without opening database)
    virtual void create_new() = 0;
    //! Open storage
    virtual void open() = 0;
    //! Close storage
    virtual void close() = 0;
    //! Delete files on disk (database should be closed)
    virtual void delete_all() = 0;
    //! Write numeric value
    virtual void add(std::string ts, std::string id, double value) = 0;
    //! Query database
    virtual std::unique_ptr<Cursor> query(std::string begin,
                                          std::string end,
                                          std::vector<std::string> ids) = 0;
    //! Query series names
    virtual std::unique_ptr<Cursor> metadata_query(std::string metric,
                                                   std::string where_clause) = 0;
};

boost::property_tree::ptree from_json(std::string json) {
    //! C-string to streambuf adapter
    struct MemStreambuf : std::streambuf {
        MemStreambuf(const char* buf) {
            char* p = const_cast<char*>(buf);
            setg(p, p, p+strlen(p));
        }
    };

    boost::property_tree::ptree ptree;
    MemStreambuf strbuf(json.c_str());
    std::istream stream(&strbuf);
    boost::property_tree::json_parser::read_json(stream, ptree);
    return ptree;
}

struct LocalCursor : Cursor {
    aku_Session* session_;
    aku_Cursor*  cursor_;
    aku_Sample   sample_;

    LocalCursor(aku_Session *s, aku_Cursor *cursor)
        : session_(s)
        , cursor_(cursor)
        , sample_()
    {
        can_proceed();
    }

    bool can_proceed() {
        aku_Status status = AKU_SUCCESS;
        if (aku_cursor_is_error(cursor_, &status)) {
            std::runtime_error err(aku_error_message(status));
            BOOST_THROW_EXCEPTION(err);
        }
        return true;
    }

    virtual ~LocalCursor() {
        aku_cursor_close(cursor_);
    }

    bool advance() {
        auto n_results = aku_cursor_read(cursor_, &sample_, sizeof(aku_Sample));
        if (can_proceed()) {
            // Return true if cache is not empty
            assert(n_results == 0 || n_results == sizeof(aku_Sample));
            return n_results;
        }
        return false;
    }

    virtual bool done() {
        if (cursor_) {
            return aku_cursor_is_done(cursor_);
        }
        return true;
    }

    virtual bool get_next_row(RowT& result) {
        if (advance()) {
            const int buffer_size = AKU_LIMITS_MAX_SNAME;
            char buffer[buffer_size];
            // Convert id
            auto len = aku_param_id_to_series(session_, sample_.paramid, buffer, buffer_size);
            if (len <= 0) {
                std::runtime_error err("no such id");
                BOOST_THROW_EXCEPTION(err);
            }
            std::string paramid(buffer, buffer + len);

            std::string timestamp;
            if (sample_.payload.type & aku_PData::TIMESTAMP_BIT) {
                // Convert timestamp
                len = aku_timestamp_to_string(sample_.timestamp, buffer, buffer_size);
                if (len <= 0) {
                    std::runtime_error err("bad timestamp");
                    BOOST_THROW_EXCEPTION(err);
                }
                timestamp = std::string(buffer, buffer + len - 1);
            }
            // Convert payload
            if (sample_.payload.type & aku_PData::FLOAT_BIT) {
                result = { timestamp, paramid, sample_.payload.float64, sample_.paramid, sample_.timestamp };
            } else {
                result = { std::string(), paramid, NAN, sample_.paramid, sample_.timestamp };
            }
            return true;
        }
        return false;
    }
};

struct LocalStorage : Storage {
    const std::string work_dir_;
    const u32 compression_threshold_;
    const u64 sliding_window_size_;
    const i32 n_volumes_;
    const u32 durability_;
    bool enable_huge_tlb_;
    bool enable_allocate_;
    const char* DBNAME_;
    aku_Database *db_;
    aku_Session  *session_;

    LocalStorage(
            std::string work_dir,
            // Creation parameters, used only to create database
            u32 compression_threshold,
            u64 sliding_window_size,
            i32 n_volumes,
            // Open parameters, used unly to open database
            u32 durability = 1u,
            bool huge_tlb = false,
            bool allocate = false
            )
        : work_dir_(work_dir)
        , compression_threshold_(compression_threshold)
        , sliding_window_size_(sliding_window_size)
        , n_volumes_(n_volumes)
        , durability_(durability)
        , enable_huge_tlb_(huge_tlb)
        , enable_allocate_(allocate)
        , DBNAME_("test")
        , db_(nullptr)
        , session_(nullptr)
    {
    }

    void throw_on_error(aku_Status status) const {
        if (status != AKU_SUCCESS) {
            std::runtime_error err(aku_error_message(status));
            BOOST_THROW_EXCEPTION(err);
        }
    }

    void throw_on_error(apr_status_t status) const {
        if (status != APR_SUCCESS) {
            char buffer[1000];
            apr_strerror(status, buffer, 1000);
            std::runtime_error err(buffer);
            BOOST_THROW_EXCEPTION(err);
        }
    }

    std::string get_db_file_path() const {
        std::string path = work_dir_ + "/" + DBNAME_ + ".akumuli";
        return path;
    }

    virtual void create_new();
    virtual void open();
    virtual void close();
    virtual void delete_all();
    virtual void add(std::string ts, std::string id, double value);
    virtual std::unique_ptr<Cursor> query(std::string begin, std::string end, std::vector<std::string> ids);
    virtual std::unique_ptr<Cursor> metadata_query(std::string metric, std::string where_clause);
};

// Storage interface
void LocalStorage::close() {
    if (session_ == nullptr || db_ == nullptr) {
        std::logic_error err("Database allready closed");
        BOOST_THROW_EXCEPTION(err);
    }
    aku_destroy_session(session_);
    aku_close_database(db_);
    db_ = nullptr;
}

void LocalStorage::create_new() {
    apr_status_t result = aku_create_database(DBNAME_, work_dir_.c_str(), work_dir_.c_str(), n_volumes_, enable_allocate_);
    throw_on_error(result);
}

void LocalStorage::open() {
    if (db_ != nullptr) {
        std::logic_error err("Database allready opened");
        BOOST_THROW_EXCEPTION(err);
    }
    aku_FineTuneParams params = {};
    params.logger = &aku_console_logger;

    std::string path = get_db_file_path();
    db_ = aku_open_database(path.c_str(), params);
    session_ = aku_create_session(db_);
    //auto status = aku_open_status(db_);
    //throw_on_error(status);
}

void LocalStorage::delete_all() {
    std::string path = get_db_file_path();
    auto status = aku_remove_database(path.c_str(), path.c_str(), true);
    throw_on_error(status);
}

void LocalStorage::add(std::string ts, std::string id, double value) {
    aku_Status status = AKU_EBUSY;
    while(status == AKU_EBUSY) {
        aku_Sample sample;
        if (aku_parse_timestamp(ts.c_str(), &sample) != AKU_SUCCESS) {
            std::runtime_error err("invalid timestamp");
            BOOST_THROW_EXCEPTION(err);
        }
        if (aku_series_to_param_id(session_, id.data(), id.data() + id.size(), &sample) != AKU_SUCCESS) {
            std::runtime_error err("invalid series name");
            BOOST_THROW_EXCEPTION(err);
        }
        sample.payload.type = AKU_PAYLOAD_FLOAT;
        sample.payload.float64 = value;
        status = aku_write(session_, &sample);
    }
    throw_on_error(status);
}

std::unique_ptr<Cursor> LocalStorage::query(std::string begin,
                                            std::string end,
                                            std::vector<std::string> ids)
{
    boost::property_tree::ptree query;
    // Add metric name
    query.add("select", "cpu");
    // Add time constraints
    boost::property_tree::ptree range;
    range.add("from", begin);
    range.add("to", end);
    query.add_child("range", range);
    // Where clause
    // Where clause
    boost::property_tree::ptree where;
    boost::property_tree::ptree array;
    for (auto series: ids) {
        auto val = series.substr(8, 1);
        boost::property_tree::ptree elem;
        elem.put("", val);
        array.push_back(std::make_pair("", elem));
    }
    where.add_child("key", array);
    query.add_child("where", where);
    std::stringstream stream;
    boost::property_tree::json_parser::write_json(stream, query, true);
    std::string query_text = stream.str();

    auto cursor = aku_query(session_, query_text.c_str());
    std::unique_ptr<LocalCursor> ptr(new LocalCursor(session_, cursor));
    return std::move(ptr);
}

std::unique_ptr<Cursor> LocalStorage::metadata_query(std::string metric, std::string where_clause) {
    boost::property_tree::ptree query;

    if (metric.empty()) {
        query.add("select", "meta:names");
    } else {
        query.add("select", "meta:names:" + metric);
    }

    // Where clause
    if (!where_clause.empty()) {
        boost::property_tree::ptree where = from_json(where_clause);
        query.add_child("where", where);
    }

    std::stringstream stream;
    boost::property_tree::json_parser::write_json(stream, query, true);
    std::string query_text = stream.str();

    auto cursor = aku_query(session_, query_text.c_str());
    std::unique_ptr<LocalCursor> ptr(new LocalCursor(session_, cursor));
    return std::move(ptr);
}

struct DataPoint {
    std::string   timestamp;
    std::string   id;
    double        float_value;
};

static std::vector<DataPoint> TEST_DATA = {
    { "20150101T000000.000000000", "cpu key=0", 0.0 },
    { "20150101T000001.000000000", "cpu key=1", 1.1 },
    { "20150101T000002.000000000", "cpu key=2", 2.2 },
    { "20150101T000003.000000000", "cpu key=3", 3.3 },
    { "20150101T000004.000000000", "cpu key=4", 4.4 },
    { "20150101T000005.000000000", "cpu key=5", 5.5 },
    { "20150101T000006.000000000", "cpu key=0", 6.6 },
    { "20150101T000007.000000000", "cpu key=1", 7.7 },
    { "20150101T000008.000000000", "cpu key=2", 8.8 },
    { "20150101T000009.000000000", "cpu key=3", 9.9 },
    { "20150101T000010.000000000", "cpu key=4", 1.0 },
    { "20150101T000011.000000000", "cpu key=5", 1.1 },
    { "20150101T000012.000000000", "cpu key=0", 1.2 },
    { "20150101T000013.000000000", "cpu key=1", 1.3 },
    { "20150101T000014.000000000", "cpu key=2", 1.4 },
    { "20150101T000015.000000000", "cpu key=3", 1.5 },
    { "20150101T000016.000000000", "cpu key=4", 1.6 },
    { "20150101T000017.000000000", "cpu key=5", 1.7 },
    { "20150101T000018.000000000", "cpu key=0", 1.8 },
    { "20150101T000019.000000000", "cpu key=1", 1.9 },
};

void add_element(Storage *storage, DataPoint& td) {
    storage->add(td.timestamp, td.id, td.float_value);
    std::cout << "Add " << td.timestamp << ", " << td.id << ", " << td.float_value << std::endl;
}

void fill_data(Storage *storage) {
    for(size_t i = 0; i < TEST_DATA.size(); i++) {
        auto td = TEST_DATA[i];
        add_element(storage, td);
    }
}

struct Query {
    std::string            begin;
    std::string              end;
    std::vector<std::string> ids;
};

void query_data(Storage *storage, Query query, std::vector<DataPoint> expected) {
    std::unique_ptr<Cursor> cursor = storage->query(query.begin, query.end, query.ids);
    size_t ix = 0;
    while(!cursor->done()) {
        Cursor::RowT row;
        if (!cursor->get_next_row(row)) {
            continue;
        }
        DataPoint exp = expected.at(ix++);
        if (row.timestamp != exp.timestamp) {
            std::cout << "Error at " << ix << std::endl;
            std::cout << "bad timestamp, get " << row.timestamp
                      << ", expected " << exp.timestamp << std::endl;
            std::runtime_error err("Bad result");
            BOOST_THROW_EXCEPTION(err);
        }
        if (row.seriesname != exp.id) {
            std::cout << "Error at " << ix << std::endl;
            std::cout << "bad id, get " << row.seriesname << " (" << row.rawid << ")"
                      << ", expected " << exp.id << std::endl;
            std::runtime_error err("Bad result");
            BOOST_THROW_EXCEPTION(err);
        }
        // payload
        #ifdef VERBOSE_OUTPUT
        std::cout << "Read " << row.seriesname << ", " << row.timestamp << ", " << row.value << std::endl;
        #endif
        if (row.value != exp.float_value) {
            std::cout << "Error at " << ix << std::endl;
            std::cout << "bad float, get " << row.value
                      << ", expected " << exp.float_value << std::endl;
            std::runtime_error err("Bad result");
            BOOST_THROW_EXCEPTION(err);
        }
    }
    if (ix != expected.size()) {
        std::cout << "Not enough data read" << std::endl;
        std::cout << "expected " << expected.size() << " values but only "
                  << ix << " was read from DB" << std::endl;
        std::runtime_error err("Not enough results");
        BOOST_THROW_EXCEPTION(err);
    }
}

aku_Timestamp to_timestamp(std::string ts) {
    aku_Sample s;
    if (aku_parse_timestamp(ts.c_str(), &s) != AKU_SUCCESS) {
        std::runtime_error err("bad timestamp string");
        BOOST_THROW_EXCEPTION(err);
    }
    return s.timestamp;
}

std::string to_string(aku_Timestamp ts) {
    const int bufsz = 0x100;
    char buf[bufsz];
    int len = aku_timestamp_to_string(ts, buf, bufsz);
    if (len <= 0) {
        std::runtime_error err("bad timestamp");
        BOOST_THROW_EXCEPTION(err);
    }
    return std::string(buf, buf + bufsz);
}

/** Query subset of the elements.
  * @param storage should point to opened storage instance
  * @param invert should be set to true to query data in backward direction
  * @param expect_empty should be set to true if expected empty result
  * @param begin beginning of the time-range (smallest timestamp)
  * @param end end of the time-range (largest timestamp)
  * @param ids should contain list of ids that we interested in
  */
void query_subset(Storage* storage, std::string begin, std::string end, bool invert, bool expect_empty, std::vector<std::string> ids) {
    auto begin_ts = to_timestamp(begin);
    auto end_ts = to_timestamp(end);
#ifdef VERBOSE_OUTPUT
    std::cout << "===============" << std::endl;
    std::cout << "   Query subset" << std::endl;
    std::cout << "          begin = " << begin << std::endl;
    std::cout << "            end = " << end << std::endl;
    std::cout << "         invert = " << invert << std::endl;
    std::cout << "   expect_empty = " << expect_empty << std::endl;
    std::cout << "            ids = ";
    bool firstid = true;
    for(auto x: ids) {
        if (!firstid) {
            std::cout << ", ";
        }
        firstid = false;
        std::cout << x;
    }
    std::cout << std::endl;
    std::cout << "===============" << std::endl;
#endif
    assert(to_timestamp(begin) < to_timestamp(end));
    std::set<std::string>  idsmap(ids.begin(), ids.end());
    std::vector<DataPoint> expected;
    for (size_t i = 0; i < TEST_DATA.size(); i++) {
        auto point = TEST_DATA[i];
        auto id_match = idsmap.count(point.id);
        auto point_ts = to_timestamp(point.timestamp);
        if (invert) {
            if (id_match &&
                point_ts > begin_ts &&
                point_ts <= end_ts)
            {
                expected.push_back(point);
            }
        } else {
            if (id_match &&
                point_ts >= begin_ts &&
                point_ts < end_ts)
            {
                expected.push_back(point);
            }
        }
    }
    if (invert) {
        auto tmp = begin;
        begin = end; end = tmp;
        std::reverse(expected.begin(), expected.end());
    }
    if (expect_empty) {
        expected.clear();
    }
    Query query = { begin, end, ids };
    query_data(storage, query, expected);
}

void query_metadata(Storage* storage, std::string metric, std::string where_clause, std::vector<std::string> expected) {
    std::unique_ptr<Cursor> cursor = storage->metadata_query(metric, where_clause);
    std::vector<std::string> actual;
    while(!cursor->done()) {
        Cursor::RowT row;
        if(!cursor->get_next_row(row)) {
            continue;
        }
        actual.push_back(row.seriesname);
    }
    cursor.reset();
    std::sort(expected.begin(), expected.end());
    std::sort(actual.begin(), actual.end());

    if (actual.size() != expected.size()) {
        std::runtime_error err("actual.size() != expected.size()");
        BOOST_THROW_EXCEPTION(err);
    }

    bool has_error = false;
    for (auto i = 0u; i < actual.size(); i++) {
        if (actual.at(i) != expected.at(i)) {
            has_error = true;
            std::cout << "Error at (" << i << "), expected: " << expected.at(i)
                                                << "actual: " << actual.at(i) << std::endl;
        }
    }
    if (has_error) {
        std::runtime_error err("bad metadata query results");
        BOOST_THROW_EXCEPTION(err);
    }
}

void console_logger(aku_LogLevel tag, const char* msg) {
    if (tag == AKU_LOG_ERROR) {
        std::cerr << msg << std::endl;
    }
}

int main(int argc, const char** argv) {
    int retcode = 0;
    try {
        std::string dir;
        if (argc == 1) {
            dir = DEFAULT_DIR;
        } else if (argc == 2) {
            dir = argv[1];
            if (dir == "--help") {
                print_help();
                return 0;
            }
            if (!check_path_exists(dir)) {
                std::cout << "Invalid path" << std::endl;
                return 2;
            }
        }
        if (boost::ends_with(dir, "/")) {
            dir.pop_back();
        }
        std::cout << "Working directory: " << dir << std::endl;
        aku_initialize(nullptr, &console_logger);

        u32 compression_threshold = 5;
        u64 windowsize = 1;
        LocalStorage storage(dir, compression_threshold, windowsize, 2);

        // Try to delete old data if any
        try {
            storage.delete_all();
        } catch(std::runtime_error const&) {
            // No old data
        }
        storage.create_new();
        storage.open();
        fill_data(&storage);

        const std::vector<std::string> allseries = {
            "cpu key=0",
            "cpu key=1",
            "cpu key=2",
            "cpu key=3",
            "cpu key=4",
            "cpu key=5",
        };

        const std::vector<std::string> evenseries = {
            "cpu key=0",
            "cpu key=2",
            "cpu key=4",
        };

        const std::vector<std::string> oddseries = {
            "cpu key=1",
            "cpu key=3",
            "cpu key=5",
        };

        const std::vector<std::string> noseries;

        const char* include_odd  = R"({"key": [1, 3, 5] })";
        const char* include_even = R"({"key": [0, 2, 4] })";

        {
            // In this stage all data should be cached inside the the sequencer

            // Query all metadata
            query_metadata(&storage, "", "", allseries);
            // Query by metric
            query_metadata(&storage, "mem", "",             noseries);
            query_metadata(&storage, "cpu", "",             allseries);
            // Query by metric and key
            query_metadata(&storage, "cpu", include_odd,    oddseries);
            query_metadata(&storage, "cpu", include_even,   evenseries);

            // Read in forward direction
            query_subset(&storage, "20150101T000000", "20150101T000015", false, false, allseries);
            // Read in backward direction, result-set shouldn't be empty
            query_subset(&storage, "20150101T000000", "20150101T000020", true, false, allseries);
            // Try to read only half of the data-points in forward direction
            query_subset(&storage, "20150101T000005", "20150101T000015", false, false, allseries);
            // Try to read only half of the data-points in backward direction
            query_subset(&storage, "20150101T000005", "20150101T000015", true, false, allseries);
            query_subset(&storage, "20150101T000000", "20150101T000015", true, false, evenseries);
            query_subset(&storage, "20150101T000000", "20150101T000015", true, false, oddseries);

            storage.close();
        }

        {
            // Database is reopened. At this stage everything should be readable in both directions.
            storage.open();

            // Query all metadata
            query_metadata(&storage, "", "", allseries);
            // Query by metric
            query_metadata(&storage, "mem", "",             noseries);
            query_metadata(&storage, "cpu", "",             allseries);
            // Query by metric and key
            query_metadata(&storage, "cpu", include_odd,    oddseries);
            query_metadata(&storage, "cpu", include_even,   evenseries);

            query_subset(&storage, "20150101T000000", "20150101T000020", false, false, allseries);
            query_subset(&storage, "20150101T000000", "20150101T000020", true, false,  allseries);

            // Filter by timestamp
            query_subset(&storage, "20150101T000005", "20150101T000015", false, false, allseries);
            query_subset(&storage, "20150101T000005", "20150101T000015", true, false,  allseries);

            // Filter out BLOBs
            query_subset(&storage, "20150101T000000", "20150101T000020", true, false,  evenseries);
            query_subset(&storage, "20150101T000000", "20150101T000020", false, false, evenseries);
            // Filter out numeric values
            query_subset(&storage, "20150101T000000", "20150101T000020", true, false,  oddseries);
            query_subset(&storage, "20150101T000000", "20150101T000020", false, false, oddseries);

            storage.close();
        }

        {
            storage.open();
            // Add some data
            DataPoint newpoints[] = {
                { "20150101T000020.000000000", "cpu key=2", 2.0 },
                { "20150101T000021.000000000", "cpu key=3", 2.1 },
                { "20150101T000022.000000000", "cpu key=4", 2.2 },
                { "20150101T000023.000000000", "cpu key=5", 2.3 },
            };
            for (int i = 0; i < 4; i++) {
                TEST_DATA.push_back(newpoints[i]);
                add_element(&storage, newpoints[i]);
            }

            query_subset(&storage, "20150101T000020", "20150101T000025", false, false, allseries);
            query_subset(&storage, "20150101T000020", "20150101T000025", true, false, allseries);
            query_subset(&storage, "20150101T000000", "20150101T000020", true, false, allseries);
            query_subset(&storage, "20150101T000000", "20150101T000024", true, false, evenseries);
            query_subset(&storage, "20150101T000000", "20150101T000024", true, false, oddseries);

            storage.close();
        }

        {
            storage.open();

            // All new data should be readable
            query_subset(&storage, "20150101T000000", "20150101T000024", false, false, allseries);
            query_subset(&storage, "20150101T000000", "20150101T000024", true, false,  allseries);

            // Filter by timestamp
            query_subset(&storage, "20150101T000005", "20150101T000015", false, false, allseries);
            query_subset(&storage, "20150101T000005", "20150101T000015", true, false,  allseries);

            // Filter out BLOBs
            query_subset(&storage, "20150101T000000", "20150101T000024", true, false,  evenseries);
            query_subset(&storage, "20150101T000000", "20150101T000024", false, false, evenseries);

            // Filter out numeric values
            query_subset(&storage, "20150101T000000", "20150101T000024", true, false,  oddseries);
            query_subset(&storage, "20150101T000000", "20150101T000024", false, false, oddseries);

            // Add new series name
            DataPoint newpoint = { "20150101T000023.000000000", "cpu key=5 xxx=1", 23 };
            add_element(&storage, newpoint);

            const std::vector<std::string> newodds = {
                "cpu key=1",
                "cpu key=3",
                "cpu key=5",
                "cpu key=5 xxx=1",
            };

            // Query by metric and key
            query_metadata(&storage, "cpu", include_odd, newodds);

            storage.close();
        }

        {
            storage.open();

            // new metadata should be readable
            const std::vector<std::string> newodds = {
                "cpu key=1",
                "cpu key=3",
                "cpu key=5",
                "cpu key=5 xxx=1",
            };

            // Query by metric and key
            query_metadata(&storage, "cpu", include_odd,    newodds);
            query_metadata(&storage, "cpu", include_even,   evenseries);

            storage.close();
        }

        {
            storage.open();
            std::vector<DataPoint> exppoints = {
                { "20150101T000020.000000000", "cpu key=2", 2.0 },
                { "20150101T000021.000000000", "cpu key=3", 2.1 },
                { "20150101T000022.000000000", "cpu key=4", 2.2 },
                { "20150101T000023.000000000", "cpu key=5", 2.3 },
            };
            std::vector<DataPoint> newpoints = {
                { "20150101T000024.000000000", "cpu key=1", 2.4 },
                { "20150101T000025.000000000", "cpu key=2", 2.5 },
                { "20150101T000026.000000000", "cpu key=3", 2.6 },
                { "20150101T000027.000000000", "cpu key=4", 2.7 },
                { "20150101T000028.000000000", "cpu key=5", 2.8 },
                { "20150101T000029.000000000", "cpu key=1", 2.8 },
            };
            std::vector<std::string> ids = {
                "cpu key=1",
                "cpu key=2",
                "cpu key=3",
                "cpu key=4",
                "cpu key=5",
            };
        }

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

        storage.delete_all();
    } catch (...) {
        std::cout << boost::current_exception_diagnostic_information() << std::endl;
        retcode = -1;
    }
    return retcode;
}

max_stars_repo_name: adulau/Akumuli

max_issues_repo_name: adulau/Akumuli

max_forks_repo_name: adulau/Akumuli


text:
#pragma once

#include <cstddef>
#include <boost/asio.hpp>

// these macros are meant to be overridden by -D flag
// do not define them anywhere else.

#ifdef _WIN32
#   define WINDOWS
#endif // _WIN32

#ifndef CONFIG_RECEIVE_BUFFER_SIZE
#   define CONFIG_RECEIVE_BUFFER_SIZE 4096
#endif // CONFIG_RECEIVE_BUFFER_SIZE

#ifndef CONFIG_READ_TIMEOUT
#   define CONFIG_READ_TIMEOUT 11
#endif // CONFIG_READ_TIMEOUT

namespace serial
{
    namespace asio = boost::asio;

    namespace config
    {
        constexpr static std::size_t buffer_size = CONFIG_RECEIVE_BUFFER_SIZE;
        constexpr static uint32_t read_timeout = CONFIG_READ_TIMEOUT;
    }
}

ext: hpp


text:
#pragma once

#include <cstdint>
#include <ctime>
#include <map>
#include <string>
#include <vector>

#include <boost/json.hpp>
#include <boost/json/object.hpp>
#include <boost/json/value.hpp>

namespace hisui::report {

struct AudioDecoderInfo {
  const std::string codec;
  const int channels;
  const std::int64_t duration;
};

void tag_invoke(const boost::json::value_from_tag&,
                boost::json::value& jv,  // NOLINT
                const AudioDecoderInfo& adi);

struct VideoDecoderInfo {
  const std::string codec;
  const std::int64_t duration;
};

void tag_invoke(const boost::json::value_from_tag&,
                boost::json::value& jv,  // NOLINT
                const VideoDecoderInfo& vdi);

struct ResolutionWithTimestamp {
  const std::uint64_t timestamp;
  const std::uint32_t width;
  const std::uint32_t height;
};

void tag_invoke(const boost::json::value_from_tag&,
                boost::json::value& jv,  // NOLINT
                const ResolutionWithTimestamp& rwt);

struct OutputInfo {
  std::string container;
  std::string mux_type;
  std::string video_codec;
  std::string audio_codec;
  double duration;
};

void tag_invoke(const boost::json::value_from_tag&,
                boost::json::value& jv,  // NOLINT
                const OutputInfo& oi);

class Reporter {
 public:
  Reporter& operator=(const Reporter&) = delete;
  Reporter(Reporter&&) = delete;
  Reporter& operator=(Reporter&&) = delete;
  std::string makeSuccessReport();
  std::string makeFailureReport(const std::string&);
  void registerOutput(const OutputInfo&);
  void registerAudioDecoder(const std::string&, const AudioDecoderInfo&);
  void registerVideoDecoder(const std::string&, const VideoDecoderInfo&);

  void registerResolutionChange(const std::string&,
                                const ResolutionWithTimestamp&);

  static void open();
  static bool hasInstance();
  static Reporter& getInstance();
  static void close();

 private:
  Reporter();
  ~Reporter() = default;
  void collectVersions();
  std::string makeReport();

  inline static Reporter* m_reporter = nullptr;
  std::map<std::string, AudioDecoderInfo> m_audio_decoder_map;
  std::map<std::string, VideoDecoderInfo> m_video_decoder_map;
  std::map<std::string, std::vector<ResolutionWithTimestamp>>
      m_resolution_changes_map;
  OutputInfo m_output_info;
  boost::json::object m_report;
  std::clock_t m_start_clock;
};

}  // namespace hisui::report

max_stars_repo_name: shiguredo/hisui

max_issues_repo_name: shiguredo/hisui

max_forks_repo_name: shiguredo/hisui


text:
//
// The MIT License(MIT)
//
// Copyright(c) 2014 Demonsaw LLC
//
// 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 <cassert>
#include <stdlib.h>
#include <boost/thread.hpp>

#include "component/tunnel_component.h"
#include "component/service/service_component.h"
#include "component/status/status_component.h"
#include "thread/thread_util.h"
#include "utility/value.h"

namespace eja
{
	// Constructor
	service_component::service_component()
	{
		m_stack_size = io::stack_size;
		m_threads = network::num_threads;
	}

	service_component::service_component(const size_t threads)
	{
		m_stack_size = io::stack_size;
		m_threads = network::num_threads;
	}

	// Operator
	service_component& service_component::operator=(const service_component& comp)
	{
		if (this != &comp)
		{
			component::operator=(comp);

			m_service = comp.m_service;
			m_thread_group = comp.m_thread_group;
			m_work = comp.m_work;

			m_priority = comp.m_priority;
			m_stack_size = comp.m_stack_size;
			m_threads = comp.m_threads;
		}

		return *this;
	}

	// Utility
	void service_component::start()
	{
		assert(m_threads && invalid());

		m_service = io_service_ptr(new boost::asio::io_service());
		m_work = io_work_ptr(new boost::asio::io_service::work(*m_service));
		m_thread_group = thread_group_ptr(new boost::thread_group());

		// Threads
		boost::thread::attributes attrs;
		attrs.set_stack_size(m_stack_size);
		const auto self = shared_from_this();

		for (size_t i = 0; i < m_threads; ++i)
		{
			auto thread = new boost::thread(attrs, [self]() { self->run(); });

			// TODO: Enable priorities for Linux (more work, range 1 - 99 usually)
			WIN32_ONLY(thread_util::set_priority(thread, m_priority);)

			m_thread_group->add_thread(thread);
		}
	}

	void service_component::restart()
	{
		stop();
		start();
	}

	void service_component::stop()
	{
		// 1) Stop new work requests
		m_work.reset();

		// 2) Close asio objects (must happen BEFORE io_service stop)
		close();

		// 3) Stop
		m_service->stop();

		// 4) Wait on the remaining threads
		if (m_thread_group)
		{
			try
			{
				m_thread_group->interrupt_all();
				m_thread_group->join_all();
				m_thread_group.reset();
			}
			catch (const std::exception& /*ex*/) { }
		}

		// 5) Clear UI
		clear();
	}

	// Socket
	bool service_component::has_socket(const entity::ptr entity, const http_socket::ptr socket)
	{
		assert(socket);

		const auto set = entity->get<socket_set_component>();
		{
			thread_lock(set);
			return set->find(socket) != set->end();
		}
	}

	void service_component::add_socket(const entity::ptr entity, const http_socket::ptr socket)
	{
		assert(socket);

		const auto set = entity->get<socket_set_component>();
		{
			thread_lock(set);
			set->insert(socket);
		}
	}

	void service_component::remove_socket(const entity::ptr entity, const http_socket::ptr socket)
	{
		assert(socket);

		const auto set = entity->get<socket_set_component>();
		{
			thread_lock(set);
			set->erase(socket);
		}
	}

	http_socket::ptr service_component::get_socket(const entity::ptr entity)
	{
		const auto set = entity->get<socket_set_component>();
		{
			thread_lock(set);

			if (!set->empty())
			{
				const auto it = set->begin();
				const auto socket = *it;
				set->erase(socket);
				return socket;
			}
		}

		return http_socket::create(get_service());
	}

	// Tunnel
	bool service_component::has_tunnel(const entity::ptr entity, const http_socket::ptr socket)
	{
		assert(socket);

		const auto tunnel_list = entity->get<tunnel_list_component>();
		{
			thread_lock(tunnel_list);
			return std::find(tunnel_list->begin(), tunnel_list->end(), socket) != tunnel_list->end();
		}
	}

	void service_component::add_tunnel(const entity::ptr entity, const http_socket::ptr socket)
	{
		assert(socket);

		const auto tunnel_list = entity->get<tunnel_list_component>();
		{
			thread_lock(tunnel_list);
			tunnel_list->push_back(socket);
		}
	}

	void service_component::remove_tunnel(const entity::ptr entity, const http_socket::ptr socket)
	{
		assert(socket);

		const auto tunnel_list = entity->get<tunnel_list_component>();
		{
			thread_lock(tunnel_list);
			tunnel_list->remove(socket);
		}
	}

	http_socket::ptr service_component::get_tunnel(const entity::ptr entity)
	{
		const auto tunnel_list = entity->get<tunnel_list_component>();
		{
			thread_lock(tunnel_list);

			if (!tunnel_list->empty())
			{
				// Use a stack (LIFO)
				const auto socket = tunnel_list->front();
				tunnel_list->pop_front();
				assert(std::find(tunnel_list->begin(), tunnel_list->end(), socket) == tunnel_list->end());

				return socket;
			}
		}

		return nullptr;
	}

	// Callback
	void service_component::run()
	{
		srand(static_cast<unsigned int>(time(0)));

		try
		{
			const auto service = get_service();
			service->run();
		}
		catch (const std::exception& ex)
		{
			log(ex);
		}
	}

	// Set
	void service_component::set_status(const status value)
	{
		const auto owner = get_entity();
		if (owner)
		{
			const auto status = owner->get<status_component>();
			status->set_status(value);

			set_status();
		}
	}

	void service_component::set_status(const entity::ptr entity, const status value)
	{
		const auto status = entity->get<status_component>();
		status->set_status(value);

		set_status();
	}
}

ext: cpp

max_stars_repo_name: demonsaw/Code

max_issues_repo_name: demonsaw/Code

max_forks_repo_name: demonsaw/Code


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

#ifndef __PROCESS_PID_HPP__
#define __PROCESS_PID_HPP__

#include <stdint.h>

#include <iosfwd>
#include <string>

#include <boost/functional/hash.hpp>

#include <process/address.hpp>

#include <stout/ip.hpp>

namespace process {

// Forward declaration to break cyclic dependencies.
class ProcessBase;

/**
 * An "untyped" `PID`, used to encapsulate the process ID for
 * lower-layer abstractions (eg, when receiving incoming requests)
 * in the dispatching mechanism.
 *
 * @see process::PID
 */
struct UPID
{
  UPID() = default;

  UPID(const UPID& that) = default;

  UPID(UPID&& that) = default;

  UPID(const char* id_, const net::IP& ip_, uint16_t port_)
    : id(id_), address(ip_, port_) { resolve(); }

  UPID(const char* id_, const network::inet::Address& address_)
    : id(id_), address(address_) { resolve(); }

  UPID(const std::string& id_, const net::IP& ip_, uint16_t port_)
    : id(id_), address(ip_, port_) { resolve(); }

  UPID(const std::string& id_, const network::inet::Address& address_)
    : id(id_), address(address_) { resolve(); }

  /*implicit*/ UPID(const char* s);

  /*implicit*/ UPID(const std::string& s);

  /*implicit*/ UPID(const ProcessBase& process);

  UPID& operator=(const UPID& that) = default;

  UPID& operator=(UPID&& that) = default;

  operator std::string() const;

  operator bool() const
  {
    return id != "" && !address.ip.isAny() && address.port != 0;
  }

  bool operator!() const // NOLINT(whitespace/operators)
  {
    return id == "" && address.ip.isAny() && address.port == 0;
  }

  bool operator<(const UPID& that) const
  {
    if (address == that.address) {
      return id < that.id;
    } else {
      return address < that.address;
    }
  }

  bool operator==(const UPID& that) const
  {
    return (id == that.id && address == that.address);
  }

  bool operator!=(const UPID& that) const
  {
    return !(*this == that);
  }

  // Attempts to resolve and cache a weak pointer to the ProcessBase
  // to which this UPID refers.
  void resolve();

  // TODO(benh): store all of the members of UPID behind a
  // copy-on-write implementation because UPID is often copied but
  // rarely written which means we could optimize performance by not
  // making so many copies.

  // A copy-on-write string for performance.
  //
  // TODO(benh): Factor this out into a generic copy-on-write string.
  struct ID
  {
    static const std::string EMPTY;

    ID() = default;

    ID(const std::string& s)
      : id(std::make_shared<std::string>(s)) {}

    ID(std::string&& s)
      : id(std::make_shared<std::string>(std::move(s))) {}

    ID& operator=(std::string&& that)
    {
      id = std::make_shared<std::string>(std::move(that));
      return *this;
    }

    bool operator==(const std::string& that) const
    {
      if (!id) {
        return EMPTY == that;
      }
      return *id == that;
    }

    bool operator==(const char* that) const
    {
      if (!id) {
        return EMPTY == that;
      }
      return *id == that;
    }

    bool operator!=(const std::string& that) const
    {
      return !(*this == that);
    }

    bool operator<(const std::string& that) const
    {
      if (!id) {
        return EMPTY < that;
      }
      return *id < that;
    }

    operator const std::string&() const
    {
      if (!id) {
        return EMPTY;
      }
      return *id;
    }

  private:
    std::shared_ptr<std::string> id;
  } id;

  // TODO(asridharan): Ideally, the following `address` field should be of
  // type `network::Address` so that the default address of the PID
  // could be a unix domain socket or an IPv4/v6 address. This change
  // however is disruptive at this point and should be done after we have
  // introduced support for unix domain and IPv6 sockets into
  // `libprocess`.
  network::inet::Address address = network::inet4::Address::ANY_ANY();

  // TODO(asridharan): Currently we are introducing only an `Optional`
  // IPv6 address in the following `addresses` structure. This will
  // help us initiate some basic IPv6 support for the
  // `DockerContainerizer`.  However, going forward, once we start
  // supporting unix domain sockets and IPv4/IPv6 socket in
  // `libprocess` we will add the following fields to this structure.
  //
  // Option<network::unix::Address> unix;
  // Option<network::inet4::Address> v4;
  //
  // With the introduction of the above fields `libprocess` PID will
  // be able to support unix, IPv4 and IPv6 sockets simultaneously.
  struct
  {
    Option<network::inet6::Address> v6;
  } addresses = {None()};

  // The hostname that was used to create this UPID, if any. This is useful
  // both for display purposes and when making outgoing connections on a TLS
  // socket, where the name recorded here can be used for hostname validation
  // checks against the X509 certificate presented by the server.
  //
  // NOTE: In the context of TLS hostname validation, this can also be set
  // manually to override the result of DNS resolution before trying to
  // `connect()` to this UPID, similar to `curl --resolve`.
  Option<std::string> host;

protected:
  friend class ProcessBase;
  friend class ProcessManager;

  // A weak pointer to the actual process used to optimize enqueuing
  // events without having to go through a shared lock in the
  // `ProcessManager`. This is `None` if someone creates a UPID and
  // doesn't call `resolve()` or if `resolve()` doesn't find a valid
  // process (i.e., the process hasn't started or has terminated).
  Option<std::weak_ptr<ProcessBase*>> reference = None();
};

inline std::ostream& operator<<(std::ostream& stream, const UPID::ID& id)
{
  const std::string& s = id;
  return stream << s;
}

inline bool operator==(const std::string& s, const UPID::ID& id)
{
  return id == s;
}

inline bool operator!=(const std::string& s, const UPID::ID& id)
{
  return !(s == id);
}

inline std::string operator+(const UPID::ID& id, const std::string& s)
{
  return (const std::string&) id + s;
}

inline std::string operator+(const UPID::ID& id, std::string&& s)
{
  return (const std::string&) id + std::move(s);
}

inline std::string operator+(const std::string& s, const UPID::ID& id)
{
  return s + (const std::string&) id;
}

inline std::string operator+(std::string&& s, const UPID::ID& id)
{
  return std::move(s) + (const std::string&) id;
}

/**
 * A "process identifier" used to uniquely identify a process when
 * dispatching messages.
 *
 * Typed with the actual process class's type, which must be
 * derived from `process::ProcessBase`.
 *
 * Use it like this:
 *
 *    using namespace process;
 *
 *    class SimpleProcess : public Process<SimpleProcess>
 *    {
 *       // ...
 *    };
 *
 *
 *    SimpleProcess process;
 *    PID<SimpleProcess> pid = spawn(process);
 *
 *    // ...
 *
 *    dispatchpid, &SimpleProcess::method, "argument");
 *
 * @see process::ProcessBase
 */
template <typename T = ProcessBase>
struct PID : UPID
{
  // Need to declare PID<U> as a friend in order to write `reference`.
  template <typename U>
  friend struct PID;

  PID() : UPID() {}

  /*implicit*/ PID(const T* t) : UPID(static_cast<const ProcessBase&>(*t)) {}
  /*implicit*/ PID(const T& t) : UPID(static_cast<const ProcessBase&>(t)) {}

  template <typename Base>
  operator PID<Base>() const
  {
    // Only allow upcasts!
    T* t = nullptr;
    Base* base = t;
    (void)base; // Eliminate unused base warning.
    PID<Base> pid;
    pid.id = id;
    pid.address = address;
    pid.addresses = addresses;
    pid.reference = reference;
    return pid;
  }
};

// Outputing UPIDs and generating UPIDs using streams.
std::ostream& operator<<(std::ostream&, const UPID&);
std::istream& operator>>(std::istream&, UPID&);

} // namespace process {

namespace std {

template <>
struct hash<process::UPID>
{
  typedef size_t result_type;

  typedef process::UPID argument_type;

  result_type operator()(const argument_type& upid) const
  {
    size_t seed = 0;
    boost::hash_combine(seed, (const std::string&) upid.id);
    boost::hash_combine(seed, std::hash<net::IP>()(upid.address.ip));
    boost::hash_combine(seed, upid.address.port);
    return seed;
  }
};

} // namespace std {

#endif // __PROCESS_PID_HPP__

max_stars_repo_name: julien-faye/mesos

max_issues_repo_name: julien-faye/mesos

max_forks_repo_name: julien-faye/mesos


text: #include <boost/type_traits/same_traits.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#include "Texture.h"
//#include <IL/il.h>
//#include <IL/ilu.h>
#include <FreeImage.h>
#include <string>
#include <boost/scope_exit.hpp>
#include "kit/log/errors.h"
#include "kit/log/log.h"
#include "Filesystem.h"
#include "GLTask.h"
using namespace std;

unsigned Texture :: DEFAULT_FLAGS =
    Texture::TRANS |
    Texture::FILTER |
    Texture::CLAMP |
    Texture::MIPMAP;

float Texture :: ANISOTROPY = 1.0f;

void Texture :: set_default_flags(unsigned f)
{
    DEFAULT_FLAGS = f;
}

void Texture :: set_anisotropy(float f)
{
    ANISOTROPY = f;
}

Texture :: Texture(const std::string& fn, unsigned int flags):
    m_Filename(fn)
{
    if(not Headless::enabled()) {
        GL_TASK_START()

        {
            auto err = glGetError();
            if(err != GL_NO_ERROR)
                K_ERRORf(GENERAL, "OpenGL Error: %s", err);
        }

        FIBITMAP* tempImage = FreeImage_Load(
            FreeImage_GetFileType(fn.c_str(), 0),
            fn.c_str()
        );
        tempImage = FreeImage_ConvertTo32Bits(tempImage);
        FreeImage_FlipVertical(tempImage);
        BOOST_SCOPE_EXIT_ALL(tempImage) {
            FreeImage_Unload(tempImage);
        };
        m_Size = glm::uvec2(
            FreeImage_GetWidth(tempImage),
            FreeImage_GetHeight(tempImage)
        );
        //ilBindImage(tempImage);
        //if(!ilLoadImage(fn.c_str())){
        //    K_ERROR(READ, Filesystem::getFileName(fn));
        //}

        //glActiveTexture(GL_TEXTURE0);
        int last_id;
        glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_id);
        glGenTextures(1,&m_ID);
        glBindTexture(GL_TEXTURE_2D, m_ID);
        BOOST_SCOPE_EXIT_ALL(last_id) {
            glBindTexture(GL_TEXTURE_2D, last_id);
        };

        {
            auto err = glGetError();
            if(err != GL_NO_ERROR)
                K_ERRORf(GENERAL, "OpenGL Error: %s", err);
        }

        glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,m_Size.x,m_Size.y,0,
            GL_BGRA,GL_UNSIGNED_BYTE,(void*)FreeImage_GetBits(tempImage));

        float filter = 2.0f;
        glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &filter);
        float aniso = std::min<float>(filter, ANISOTROPY);
        if (filter >= 1.9f)
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);

        if(flags & CLAMP)
        {
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
        }
        else
        {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        }

        if(flags & FILTER)
        {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            if(flags & MIPMAP)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
            else
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        } else {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        }

        if(flags & MIPMAP)
        {
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4);

            glGenerateMipmap(GL_TEXTURE_2D);
        }

        {
            auto err = glGetError();
            if(err != GL_NO_ERROR)
                K_ERRORf(GENERAL, "OpenGL Error: %s", err);
        }

        GL_TASK_END()
    }
}

//unsigned int Texture :: load(std::string fn, unsigned int flags)
//{
//    unload();
//    FIBITMAP* img = FreeImage_Load(
//        FreeImage_GetFIFFromFilename(fn.c_str()),
//        fn.c_str()
//    );
//    if(!img)
//    {
//        FreeImage_Unload(img);
//        K_ERROR(READ, Filesystem::getFileName(fn));
//    }

//    unsigned char* buffer = FreeImage_GetBits(img);
//    m_Size = glm::uvec2(FreeImage_GetWidth(img), FreeImage_GetHeight(img));
//    if(!buffer)
//    {
//        FreeImage_Unload(img);
//        K_ERROR(READ, Filesystem::getFileName(fn));
//    }

//    glGenTextures(1,&m_ID);
//    glBindTexture(GL_TEXTURE_2D, m_ID);
//    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Size.x, m_Size.y, 0, GL_RGBA,
//        GL_UNSIGNED_BYTE, buffer);

//    FreeImage_Unload(img);
//    return m_ID;

//    //assert(glGetError() == GL_NO_ERROR);

//    //m_ID = gli::createTexture2D(fn);
//    //if(!m_ID)
//    //    K_ERROR(READ, Filesystem::getFileName(fn));

//    //assert(glGetError() == GL_NO_ERROR);
//    //return m_ID;
//}

void Texture :: unload()
{
    if(m_ID)
    {
        GL_TASK_ASYNC_START()
            glDeleteTextures(1,&m_ID);
        GL_TASK_ASYNC_END()
        m_ID = 0;
    }
}

Texture :: ~Texture()
{
    unload();
}

max_stars_repo_name: flipcoder/qor

max_issues_repo_name: flipcoder/qor

max_forks_repo_name: flipcoder/qor


text:
#pragma once

#include <iostream>
#include <iomanip>
#include <array>
#include <vector>
#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include <common_robotics_utilities/utility.hpp>
#include <Eigen/Geometry>

namespace common_robotics_utilities
{
namespace print
{
// Base template function for printing types
template <typename T>
inline std::string Print(const T& toprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ")
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  std::ostringstream strm;
  strm << toprint;
  return strm.str();
}

///////////////////////////////////////////////////////////////////
/////                     PROTOTYPES ONLY                     /////
///////////////////////////////////////////////////////////////////

template<>
inline std::string Print(const bool& bool_to_print,
                         const bool add_delimiters,
                         const std::string& separator);

template<>
inline std::string Print(const uint8_t& byte_to_print,
                         const bool add_delimiters,
                         const std::string& separator);

template<>
inline std::string Print(const Eigen::Vector2d& vector_to_print,
                         const bool add_delimiters,
                         const std::string& separator);

template<>
inline std::string Print(const Eigen::Vector3d& vector_to_print,
                         const bool add_delimiters,
                         const std::string& separator);

template<>
inline std::string Print(const Eigen::Vector4d& vector_to_print,
                         const bool add_delimiters,
                         const std::string& separator);

template<>
inline std::string Print(const Eigen::VectorXd& vector_to_print,
                         const bool add_delimiters,
                         const std::string& separator);

template<>
inline std::string Print(const Eigen::MatrixXd& matrix_to_print,
                         const bool add_delimiters,
                         const std::string& separator);

template<>
inline std::string Print(const Eigen::Quaterniond& quaternion_to_print,
                         const bool add_delimiters,
                         const std::string& separator);

template<>
inline std::string Print(const Eigen::Isometry3d& transform_to_print,
                         const bool add_delimiters,
                         const std::string& separator);

template <typename A, typename B>
inline std::string Print(const std::pair<A, B>& pairtoprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ");

template <typename T, size_t N>
inline std::string Print(const std::array<T, N>& arraytoprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ");

template <typename T, typename Allocator=std::allocator<T>>
inline std::string Print(const std::vector<T, Allocator>& vectoprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ");

template <typename T, typename Allocator=std::allocator<T>>
inline std::string Print(const std::list<T, Allocator>& listtoprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ");

template <typename T, typename Allocator=std::allocator<T>>
inline std::string Print(const std::forward_list<T, Allocator>& listtoprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ");

template <typename T, typename Allocator=std::allocator<T>>
inline std::string Print(const std::deque<T, Allocator>& dequetoprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ");

template <typename A, typename B,
          typename Compare=std::less<A>,
          typename Allocator=std::allocator<std::pair<const A, B>>>
inline std::string Print(const std::map<A, B, Compare, Allocator>& maptoprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ");

template <typename A, typename B,
          typename Compare=std::less<A>,
          typename Allocator=std::allocator<std::pair<const A, B>>>
inline std::string Print(
    const std::multimap<A, B, Compare, Allocator>& maptoprint,
    const bool add_delimiters=false,
    const std::string& separator=", ");

template <typename T,
          typename Compare=std::less<T>,
          typename Allocator=std::allocator<T>>
inline std::string Print(const std::set<T, Compare, Allocator>& settoprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ");

template <typename T,
          typename Compare=std::less<T>,
          typename Allocator=std::allocator<T>>
inline std::string Print(const std::multiset<T, Compare, Allocator>& settoprint,
                         const bool add_delimiters=false,
                         const std::string& separator=", ");

template <typename A, typename B,
          typename Hash=std::hash<A>,
          typename Predicate=std::equal_to<A>,
          typename Allocator=std::allocator<std::pair<const A, B>>>
inline std::string Print(
    const std::unordered_map<A, B, Hash, Predicate, Allocator>& maptoprint,
    const bool add_delimiters=false,
    const std::string& separator=", ");

template <typename A, typename B,
          typename Hash=std::hash<A>,
          typename Predicate=std::equal_to<A>,
          typename Allocator=std::allocator<std::pair<const A, B>>>
inline std::string Print(
    const std::unordered_multimap<A, B, Hash, Predicate, Allocator>& maptoprint,
    const bool add_delimiters=false,
    const std::string& separator=", ");

template <typename T,
          typename Hash=std::hash<T>,
          typename Predicate=std::equal_to<T>,
          typename Allocator=std::allocator<T>>
inline std::string Print(
    const std::unordered_set<T, Hash, Predicate, Allocator>& settoprint,
    const bool add_delimiters=false,
    const std::string& separator=", ");

template <typename T,
          typename Hash=std::hash<T>,
          typename Predicate=std::equal_to<T>,
          typename Allocator=std::allocator<T>>
inline std::string Print(
    const std::unordered_multiset<T, Hash, Predicate, Allocator>& settoprint,
    const bool add_delimiters=false,
    const std::string& separator=", ");

/////////////////////////////////////////////////////////////////////
/////                   IMPLEMENTATIONS ONLY                    /////
/////////////////////////////////////////////////////////////////////

template<>
inline std::string Print(const bool& bool_to_print,
                         const bool add_delimiters,
                         const std::string& separator)
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  if (bool_to_print)
  {
    return "true";
  }
  else
  {
    return "false";
  }
}

template<>
inline std::string Print(const uint8_t& byte_to_print,
                         const bool add_delimiters,
                         const std::string& separator)
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  return std::to_string(static_cast<int32_t>(byte_to_print));
}

template<>
inline std::string Print(const Eigen::Vector2d& vector_to_print,
                         const bool add_delimiters,
                         const std::string& separator)
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  std::ostringstream strm;
  strm << std::setprecision(12);
  strm << "Vector2d: <x: ";
  strm << vector_to_print(0);
  strm << " y: ";
  strm << vector_to_print(1);
  strm << ">";
  return strm.str();
}

template<>
inline std::string Print(const Eigen::Vector3d& vector_to_print,
                         const bool add_delimiters,
                         const std::string& separator)
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  std::ostringstream strm;
  strm << std::setprecision(12);
  strm << "Vector3d: <x: ";
  strm << vector_to_print.x();
  strm << " y: ";
  strm << vector_to_print.y();
  strm << " z: ";
  strm << vector_to_print.z();
  strm << ">";
  return strm.str();
}

template<>
inline std::string Print(const Eigen::Vector4d& vector_to_print,
                         const bool add_delimiters,
                         const std::string& separator)
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  std::ostringstream strm;
  strm << std::setprecision(12);
  strm << "Vector4d: <x: ";
  strm << vector_to_print(0);
  strm << " y: ";
  strm << vector_to_print(1);
  strm << " z: ";
  strm << vector_to_print(2);
  strm << " w: ";
  strm << vector_to_print(3);
  strm << ">";
  return strm.str();
}

template<>
inline std::string Print(const Eigen::VectorXd& vector_to_print,
                         const bool add_delimiters,
                         const std::string& separator)
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  if (vector_to_print.size() > 0)
  {
    std::ostringstream strm;
    strm << std::setprecision(12);
    strm << "VectorXd: <" << vector_to_print(0);
    for (ssize_t idx = 1; idx < vector_to_print.size(); idx++)
    {
      strm << ", " << vector_to_print(idx);
    }
    strm << ">";
    return strm.str();
  }
  else
  {
    return "VectorXd: <>";
  }
}

template<>
inline std::string Print(const Eigen::MatrixXd& matrix_to_print,
                         const bool add_delimiters,
                         const std::string& separator)
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  if (matrix_to_print.rows() > 0 && matrix_to_print.cols() > 0)
  {
    std::ostringstream strm;
    strm << std::setprecision(12);
    strm << "MatrixXd:\n[";
    strm << matrix_to_print(0, 0);
    for (int64_t col = 1; col < matrix_to_print.cols(); col++)
    {
      strm << ", " << matrix_to_print(0, col);
    }
    for (int64_t row = 1; row < matrix_to_print.rows(); row++)
    {
      strm << "\n" << matrix_to_print(row, 0);
      for (int64_t col = 1; col < matrix_to_print.cols(); col++)
      {
        strm << ", " << matrix_to_print(row, col);
      }
    }
    strm << "]";
    return strm.str();
  }
  else
  {
    return "MatrixXd:\n[]";
  }
}

template<>
inline std::string Print(const Eigen::Quaterniond& quaternion_to_print,
                         const bool add_delimiters,
                         const std::string& separator)
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  std::ostringstream strm;
  strm << std::setprecision(12);
  strm << "Quaterniond: <x: ";
  strm << quaternion_to_print.x();
  strm << " y: ";
  strm << quaternion_to_print.y();
  strm << " z: ";
  strm << quaternion_to_print.z();
  strm << " w: ";
  strm << quaternion_to_print.w();
  strm << ">";
  return strm.str();
}

template<>
inline std::string Print(const Eigen::Isometry3d& transform_to_print,
                         const bool add_delimiters,
                         const std::string& separator)
{
  UNUSED(add_delimiters);
  UNUSED(separator);
  Eigen::Vector3d vector_to_print = transform_to_print.translation();
  Eigen::Quaterniond quaternion_to_print(transform_to_print.rotation());
  std::ostringstream strm;
  strm << std::setprecision(12);
  strm << "Isometry3d: <x: ";
  strm << vector_to_print.x();
  strm << " y: ";
  strm << vector_to_print.y();
  strm << " z: ";
  strm << vector_to_print.z();
  strm << ">, <x: ";
  strm << quaternion_to_print.x();
  strm << " y: ";
  strm << quaternion_to_print.y();
  strm << " z: ";
  strm << quaternion_to_print.z();
  strm << " w: ";
  strm << quaternion_to_print.w();
  strm << ">";
  return strm.str();
}

template <typename A, typename B>
inline std::string Print(const std::pair<A, B>& pairtoprint,
                         const bool add_delimiters,
                         const std::string& separator)
{
  std::ostringstream strm;
  if (add_delimiters)
  {
    strm << "<" << Print(pairtoprint.first, add_delimiters, separator);
    strm << ": " << Print(pairtoprint.second, add_delimiters, separator) << ">";
  }
  else
  {
    strm << Print(pairtoprint.first, add_delimiters, separator);
    strm << ": " << Print(pairtoprint.second, add_delimiters, separator);
  }
  return strm.str();
}

template <typename T, size_t N>
inline std::string Print(const std::array<T, N>& arraytoprint,
                         const bool add_delimiters,
                         const std::string& separator)
{
  std::ostringstream strm;
  if (arraytoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "[" << Print(arraytoprint[0], add_delimiters, separator);
      for (size_t idx = 1; idx < arraytoprint.size(); idx++)
      {
        strm << separator;
        strm << Print(arraytoprint[idx], add_delimiters, separator);
      }
      strm << "]";
    }
    else
    {
      strm << Print(arraytoprint[0], add_delimiters, separator);
      for (size_t idx = 1; idx < arraytoprint.size(); idx++)
      {
        strm << separator;
        strm << Print(arraytoprint[idx], add_delimiters, separator);
      }
    }
  }
  return strm.str();
}

template <typename T, typename Allocator>
inline std::string Print(const std::vector<T, Allocator>& vectoprint,
                         const bool add_delimiters,
                         const std::string& separator)
{
  std::ostringstream strm;
  if (vectoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "[" << Print(vectoprint[0], add_delimiters, separator);
      for (size_t idx = 1; idx < vectoprint.size(); idx++)
      {
        strm << separator << Print(vectoprint[idx], add_delimiters, separator);
      }
      strm << "]";
    }
    else
    {
      strm << Print(vectoprint[0], add_delimiters, separator);
      for (size_t idx = 1; idx < vectoprint.size(); idx++)
      {
        strm << separator << Print(vectoprint[idx], add_delimiters, separator);
      }
    }
  }
  return strm.str();
}

template <typename T, typename Allocator>
inline std::string Print(const std::list<T, Allocator>& listtoprint,
                         const bool add_delimiters,
                         const std::string& separator)
{
  std::ostringstream strm;
  if (listtoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "[";
      typename std::list<T, Allocator>::const_iterator itr;
      for (itr = listtoprint.begin(); itr != listtoprint.end(); ++itr)
      {
        if (itr != listtoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
      strm << "]";
    }
    else
    {
      typename std::list<T, Allocator>::const_iterator itr;
      for (itr = listtoprint.begin(); itr != listtoprint.end(); ++itr)
      {
        if (itr != listtoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename T, typename Allocator>
inline std::string Print(const std::forward_list<T, Allocator>& listtoprint,
                         const bool add_delimiters,
                         const std::string& separator)
{
  std::ostringstream strm;
  if (listtoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "[";
      typename std::forward_list<T, Allocator>::const_iterator itr;
      for (itr = listtoprint.begin(); itr != listtoprint.end(); ++itr)
      {
        if (itr != listtoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
      strm << "]";
    }
    else
    {
      typename std::forward_list<T, Allocator>::const_iterator itr;
      for (itr = listtoprint.begin(); itr != listtoprint.end(); ++itr)
      {
        if (itr != listtoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename T, typename Allocator>
inline std::string Print(const std::deque<T, Allocator>& dequetoprint,
                         const bool add_delimiters,
                         const std::string& separator)
{
  std::ostringstream strm;
  if (dequetoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "[";
      typename std::deque<T, Allocator>::const_iterator itr;
      for (itr = dequetoprint.begin(); itr != dequetoprint.end(); ++itr)
      {
        if (itr != dequetoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
      strm << "]";
    }
    else
    {
      typename std::deque<T, Allocator>::const_iterator itr;
      for (itr = dequetoprint.begin(); itr != dequetoprint.end(); ++itr)
      {
        if (itr != dequetoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename A, typename B, typename Compare, typename Allocator>
inline std::string Print(const std::map<A, B, Compare, Allocator>& maptoprint,
                         const bool add_delimiters,
                         const std::string& separator)
{
  std::ostringstream strm;
  if (maptoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "{";
      typename std::map<A, B, Compare, Allocator>::const_iterator itr;
      for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
      {
        std::pair<A, B> cur_pair(itr->first, itr->second);
        if (itr != maptoprint.begin())
        {
          strm << separator << Print(cur_pair, add_delimiters, separator);
        }
        else
        {
          strm << Print(cur_pair, add_delimiters, separator);
        }
      }
      strm << "}";
    }
    else
    {
      typename std::map<A, B, Compare, Allocator>::const_iterator itr;
      for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
      {
        std::pair<A, B> cur_pair(itr->first, itr->second);
        if (itr != maptoprint.begin())
        {
          strm << separator << Print(cur_pair, add_delimiters, separator);
        }
        else
        {
          strm << Print(cur_pair, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename A, typename B, typename Compare, typename Allocator>
inline std::string Print(
    const std::multimap<A, B, Compare, Allocator>& maptoprint,
    const bool add_delimiters,
    const std::string& separator)
{
  std::ostringstream strm;
  if (maptoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "{";
      typename std::multimap<A, B, Compare, Allocator>::const_iterator itr;
      for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
      {
        std::pair<A, B> cur_pair(itr->first, itr->second);
        if (itr != maptoprint.begin())
        {
          strm << separator << Print(cur_pair, add_delimiters, separator);
        }
        else
        {
          strm << Print(cur_pair, add_delimiters, separator);
        }
      }
      strm << "}";
    }
    else
    {
      typename std::multimap<A, B, Compare, Allocator>::const_iterator itr;
      for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
      {
        std::pair<A, B> cur_pair(itr->first, itr->second);
        if (itr != maptoprint.begin())
        {
          strm << separator << Print(cur_pair, add_delimiters, separator);
        }
        else
        {
          strm << Print(cur_pair, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename T, typename Compare, typename Allocator>
inline std::string Print(const std::set<T, Compare, Allocator>& settoprint,
                         const bool add_delimiters,
                         const std::string& separator)
{
  std::ostringstream strm;
  if (settoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "(";
      typename std::set<T, Compare, Allocator>::const_iterator itr;
      for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
      {
        if (itr != settoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
      strm << ")";
    }
    else
    {
      typename std::set<T, Compare, Allocator>::const_iterator itr;
      for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
      {
        if (itr != settoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename T, typename Compare, typename Allocator>
inline std::string Print(const std::multiset<T, Compare, Allocator>& settoprint,
                         const bool add_delimiters,
                         const std::string& separator)
{
  std::ostringstream strm;
  if (settoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "(";
      typename std::multiset<T, Compare, Allocator>::const_iterator itr;
      for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
      {
        if (itr != settoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
      strm << ")";
    }
    else
    {
      typename std::multiset<T, Compare, Allocator>::const_iterator itr;
      for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
      {
        if (itr != settoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename A, typename B,
          typename Hash, typename Predicate, typename Allocator>
inline std::string Print(
    const std::unordered_map<A, B, Hash, Predicate, Allocator>& maptoprint,
    const bool add_delimiters,
    const std::string& separator)
{
  std::ostringstream strm;
  if (maptoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "{";
      typename std::unordered_map<A, B, Hash, Predicate, Allocator>
          ::const_iterator itr;
      for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
      {
        std::pair<A, B> cur_pair(itr->first, itr->second);
        if (itr != maptoprint.begin())
        {
          strm << separator << Print(cur_pair, add_delimiters, separator);
        }
        else
        {
          strm << Print(cur_pair, add_delimiters, separator);
        }
      }
      strm << "}";
    }
    else
    {
      typename std::unordered_map<A, B, Hash, Predicate, Allocator>
          ::const_iterator itr;
      for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
      {
        std::pair<A, B> cur_pair(itr->first, itr->second);
        if (itr != maptoprint.begin())
        {
          strm << separator << Print(cur_pair, add_delimiters, separator);
        }
        else
        {
          strm << Print(cur_pair, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename A, typename B,
          typename Hash, typename Predicate, typename Allocator>
inline std::string Print(
    const std::unordered_multimap<A, B, Hash, Predicate, Allocator>& maptoprint,
    const bool add_delimiters,
    const std::string& separator)
{
  std::ostringstream strm;
  if (maptoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "{";
      typename std::unordered_multimap<A, B, Hash, Predicate, Allocator>
          ::const_iterator itr;
      for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
      {
        std::pair<A, B> cur_pair(itr->first, itr->second);
        if (itr != maptoprint.begin())
        {
          strm << separator << Print(cur_pair, add_delimiters, separator);
        }
        else
        {
          strm << Print(cur_pair, add_delimiters, separator);
        }
      }
      strm << "}";
    }
    else
    {
      typename std::unordered_multimap<A, B, Hash, Predicate, Allocator>
          ::const_iterator itr;
      for (itr = maptoprint.begin(); itr != maptoprint.end(); ++itr)
      {
        std::pair<A, B> cur_pair(itr->first, itr->second);
        if (itr != maptoprint.begin())
        {
          strm << separator << Print(cur_pair, add_delimiters, separator);
        }
        else
        {
          strm << Print(cur_pair, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename T, typename Hash, typename Predicate, typename Allocator>
inline std::string Print(
    const std::unordered_set<T, Hash, Predicate, Allocator>& settoprint,
    const bool add_delimiters,
    const std::string& separator)
{
  std::ostringstream strm;
  if (settoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "(";
      typename std::unordered_set<T, Hash, Predicate, Allocator>
          ::const_iterator itr;
      for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
      {
        if (itr != settoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
      strm << ")";
    }
    else
    {
      typename std::unordered_set<T, Hash, Predicate, Allocator>
          ::const_iterator itr;
      for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
      {
        if (itr != settoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}

template <typename T, typename Hash, typename Predicate, typename Allocator>
inline std::string Print(
    const std::unordered_multiset<T, Hash, Predicate, Allocator>& settoprint,
    const bool add_delimiters,
    const std::string& separator)
{
  std::ostringstream strm;
  if (settoprint.size() > 0)
  {
    if (add_delimiters)
    {
      strm << "(";
      typename std::unordered_multiset<T, Hash, Predicate, Allocator>
          ::const_iterator itr;
      for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
      {
        if (itr != settoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
      strm << ")";
    }
    else
    {
      typename std::unordered_multiset<T, Hash, Predicate, Allocator>
          ::const_iterator itr;
      for (itr = settoprint.begin(); itr != settoprint.end(); ++itr)
      {
        if (itr != settoprint.begin())
        {
          strm << separator << Print(*itr, add_delimiters, separator);
        }
        else
        {
          strm << Print(*itr, add_delimiters, separator);
        }
      }
    }
  }
  return strm.str();
}
}  // namespace print
}  // namespace common_robotics_utilities


text:
#ifndef BOOST_PREPROCESSOR_ASSERT_MSG_HPP
#define BOOST_PREPROCESSOR_ASSERT_MSG_HPP

/* Copyright (C) 2001
 * Housemarque Oy
 * http://www.housemarque.com
 *
 * Permission to copy, use, modify, sell and distribute this software is
 * granted provided this copyright notice appears in all copies. This
 * software is provided "as is" without express or implied warranty, and
 * with no claim as to its suitability for any purpose.
 *
 * See http://www.boost.org for most recent version.
 */

#include <boost/preprocessor/expr_if.hpp>
#include <boost/preprocessor/logical/not.hpp>

/**
Expands to nothing if COND != 0 and to MSG if
COND == 0.

COND must expand to an integer literal in the range [0, BOOST_PP_LIMIT_MAG].

For example, BOOST_PP_ASSERT_MSG(1,A BUG!) expands to A BUG!.

*/
#define BOOST_PP_ASSERT_MSG(COND,MSG) BOOST_PP_EXPR_IF(BOOST_PP_NOT(COND),MSG)

/*
Obsolete. Use BOOST_PP_ASSERT_MSG().
 */
#define BOOST_PREPROCESSOR_ASSERT_MSG(C,MSG) BOOST_PP_ASSERT_MSG(C,MSG)
#endif


text: #include <boost/metaparse/v1/foldl_start_with_parser.hpp>


text:
#define BOOST_TEST_MODULE Linker unittests
#include <include/cow.h>
#include <boost/test/unit_test.hpp>

#include <iostream>
#include <fstream>
#include <numeric>
#include <algorithm>
BOOST_AUTO_TEST_SUITE(mmcow)

template <class T, std::size_t size>
struct ftor
{
	ftor()
	{
		(*this)();
	}
	void operator()()
	{
		T simple[size];
		std::iota(std::begin(simple), std::end(simple), 0);

		MMap::Container<T> _cow(std::begin(simple), std::end(simple));

		for (auto idx = 0; idx < size; idx++)
		{
			BOOST_CHECK_EQUAL(simple[idx], idx);
			BOOST_CHECK_EQUAL(_cow[idx], simple[idx]);
			_cow[idx] = size-idx;
		}
		for (auto idx = 0; idx < size; idx++)
		{
			BOOST_CHECK_EQUAL(simple[idx], idx);
			BOOST_CHECK_EQUAL(_cow[idx], size-idx);
		}

		std::iota(std::begin(_cow), std::end(_cow), 0);

		for (auto idx = 0; idx < size; idx++)
		{
			BOOST_CHECK_EQUAL(simple[idx], idx);
			BOOST_CHECK_EQUAL(_cow[idx], idx);
		}
		std::iota(std::begin(_cow), std::end(_cow), 100);

		uint64_t counter = 100;
		std::for_each(
			std::begin(_cow),
			std::end(_cow),
			[&](auto const& val)
			{
				BOOST_CHECK_EQUAL((uint8_t)val, counter++);
			});

		for (auto idx = 0; idx < size; idx++)
		{
			_cow[idx] = idx * 2;
			BOOST_CHECK_EQUAL(_cow[idx], idx * 2);
		}

	}
};

BOOST_AUTO_TEST_CASE(fundamental_types)
{
	ftor<uint8_t,  20>();
	ftor<uint16_t, 20>();
	ftor<uint32_t, 20>();
	ftor<uint64_t, 20>();
	ftor<int8_t, 20>();
	ftor<int16_t, 20>();
	ftor<int32_t, 20>();
	ftor<int64_t, 20>();
}

BOOST_AUTO_TEST_CASE(const_iterator_support)
{
	uint16_t simple[100];
	std::iota(std::begin(simple), std::end(simple), 0);

	MMap::Container<uint16_t> _cow(std::begin(simple), std::end(simple));

	uint16_t counter = 0;

	std::for_each(std::cbegin(_cow), std::cend(_cow), [&](auto const& it)
	{
		BOOST_CHECK_EQUAL((uint16_t)counter++, it);
	});
}

BOOST_AUTO_TEST_CASE(aggregate_POD_array)
{
	struct A
	{
		uint64_t value1;
		uint32_t value2;
	};
	A simple[100];
	simple[0].value1 = 100;
	simple[0].value2 = 139;
	MMap::Container<A> _cow(std::begin(simple), std::end(simple));

	BOOST_CHECK_EQUAL(((A)_cow[0]).value1, 100);

	A a;
	a.value1 = 101;
	a.value2 = 150;
	_cow[0] = a;

	BOOST_CHECK_EQUAL(((A)_cow[0]).value1, 101);
	BOOST_CHECK_EQUAL(((A)_cow[0]).value2, 150);

}

BOOST_AUTO_TEST_CASE(aggregate_POD_single_resize)
{
	struct A
	{
		uint16_t value1;
		uint32_t value2;
	};
	A simple;
	MMap::Container<A> _cow(&simple);

	A a;
	a.value1 = 33;
	a.value2 = 34;
	_cow[0] = a;

	BOOST_CHECK_EQUAL(((A)_cow[0]).value1, 33);
	BOOST_CHECK_EQUAL(((A)_cow[0]).value2, 34);

	BOOST_CHECK_EQUAL(1, _cow.get_size());
	_cow.resize(_cow.get_size()+1);
	BOOST_CHECK_EQUAL(2, _cow.get_size());
	a.value1 = 99;
	a.value2 = 100;
	_cow[1] = a;
	BOOST_CHECK_EQUAL(((A)_cow[1]).value1, 99);
	BOOST_CHECK_EQUAL(((A)_cow[1]).value2, 100);

	//auto resize using []
	a.value1 = 150;
	a.value2 = 151;
	_cow[2] = a;
	BOOST_CHECK_EQUAL(((A)_cow[2]).value1, 150);
	BOOST_CHECK_EQUAL(((A)_cow[2]).value2, 151);
}
BOOST_AUTO_TEST_CASE(set_get_POD_A)
{
	struct A
	{
		uint16_t value1;
		uint32_t value2;
	};
	A simple;
	MMap::Container<A> _cow(&simple);
	A a;
	a.value1 = 33;
	a.value2 = 34;
	_cow[0] = a;

	set(_cow, &A::value1, 10);
	auto v = get(_cow, &A::value1);
	BOOST_CHECK_EQUAL(v, 10);
}

BOOST_AUTO_TEST_CASE(swap_issue)
{
	uint16_t simple[100];
	MMap::Container<uint16_t> container(std::begin(simple), std::end(simple));
	container[0] = 0;
	container[1] = 1;

	container[0] = container[1];
	BOOST_CHECK_EQUAL(container[0], 1);
	BOOST_CHECK_EQUAL(container[1], 1);

	container[0] = 0;

	auto tmp = container[0];
	// tmp is more or less a pointer and not an actually value. Creating a
	// backup is not supported as of now.
	container[0] = container[1];
	container[1] = tmp;
	BOOST_CHECK_EQUAL(container[0], 1);
	BOOST_CHECK_EQUAL(container[1], 1);

	container[0] = 0;

	auto tmp2 = (uint16_t)container[0];
	// tmp is more or less a pointer and not an actually value. Creating a
	// backup is not supported as of now.
	container[0] = container[1];
	container[1] = tmp2;
	BOOST_CHECK_EQUAL(container[0], 1);
	BOOST_CHECK_EQUAL(container[1], 0);
}

BOOST_AUTO_TEST_CASE(other_type_reinterpret_cast_single_ptr)
{
	uint8_t simple[100];
	simple[0] = 100;
	simple[1] = 120;

	struct A
	{
		uint8_t should_be_100;
		uint8_t should_be_120;
	};

	MMap::Container<A> container(std::begin(simple), std::end(simple));

	BOOST_CHECK_EQUAL(get(container, &A::should_be_100), 100);
	BOOST_CHECK_EQUAL(get(container, &A::should_be_120), 120);
	BOOST_CHECK_EQUAL(container.get_size(), 50);

	MMap::Container<A> container2(std::begin(simple));
	BOOST_CHECK_EQUAL(get(container2, &A::should_be_100), 100);
	BOOST_CHECK_EQUAL(get(container2, &A::should_be_120), 120);
	BOOST_CHECK_EQUAL(container2.get_size(), 1);
}

BOOST_AUTO_TEST_CASE(copy_ctor)
{
	uint8_t simple[100];
	simple[0] = 100;
	simple[1] = 120;

	MMap::Container<uint8_t> container(std::begin(simple), std::end(simple));
	MMap::Container<uint8_t> container2(container);

	BOOST_CHECK_EQUAL(container[0], 100);
	BOOST_CHECK_EQUAL(container[1], 120);
	BOOST_CHECK_EQUAL(container2[0], 100);
	BOOST_CHECK_EQUAL(container2[1], 120);

	container[0] = 110;

	BOOST_CHECK_EQUAL(container[0], 110);
	BOOST_CHECK_EQUAL(container2[0], 100);

	container2[0] = 144;

	BOOST_CHECK_EQUAL(container[0], 110);
	BOOST_CHECK_EQUAL(container2[0], 144);

	MMap::Container<uint8_t> container3(container);

	BOOST_CHECK_EQUAL(container[0], 110);
	BOOST_CHECK_EQUAL(container2[0], 144);
	BOOST_CHECK_EQUAL(container3[0], 110);
}
BOOST_AUTO_TEST_CASE(move_ctor)
{
	uint8_t simple[100];
	simple[0] = 100;
	simple[1] = 120;
	MMap::Container<uint8_t> container(std::begin(simple), std::end(simple));
	container[0] = 13;

	MMap::Container<uint8_t> container2(std::move(container));

	BOOST_CHECK_EQUAL(container2[0], 13);
}

BOOST_AUTO_TEST_CASE(simple_default_ctor)
{
	MMap::Container<uint8_t> container;
	container[100] = 13;
	BOOST_CHECK_EQUAL(container[100], 13);
	BOOST_CHECK_EQUAL(container.get_size(), 101);
}

BOOST_AUTO_TEST_CASE(POD_default_ctor)
{
	struct A
	{
		uint8_t should_be_100;
		uint8_t should_be_120;
	};

	MMap::Container<A> container;
	A a;
	a.should_be_100 = 100;
	a.should_be_120 = 120;
	container[10] = a;

	BOOST_CHECK_EQUAL(get(container, &A::should_be_100, 10), 100);
	BOOST_CHECK_EQUAL(get(container, &A::should_be_120, 10), 120);
	BOOST_CHECK_EQUAL(container.get_size(), 11);
}

bool is_little_endian()
{
	uint16_t some_value = 10;

	uint8_t* some_ptr = reinterpret_cast<uint8_t*>(&some_value);

	return *some_ptr == some_value;
}

BOOST_AUTO_TEST_CASE(stream_overload)
{
	uint16_t simple[50];

	std::iota(std::begin(simple), std::end(simple), 100); //from 100 to 149

	MMap::Container<uint16_t> container(std::begin(simple), std::end(simple));

	BOOST_CHECK_EQUAL(container.get_size(), 50);
	std::ofstream stream;
	stream.open("dump_function");

	stream << container;

	stream.close();

	std::ifstream ifs("dump_function", std::ifstream::in);

	uint16_t expected_value = 100;
	do
	{
		uint8_t first_byte = ifs.get();
		uint8_t last_byte = ifs.get();

		uint16_t value = 0;

		if (is_little_endian())
		{
			value=first_byte | (last_byte << 8);
		}
		else
		{
			value = last_byte | (first_byte << 8);
		}
		BOOST_CHECK_EQUAL(value, expected_value++);
	}
	while (expected_value <= 149);
}
BOOST_AUTO_TEST_CASE(file_size)
{
	constexpr std::size_t number_of_elements = 2;
	uint16_t simple[number_of_elements];

	std::iota(std::begin(simple), std::end(simple), 100); //from 100 to 149

	MMap::Container<uint16_t> container(std::begin(simple), std::end(simple));

	BOOST_CHECK_EQUAL(container.get_size(), number_of_elements);
	std::ofstream stream;
	stream.open("dump_function");
	stream << container;
	stream.close();
	std::ifstream ifs("dump_function", std::ifstream::in);

	ifs.seekg(0, std::ios_base::end);
	std::streampos pos = ifs.tellg();

	BOOST_CHECK_EQUAL(number_of_elements * sizeof(uint16_t), pos);
}
BOOST_AUTO_TEST_CASE(compare_ptr_to_const_ptr)
{
	constexpr std::size_t number_of_elements = 2;
	uint8_t simple[number_of_elements];

	std::iota(std::begin(simple), std::end(simple), 100); //from 100 to 149

	MMap::Container<uint8_t> container(std::begin(simple), std::end(simple));

	uint8_t* t = &(*std::begin(container));

	MMap::Container<uint8_t> const& container2(container);

	uint8_t const* t2 = &(*std::begin(container2));

	BOOST_CHECK_EQUAL(t, t2);
}
BOOST_AUTO_TEST_CASE(assignment)
{
	constexpr std::size_t number_of_elements = 2;
	uint8_t simple[number_of_elements];

	std::iota(std::begin(simple), std::end(simple), 100); //from 100 to 149

	MMap::Container<uint8_t> container(std::begin(simple), std::end(simple));

	MMap::Container<uint8_t> container2 = container;
	auto counter = 100;
	std::for_each(std::cbegin(container2), std::cend(container2), [&](auto const& it)
	{
		BOOST_CHECK_EQUAL((uint16_t)counter++, it);
	});

}
BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: williamnagels/mmcow

max_issues_repo_name: williamnagels/mmcow

max_forks_repo_name: williamnagels/mmcow