text:
// Copyright (C) 2014 Massachusetts Institute of Technology, Lincoln Laboratory
// License: Boost Software License   See LICENSE.txt for the full license.
// Authors: Davis E. King (davis@dlib.net)

#include <mitie/text_categorizer_trainer.h>
#include <dlib/svm_threaded.h>

using namespace std;
using namespace dlib;

namespace mitie
{

// ----------------------------------------------------------------------------------------
    text_categorizer_trainer::
    text_categorizer_trainer ( ) : beta(0.5), num_threads(4)
    {

    }

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

    text_categorizer_trainer::
    text_categorizer_trainer (
        const std::string& filename
    ) : beta(0.5), num_threads(4)
    {
        string classname;
        dlib::deserialize(filename) >> classname >> tfe;
    }

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

    unsigned long text_categorizer_trainer::
    size() const
    {
        return contents.size();
    }

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

    void text_categorizer_trainer::
    add (
            const std::vector<std::string>& text,
            const std::string& label
    )
    {
        contents.push_back(text);
        text_labels.push_back(get_label_id(label));
    }

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

    void text_categorizer_trainer::
    add (
            const std::vector<std::vector<std::string> >& texts,
            const std::vector<std::string>& labels
    )
    /*!
        requires
            - it must be legal to call add(texts[i], labels[i]) for all i.
        ensures
            - For all valid i: performs:  add(texts[i], labels[i]);
                (i.e. This function is just a convenience for adding a bunch of training
                data into a trainer in one call).
    !*/
    {
        DLIB_CASSERT(texts.size() == labels.size(),"");

        for (unsigned long i = 0; i < texts.size(); ++i)
            add(texts[i], labels[i]);
    }

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

    unsigned long text_categorizer_trainer::
    get_num_threads (
    ) const { return num_threads; }

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

    void text_categorizer_trainer::
    set_num_threads (
        unsigned long num
    ) { num_threads = num; }

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

    double text_categorizer_trainer::
    get_beta (
    ) const { return beta; }

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

    void text_categorizer_trainer::
    set_beta (
        double new_beta
    )
    {
        DLIB_CASSERT(new_beta >= 0, "Invalid beta");
        beta = new_beta;
    }

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

    text_categorizer text_categorizer_trainer::
    train (
    ) const
    /*!
        requires
            - size() > 0
    !*/
    {
        DLIB_CASSERT(size() > 0, "You can't train a text_categorizer if you don't give any training data.");

        // timestaper used for printouts
        dlib::timestamper ts;

        // Print out all the labels the user gave to the screen.
        std::vector<std::string> all_labels = get_all_labels();
        cout << "Training to recognize " << all_labels.size() << " categories: ";
        for (unsigned long i = 0; i < all_labels.size(); ++i)
        {
            cout << "'" << all_labels[i] << "'";
            if (i+1 < all_labels.size())
                cout << ", ";
        }
        cout << endl;

        cout << "Train classifier" << endl;

        dlib::uint64 start = ts.get_timestamp();
        classifier_type df = train_text_categorizer_classifier();
        dlib::uint64 stop = ts.get_timestamp();
        cout << "Training time: " << (stop - start)/1000/1000 << " seconds." << endl;
        cout << "df.number_of_classes(): "<< df.number_of_classes() << endl << endl;

        return text_categorizer(get_all_labels(), tfe, df);
    }

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

    class train_text_classifier_objective
    {
    public:
        train_text_classifier_objective (
            const std::vector<text_sample_type>& samples_,
            const std::vector<unsigned long>& labels_,
            unsigned long num_threads_,
            double beta_,
            unsigned long num_labels_,
            unsigned long max_iterations_
        ) : samples(samples_), labels(labels_), num_threads(num_threads_), beta(beta_), num_labels(num_labels_), max_iterations(max_iterations_)
        {}

        double operator() (
            const double C
        ) const
        {
            svm_multiclass_linear_trainer<sparse_linear_kernel<text_sample_type>,unsigned long> trainer;

            trainer.set_c(C);
            trainer.set_num_threads(num_threads);
            trainer.set_max_iterations(max_iterations);
            //trainer.be_verbose();
            matrix<double> res = cross_validate_multiclass_trainer(trainer, samples, labels, 2);
            double score = compute_fscore(res, num_labels);
            cout << "C: " << C << "   f-score: "<< score << endl;
            return score;
        }

        double compute_fscore (
            const matrix<double>& res,
            const unsigned long num_labels
        ) const
        {
            // Any output from the classifier that has a label value >= num_labels is
            // predicting that something is in the "not a relation" category.  For the
            // purposes of computing precision, we ignore this category.
            double correct_relation_predictions = sum(diag(subm(res,0,0, num_labels, num_labels)));
            double total_relation_predictions   = sum(     subm(res,0,0, res.nr(), num_labels));
            double total_truth_relations        = sum(     subm(res,0,0, num_labels, res.nc()));

            double precision = correct_relation_predictions/total_relation_predictions;
            double recall = correct_relation_predictions/total_truth_relations;

            return (1+beta*beta) * precision*recall/(beta*beta*precision + recall);
        }

    private:
        const std::vector<text_sample_type>& samples;
        const std::vector<unsigned long>& labels;
        const unsigned long num_threads;
        const double beta;
        const unsigned long num_labels;
        const unsigned long max_iterations;
    };

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

    unsigned long text_categorizer_trainer::
    count_of_least_common_label (
        const std::vector<unsigned long>& labels
    ) const
    {
        std::map<unsigned long, unsigned long> counts;
        for (unsigned long i = 0; i < labels.size(); ++i)
        {
            counts[labels[i]]++;
        }
        unsigned long min_count = 1000000000; //std::numeric_limits<unsigned long>::max();
        for (std::map<unsigned long,unsigned long>::iterator i = counts.begin(); i != counts.end(); ++i)
        {
            min_count = std::min(min_count, i->second);
        }
        return min_count;
    }

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

    text_categorizer_trainer::classifier_type text_categorizer_trainer::
    train_text_categorizer_classifier (
    ) const
    {
        cout << "extracting text features" << endl;
        // do the feature extraction for all the texts
        std::vector<text_sample_type> samples;
        std::vector<unsigned long> labels;
        samples.reserve(contents.size());
        labels.reserve(text_labels.size());
        for (unsigned long i = 0; i < contents.size(); ++i) {
            const std::vector<matrix<float,0,1> >& sent = sentence_to_feats(tfe, contents[i]);
            samples.push_back( extract_combined_features(contents[i], sent) );
            labels.push_back( text_labels[i] );
        }
        randomize_samples(samples, labels);

        cout << "now do training" << endl;
        cout << "num training samples: " << samples.size() << endl;

        svm_multiclass_linear_trainer<sparse_linear_kernel<text_sample_type>,unsigned long> trainer;

        trainer.set_c(300);
        trainer.set_num_threads(num_threads);
        trainer.set_epsilon(0.0001);
        trainer.set_max_iterations(2000);
        //trainer.be_verbose();

        if (count_of_least_common_label(labels) > 1)
        {
            train_text_classifier_objective obj(samples, labels, num_threads, beta, get_all_labels().size(), 2000);

            double C = 300;
            const double min_C = 0.01;
            const double max_C = 5000;
            const double eps = 1;
            try
            {
                find_max_single_variable(obj, C, min_C, max_C, eps, 100, 100);
            }
            catch (optimize_single_variable_failure&)
            {
                // if the optimization ran too long then just use a C of 300
                C = 300;
            }

            cout << "best C: "<< C << endl;
            trainer.set_c(C);
        }

        classifier_type df = trainer.train(samples, labels);
        matrix<double> res = test_multiclass_decision_function(df, samples, labels);
        cout << "test on train: \n" << res << endl;
        cout << "overall accuracy: "<< sum(diag(res))/sum(res) << endl;

        return df;
    }

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

    unsigned long text_categorizer_trainer::
    get_label_id (
        const std::string& str
    )
    {
        std::map<std::string,unsigned long>::iterator i;
        i = label_to_id.find(str);
        if (i != label_to_id.end())
        {
            return i->second;
        }
        else
        {
            const unsigned long next_id = label_to_id.size();
            label_to_id[str] = next_id;
            return next_id;
        }
    }

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

    std::vector<std::string> text_categorizer_trainer::
    get_all_labels(
    ) const
    {
        std::vector<std::string> temp(label_to_id.size());
        for (std::map<std::string,unsigned long>::const_iterator i = label_to_id.begin();
            i != label_to_id.end(); ++i)
        {
            temp[i->second] = i->first;
        }
        return temp;
    }

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
}

max_stars_repo_name: maxmert/nlp-mitie

max_issues_repo_name: maxmert/nlp-mitie

max_forks_repo_name: maxmert/nlp-mitie


text:
// Copyright 2013 Daniel Parker
// Distributed under Boost license
#ifdef __linux__
#define BOOST_TEST_DYN_LINK
#endif

#include <boost/test/unit_test.hpp>
#include <jsoncons/json.hpp>
#include <jsoncons/json_serializer.hpp>
#include <sstream>
#include <vector>
#include <utility>
#include <ctime>

using namespace jsoncons;

BOOST_AUTO_TEST_SUITE(json_array_tests)

BOOST_AUTO_TEST_CASE(test_initializer_list_of_integers)
{
    json arr = json::array{0,1,2,3};
    BOOST_CHECK(arr.is_array());
    BOOST_CHECK(arr.size() == 4);
    for (size_t i = 0; i < arr.size(); ++i)
    {
        BOOST_CHECK_EQUAL(i,arr[i].as<size_t>());
    }
}

BOOST_AUTO_TEST_CASE(test_assignment_to_initializer_list)
{
    json arr = json::array({0,1,2,3});

    arr = json::array{0,1,2,3};
    BOOST_CHECK(arr.is_array());
    BOOST_CHECK(arr.size() == 4);
    for (size_t i = 0; i < arr.size(); ++i)
    {
        BOOST_CHECK_EQUAL(i,arr[i].as<size_t>());
    }
}

BOOST_AUTO_TEST_CASE(test_assignment_to_initializer_list2)
{
    json val;
    val["data"]["id"] = json::array{0,1,2,3,4,5,6,7};
    val["data"]["item"] = json::array{json::array{2},
                                      json::array{4,5,2,3},
                                      json::array{4},
                                      json::array{4,5,2,3},
                                      json::array{2},
                                      json::array{4,5,3},
                                      json::array{2},
                                      json::array{4,3}};

    BOOST_CHECK(val["data"]["item"][0][0] == json(2));
    BOOST_CHECK(val["data"]["item"][1][0] == json(4));
    BOOST_CHECK(val["data"]["item"][2][0] == json(4));
    BOOST_CHECK(val["data"]["item"][3][0] == json(4));
    BOOST_CHECK(val["data"]["item"][4][0] == json(2));
    BOOST_CHECK(val["data"]["item"][5][0] == json(4));
    BOOST_CHECK(val["data"]["item"][6][0] == json(2));
    BOOST_CHECK(val["data"]["item"][7][0] == json(4));
    BOOST_CHECK(val["data"]["item"][7][1] == json(3));
}

BOOST_AUTO_TEST_CASE(test_assignment_to_initializer_list3)
{
    json val;
    val["data"]["id"] = json::array{0,1,2,3,4,5,6,7};
    val["data"]["item"] = json::array{json::object{{"first",1},{"second",2}}};

    json expected_id = json::parse(R"(
[0,1,2,3,4,5,6,7]
    )");

    json expected_item = json::parse(R"(
    [{"first":1,"second":2}]
    )");

    BOOST_CHECK(expected_id == val["data"]["id"]);
    BOOST_CHECK(expected_item == val["data"]["item"]);
}

BOOST_AUTO_TEST_CASE(test_assign_initializer_list_of_object)
{
    json arr = json::array();

    json transaction;
    transaction["Debit"] = 10000;

    arr = json::array{transaction};
    BOOST_CHECK(arr.is_array());
    BOOST_CHECK(arr.size() == 1);
    BOOST_CHECK_EQUAL(arr[0], transaction);
}

BOOST_AUTO_TEST_CASE(test_initializer_list_of_objects)
{
    json book1;
    book1["author"] = "Smith";
    book1["title"] = "Old Bones";

    json book2;
    book2["author"] = "Jones";
    book2["title"] = "New Things";

    json arr = json::array{book1, book2};
    BOOST_CHECK(arr.is_array());
    BOOST_CHECK(arr.size() == 2);

    BOOST_CHECK_EQUAL(book1,arr[0]);
    BOOST_CHECK_EQUAL(book2,arr[1]);
}

BOOST_AUTO_TEST_CASE(test_array_constructor)
{
    json arr = json::array();
    arr.resize(10,10.0);
    BOOST_CHECK(arr.is_array());
    BOOST_CHECK(arr.size() == 10);
    BOOST_CHECK_CLOSE(arr[0].as<double>(), 10.0, 0.0000001);
}

BOOST_AUTO_TEST_CASE(test_make_array)
{
    json arr = json::array();
    BOOST_CHECK(arr.size() == 0);
    arr.resize(10,10.0);
    BOOST_CHECK(arr.is_array());
    BOOST_CHECK(arr.size() == 10);
    BOOST_CHECK_CLOSE(arr[0].as<double>(), 10.0, 0.0000001);

}

BOOST_AUTO_TEST_CASE(test_add_element_to_array)
{
    json arr = json::array();
    BOOST_CHECK(arr.is_array());
    BOOST_CHECK(arr.is<json::array>());
    arr.push_back("Toronto");
    arr.push_back("Vancouver");
    arr.insert(arr.array_range().begin(),"Montreal");

    BOOST_CHECK(arr.size() == 3);

    BOOST_CHECK(arr[0].as<std::string>() == std::string("Montreal"));
    BOOST_CHECK(arr[1].as<std::string>() == std::string("Toronto"));
    BOOST_CHECK(arr[2].as<std::string>() == std::string("Vancouver"));
}

BOOST_AUTO_TEST_CASE(test_emplace_element_to_array)
{
    json a = json::array();
    BOOST_CHECK(a.is_array());
    BOOST_CHECK(a.is<json::array>());
    a.emplace_back("Toronto");
    a.emplace_back("Vancouver");
    a.emplace(a.array_range().begin(),"Montreal");

    BOOST_CHECK(a.size() == 3);

    BOOST_CHECK(a[0].as<std::string>() == std::string("Montreal"));
    BOOST_CHECK(a[1].as<std::string>() == std::string("Toronto"));
    BOOST_CHECK(a[2].as<std::string>() == std::string("Vancouver"));
}

BOOST_AUTO_TEST_CASE(test_array_add_pos)
{
    json arr = json::array();
    BOOST_CHECK(arr.is_array());
    BOOST_CHECK(arr.is<json::array>());
    arr.push_back("Toronto");
    arr.push_back("Vancouver");
    arr.insert(arr.array_range().begin(),"Montreal");

    BOOST_CHECK(arr.size() == 3);

    BOOST_CHECK(arr[0].as<std::string>() == std::string("Montreal"));
    BOOST_CHECK(arr[1].as<std::string>() == std::string("Toronto"));
    BOOST_CHECK(arr[2].as<std::string>() == std::string("Vancouver"));
}

BOOST_AUTO_TEST_CASE(test_array_erase_range)
{
    json arr = json::array();
    BOOST_CHECK(arr.is_array());
    BOOST_CHECK(arr.is<json::array>());
    arr.push_back("Toronto");
    arr.push_back("Vancouver");
    arr.insert(arr.array_range().begin(),"Montreal");

    BOOST_CHECK(arr.size() == 3);

    arr.erase(arr.array_range().begin()+1,arr.array_range().end());

    BOOST_CHECK(arr.size() == 1);
    BOOST_CHECK(arr[0].as<std::string>() == std::string("Montreal"));
}

BOOST_AUTO_TEST_CASE(test_reserve_array_capacity)
{
    json cities = json::array();
    BOOST_CHECK(cities.is_array());
    BOOST_CHECK(cities.is<json::array>());
    cities.reserve(10);  // storage is allocated
    BOOST_CHECK(cities.capacity() == 10);
    BOOST_CHECK(cities.size() == 0);

    cities.push_back("Toronto");
    BOOST_CHECK(cities.is_array());
    BOOST_CHECK(cities.is<json::array>());
    BOOST_CHECK(cities.capacity() == 10);
    BOOST_CHECK(cities.size() == 1);
    cities.push_back("Vancouver");
    cities.insert(cities.array_range().begin(),"Montreal");
    BOOST_CHECK(cities.capacity() == 10);
    BOOST_CHECK(cities.size() == 3);
}

BOOST_AUTO_TEST_CASE(test_one_dim_array)
{
    basic_json<char,sorted_policy,std::allocator<char>> a = basic_json<char,sorted_policy,std::allocator<char>>::make_array<1>(10,0);
    BOOST_CHECK(a.size() == 10);
    BOOST_CHECK(a[0].as_integer() == 0);
    a[1] = 1;
    a[2] = 2;
    BOOST_CHECK(a[1].as_integer() == 1);
    BOOST_CHECK(a[2].as_integer() == 2);
    BOOST_CHECK(a[9].as_integer() == 0);

    BOOST_CHECK(a[1].as<long long>() == 1);
    BOOST_CHECK(a[2].as<long long>() == 2);
    BOOST_CHECK(a[9].as<long long>() == 0);
}

BOOST_AUTO_TEST_CASE(test_two_dim_array)
{
    json a = json::make_array<2>(3,4,0);
    BOOST_CHECK(a.size() == 3);
    a[0][0] = "Tenor";
    a[0][1] = "ATM vol";
    a[0][2] = "25-d-MS";
    a[0][3] = "25-d-RR";
    a[1][0] = "1Y";
    a[1][1] = 0.20;
    a[1][2] = 0.009;
    a[1][3] = -0.006;
    a[2][0] = "2Y";
    a[2][1] = 0.18;
    a[2][2] = 0.009;
    a[2][3] = -0.005;

    BOOST_CHECK_EQUAL(a[0][0].as<std::string>(), std::string("Tenor"));
    BOOST_CHECK_CLOSE(a[2][3].as<double>(), -0.005, 0.00000001);

    BOOST_CHECK_EQUAL(a[0][0].as<std::string>(), std::string("Tenor"));
    BOOST_CHECK_CLOSE(a[2][3].as<double>(), -0.005, 0.00000001);
}

BOOST_AUTO_TEST_CASE(test_three_dim_array)
{
    json a = json::make_array<3>(4,3,2,0);
    BOOST_CHECK(a.size() == 4);
    a[0][2][0] = 2;
    a[0][2][1] = 3;

    BOOST_CHECK(a[0][2][0].as_integer() == 2);
    BOOST_CHECK(a[0][2][1].as_integer() == 3);
    BOOST_CHECK(a[3][2][1].as_integer() == 0);

    BOOST_CHECK(a[0][2][0].as<long long>() == 2);
    BOOST_CHECK(a[0][2][1].as<long long>() == 3);
    BOOST_CHECK(a[3][2][1].as<long long>() == 0);
}

BOOST_AUTO_TEST_CASE(test_assign_vector)
{
    std::vector<std::string> vec;
    vec.push_back("Toronto");
    vec.push_back("Vancouver");
    vec.push_back("Montreal");

    json val;
    val = vec;

    BOOST_CHECK(val.size() == 3);
    BOOST_CHECK_EQUAL(val[0].as<std::string>(), std::string("Toronto"));
    BOOST_CHECK_EQUAL(val[1].as<std::string>(), std::string("Vancouver"));
    BOOST_CHECK_EQUAL(val[2].as<std::string>(), std::string("Montreal"));

}

BOOST_AUTO_TEST_CASE(test_assign_vector_of_bool)
{
    std::vector<bool> vec;
    vec.push_back(true);
    vec.push_back(false);
    vec.push_back(true);

    json val;
    val = vec;

    BOOST_CHECK(val.size() == 3);
    BOOST_CHECK_EQUAL(val[0].as<bool>(), true);
    BOOST_CHECK_EQUAL(val[1].as<bool>(), false);
    BOOST_CHECK_EQUAL(val[2].as<bool>(), true);

}

BOOST_AUTO_TEST_CASE(test_add_null)
{
    json a = json::array();
    a.push_back(jsoncons::null_type());
    a.push_back(json::null());
    BOOST_CHECK(a[0].is_null());
    BOOST_CHECK(a[1].is_null());
}

BOOST_AUTO_TEST_CASE(test_from_container)
{
    std::vector<int> vec;
    vec.push_back(10);
    vec.push_back(20);
    vec.push_back(30);

    json val1 = vec;
    BOOST_REQUIRE(vec.size() == 3);
    BOOST_CHECK(vec[0] == 10);
    BOOST_CHECK(vec[1] == 20);
    BOOST_CHECK(vec[2] == 30);

    std::list<double> list;
    list.push_back(10.5);
    list.push_back(20.5);
    list.push_back(30.5);

    json val2 = list;
    BOOST_REQUIRE(val2.size() == 3);
    BOOST_CHECK_CLOSE(val2[0].as<double>(),10.5,0.000001);
    BOOST_CHECK_CLOSE(val2[1].as<double>(),20.5,0.000001);
    BOOST_CHECK_CLOSE(val2[2].as<double>(),30.5,0.000001);
}

BOOST_AUTO_TEST_SUITE_END()

ext: cpp


text:
/*
 * This file is part of the DUDS project. It is subject to the BSD-style
 * license terms in the LICENSE file found in the top-level directory of this
 * distribution and at http://www.somewhere.org/somepath/license.html.
 * No part of DUDS, including this file, may be copied, modified, propagated,
 * or distributed except according to the terms contained in the LICENSE file.
 *
 * Copyright (C) 2020  Jeff Jackowski
 */
/**
 * @file
 * A sample demonstrating rendering text using bit-per-pixel graphics and
 * outputting the result to the console. Used to assist debugging some
 * unexpected text rendering results.
 */

#include <duds/hardware/devices/displays/SimulatedBppDisplay.hpp>
#include <duds/hardware/devices/displays/ST7920.hpp>
#include <duds/hardware/interface/linux/GpioDevPort.hpp>
#include <duds/hardware/interface/PinConfiguration.hpp>
#include <boost/property_tree/info_parser.hpp>
#include <duds/ui/graphics/BppImageArchive.hpp>
#include <duds/ui/graphics/BppStringCache.hpp>
#include <iostream>
#include <assert.h>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/program_options.hpp>

bool quit = false;

//namespace display = duds::hardware::display;

int main(int argc, char *argv[])
try {
	std::string fontpath, confpath, lcdname;
	std::string imgpath(argv[0]);
	int dispW, dispH;
	bool uselcd = false;
	{
		int found = 0;
		while (!imgpath.empty() && (found < 3)) {
			imgpath.pop_back();
			if (imgpath.back() == '/') {
				++found;
			}
		}
		imgpath += "images/";
	}
	{ // option parsing
		boost::program_options::options_description optdesc(
			"Options for bit-per-pxiel text rendering test"
		);
		optdesc.add_options()
			( // help info
				"help,h",
				"Show this help message"
			)
			(
				"font",
				boost::program_options::value<std::string>(&fontpath)->
					default_value(imgpath + "font_8x16.bppia"),
				"Font file"
			)
			(
				"st7920",
				"Use a graphic ST7920 LCD instead of console output"
			)
			(
				"conf,c",
				boost::program_options::value<std::string>(&confpath)->
					default_value("samples/pins.conf"),
				"Pin configuration file; required if ST7920 LCD used"
			)
			(
				"lcdname",
				boost::program_options::value<std::string>(&lcdname)->
					default_value("lcdGraphic"),
				"Name of LCD inside pin configuration"
			)
			( // the display width
				"width,x",
				boost::program_options::value<int>(&dispW)->
					default_value(144),
				"ST7920 display width in pixels"
			)
			( // the display height
				"height,y",
				boost::program_options::value<int>(&dispH)->
					default_value(32),
				"ST7920 display height in pixels"
			)
		;
		boost::program_options::variables_map vm;
		boost::program_options::store(
			boost::program_options::parse_command_line(argc, argv, optdesc),
			vm
		);
		boost::program_options::notify(vm);
		if (vm.count("help")) {
			std::cout << "Bit-per-pxiel text rendering test\nOnce running, input "
			"text to render in stdin and press enter to render the text.\n"
			"Enter a blank line to quit.\n\t" << argv[0] << " [options]\n" <<
			optdesc << std::endl;
			return 0;
		}
		if (vm.count("st7920")) {
			uselcd = true;
		}
	}

	// load font
	duds::ui::graphics::BppFontSptr font =
		std::make_shared<duds::ui::graphics::BppFont>();
	font->load(fontpath);
	duds::ui::graphics::BppStringCache bsc(font);

	duds::ui::graphics::ImageDimensions cdim = font->estimatedMaxCharacterSize();
	std::cout << "Estimated character size is " << cdim << std::endl;

	std::shared_ptr<duds::hardware::devices::displays::ST7920> lcd;
	duds::hardware::devices::displays::SimulatedBppDisplay sd;
	// display configuration
	duds::hardware::interface::PinConfiguration pc;
	std::shared_ptr<duds::hardware::interface::DigitalPort> port;
	// ST7920
	if (uselcd) {
		boost::property_tree::ptree tree;
		boost::property_tree::read_info(confpath, tree);
		// if an exception is thrown here, the program will terminate without
		// getting to the catch block below; don't know why
		pc.parse(tree.get_child("pins"));
		port = duds::hardware::interface::linux::GpioDevPort::makeConfiguredPort(pc);
		duds::hardware::interface::DigitalPinSet lcdset;
		duds::hardware::interface::ChipSelect lcdsel;
		pc.getPinSetAndSelect(lcdset, lcdsel, lcdname);
		lcd = std::make_shared<duds::hardware::devices::displays::ST7920>(
			std::move(lcdset), std::move(lcdsel), dispW, dispH
			);
		lcd->initialize();
	}

	char inbuf[256] = { 0 };
	do {
		std::cin.getline(inbuf, 255);
		if (std::cin.good() && inbuf[0]) {
			std::cout << "Rendering \"" << inbuf << "\"";
			// render the text
			duds::ui::graphics::ConstBppImageSptr label = bsc.text(inbuf);
			std::cout << ", size " << label->width() << 'x' << label->height() <<
			std::endl;
			assert(label->dimensions() == font->lineDimensions(inbuf));
			if (uselcd) {
				const duds::ui::graphics::ImageDimensions &dim = lcd->dimensions();
				duds::ui::graphics::BppImage frame(dim);
				frame.clearImage();
				duds::ui::graphics::ImageLocation loc(
					std::max((dim.w - label->width()) / 2, 0),
					std::max((dim.h - label->height()) / 2, 0)
				);
				frame.write(label, loc);
				lcd->write(&frame);
			} else {
				sd.configure(label->dimensions());
				sd.write(label);
			}
		}
	} while (std::cin.good() && inbuf[0]);

} catch (...) {
	std::cerr << "Test failed in main():\n" <<
	boost::current_exception_diagnostic_information() << std::endl;
	return 1;
}

max_stars_repo_name: jjackowski/duds

max_issues_repo_name: jjackowski/duds

max_forks_repo_name: jjackowski/duds


text:
#include <common/net/message/nodes/RefreshCapacityPoolsMsg.h>
#include <common/net/message/nodes/SetTargetConsistencyStatesMsg.h>
#include <common/net/message/nodes/SetTargetConsistencyStatesRespMsg.h>
#include <common/storage/Storagedata.h>
#include <common/threading/RWLockGuard.h>
#include <common/toolkit/StorageTk.h>
#include <common/toolkit/StringTk.h>
#include <common/toolkit/ZipIterator.h>
#include <program/Program.h>
#include <toolkit/StorageTkEx.h>
#include "StorageTargets.h"

#include <boost/lexical_cast.hpp>

#define STORAGETARGETS_TARGETDIR_MKDIR_MODE (S_IRWXU)
#define STORAGETARGETS_CHUNKDIR_MKDIR_MODE (S_IRWXU | S_IRWXG | S_IRWXO)

#define BUDDY_NEEDS_RESYNC_FILENAME        ".buddyneedsresync"
#define LAST_BUDDY_COMM_TIMESTAMP_FILENAME ".lastbuddycomm"

StorageTarget::StorageTarget(Path path, uint16_t targetID, TimerQueue& timerQueue,
      NodeStoreServers& mgmtNodes, MirrorBuddyGroupMapper& buddyGroupMapper):
   path(std::move(path)), id(targetID),
   buddyNeedsResyncFile((this->path / BUDDY_NEEDS_RESYNC_FILENAME).str(), S_IRUSR | S_IWUSR),
   lastBuddyCommFile((this->path / LAST_BUDDY_COMM_TIMESTAMP_FILENAME).str(), S_IRUSR | S_IWUSR),
   timerQueue(timerQueue), mgmtNodes(mgmtNodes),
   buddyGroupMapper(buddyGroupMapper), buddyResyncInProgress(false),
   consistencyState(TargetConsistencyState_GOOD), cleanShutdown(false)
{
   const auto chunkPath = this->path / CONFIG_CHUNK_SUBDIR_NAME;
   chunkFD = FDHandle(open(chunkPath.str().c_str(), O_RDONLY | O_DIRECTORY));
   if (!chunkFD.valid())
      throw std::system_error(errno, std::system_category(), chunkPath.str());

   // mirror chunks path

   const auto mirrorPath = this->path / CONFIG_BUDDYMIRROR_SUBDIR_NAME;
   mirrorFD = FDHandle(open(mirrorPath.str().c_str(), O_RDONLY | O_DIRECTORY));
   if (!mirrorFD.valid())
      throw std::system_error(errno, std::system_category(), mirrorPath.str());

   quotaBlockDevice = QuotaBlockDevice::getBlockDeviceOfTarget(this->path.str(), targetID);

   if (buddyNeedsResyncFile.read().get_value_or(0) & BUDDY_RESYNC_UNACKED_FLAG)
   {
      setBuddyNeedsResyncEntry = timerQueue.enqueue(std::chrono::seconds(0), [this] {
         retrySetBuddyNeedsResyncComm();
      });
   }
}

void StorageTarget::prepareTargetDir(const Path& path)
{
   mode_t targetMkdirMode = STORAGETARGETS_TARGETDIR_MKDIR_MODE;
   mode_t chunkMkDirMode  = STORAGETARGETS_CHUNKDIR_MKDIR_MODE;

   if (!StorageTk::createPathOnDisk(path, false, &targetMkdirMode))
      throw InvalidConfigException("Unable to create storage directory: " + path.str());

   // storage format file
   if (!StorageTk::createStorageFormatFile(path.str(), STORAGETK_FORMAT_CURRENT_VERSION))
      throw InvalidConfigException("Unable to create storage format file in: " + path.str());

   StorageTk::loadAndUpdateStorageFormatFile(path.str(), STORAGETK_FORMAT_MIN_VERSION,
      STORAGETK_FORMAT_CURRENT_VERSION);

   // chunks directory
   Path chunksPath = path / CONFIG_CHUNK_SUBDIR_NAME;

   if (!StorageTk::createPathOnDisk(chunksPath, false, &chunkMkDirMode))
      throw InvalidConfigException("Unable to create chunks directory: " + chunksPath.str());

   // buddy mirror directory
   Path mirrorPath = path / CONFIG_BUDDYMIRROR_SUBDIR_NAME;
   if (!StorageTk::createPathOnDisk(mirrorPath, false, &chunkMkDirMode))
      throw InvalidConfigException("Unable to create buddy mirror directory: " + mirrorPath.str());
}

bool StorageTarget::isTargetDir(const Path& path)
{
   return StorageTk::checkStorageFormatFileExists(path.str());
}

void StorageTarget::setBuddyNeedsResync(bool needsResync)
{
   const RWLockGuard lock(rwlock, SafeRWLock_WRITE);

   const auto oldState = buddyNeedsResyncFile.read().get_value_or(BUDDY_RESYNC_NOT_REQUIRED);
   const auto newState = needsResync
      ? BUDDY_RESYNC_REQUIRED_UNACKED
      : BUDDY_RESYNC_NOT_REQUIRED_UNACKED;

   // if the change has already been requested by some other thread, we should not request it
   // again - even if the change is unacked, as retrying immediately after a failed communication
   // attempt is not likely to be successful, we must handle externally started resyncs however,
   // which *do not* change the buddyneedsresync file contents but *do* use this mechanism to
   // communicate that a resync has finished and the buddy is good again - these only use us to
   // set the buddy to "needs no resync" though, so we can still skip setting needs-resync when that
   // is already pending.
   if (needsResync
         && (oldState & BUDDY_RESYNC_REQUIRED_FLAG) == (newState & BUDDY_RESYNC_REQUIRED_FLAG))
      return;

   // cancel any pending retries, we will send a message to mgmt anyway.
   if (setBuddyNeedsResyncEntry)
      setBuddyNeedsResyncEntry->cancel();

   buddyNeedsResyncFile.write(newState);

   if (!setBuddyNeedsResyncComm())
      LOG(GENERAL, CRITICAL, "Could not reach mgmt for state update, will retry.",
            ("primary target", id), ("buddyNeedsResync", needsResync));
}

bool StorageTarget::setBuddyNeedsResyncComm()
{
   // this is a timer callback. as such we must be prepared to deal with the fact that we were
   // cancelled *after* we were dequeued and started executing, but were blocked on the lock in
   // retrySetBuddyNeedsResyncComm. always reading the current state and sending that fixes this:
   // if the state is not unacked we can return without doing anything, and if it is nobody can
   // change it while we are using it.
   const auto state = buddyNeedsResyncFile.read().get_value_or(BUDDY_RESYNC_NOT_REQUIRED);
   const bool needsResync = state & BUDDY_RESYNC_REQUIRED_FLAG;

   if (!(state & BUDDY_RESYNC_UNACKED_FLAG))
      return true;

   const TargetConsistencyState stateToSet = needsResync
      ? TargetConsistencyState_NEEDS_RESYNC
      : TargetConsistencyState_GOOD;

   bool currentIsPrimary;
   const uint16_t buddyTargetID = buddyGroupMapper.getBuddyTargetID(id, &currentIsPrimary);

   // until mgmt handles resync decision, refuse to set a primary to needs-resync locally.
   if (!currentIsPrimary)
      return true;

   UInt16List targetIDList(1, buddyTargetID);
   UInt8List stateList(1, stateToSet);

   SetTargetConsistencyStatesMsg msg(NODETYPE_Storage, &targetIDList, &stateList, false);

   const auto respMsg = MessagingTk::requestResponse(*mgmtNodes.referenceFirstNode(), msg,
         NETMSGTYPE_SetTargetConsistencyStatesResp);

   if (!respMsg)
   {
      setBuddyNeedsResyncEntry = timerQueue.enqueue(std::chrono::seconds(5), [this] {
         retrySetBuddyNeedsResyncComm();
      });
      return false;
   }

   auto* respMsgCast = (SetTargetConsistencyStatesRespMsg*)respMsg.get();

   if (respMsgCast->getValue() != FhgfsOpsErr_SUCCESS)
   {
      LOG(GENERAL, CRITICAL, "Management node did not accept target states.", buddyTargetID,
            needsResync);
      return true;
   }

   buddyNeedsResyncFile.write(state & ~BUDDY_RESYNC_UNACKED_FLAG);
   if (state & BUDDY_RESYNC_REQUIRED_FLAG)
      LOG(GENERAL, CRITICAL, "Marked secondary buddy for needed resync.", ("primary target", id));
   return true;
}

void StorageTarget::handleTargetStateChange()
{
   const auto newState = getConsistencyState();

   LOG(GENERAL, DEBUG, "Notifying management node of target state change.", id, newState);

   if (getOfflineTimeout())
      Program::getApp()->getInternodeSyncer()->publishTargetState(id, newState);
}

/**
 * Decide whether a resync is needed for any of the storage targets, and set its targetState to
 * TargetState_RESYNCING if so.
 */
void StorageTargets::decideResync(const TargetStateMap& statesFromMgmtd,
   TargetStateMap& outLocalStateChanges)
{
   const char* logContext = "Decide resync";

   App* app = Program::getApp();
   MirrorBuddyGroupMapper* mirrorBuddyGroupMapper = app->getMirrorBuddyGroupMapper();

   std::map<uint16_t, uint16_t> targetBuddyGroupMap;
   {
      MirrorBuddyGroupMap groupMap;
      mirrorBuddyGroupMapper->getMirrorBuddyGroups(groupMap);

      for (const auto& group : groupMap)
      {
         targetBuddyGroupMap[group.second.firstTargetID] = group.first;
         targetBuddyGroupMap[group.second.secondTargetID] = group.first;
      }
   }

   // Make a map of targetID->Iterator on statesFromMgmtd containing only the local target
   // to make lookup under lock quicker.
   typedef std::map<uint16_t, TargetStateMapCIter> TargetStateIterMap;
   TargetStateIterMap stateFromMgmtdIterMap;
   // First we make a list of local target IDs (so later, when we iterate over all local states
   // in the "main loop" holding a read lock, we don't have to look them up in the (potentially
   // big) statesFromMgmtd, only in the smaller stateFromMgmtdIterMap.
   UInt16List localTargetIDs;
   {
      for (StorageTargetMapCIter localTargetIt = this->storageTargetMap.begin();
           localTargetIt != this->storageTargetMap.end(); ++localTargetIt)
         localTargetIDs.push_back(localTargetIt->first);
   }

   // Fill the map (only operating on local data structures -> no lock needed).
   for (UInt16ListConstIter localTargetIDIt = localTargetIDs.begin();
        localTargetIDIt != localTargetIDs.end(); ++localTargetIDIt)
   {
      const uint16_t targetID = *localTargetIDIt;

      TargetStateMapCIter targetStateMapIter = statesFromMgmtd.find(targetID);
      if  (targetStateMapIter == statesFromMgmtd.end() )
      {
         LOG_DEBUG(logContext, Log_DEBUG, "Local target " + StringTk::uintToStr(targetID) +
            " not found in management node state report.");
         continue;
      }

      stateFromMgmtdIterMap.insert(std::pair<uint16_t, TargetStateMapCIter>(
         targetID, targetStateMapIter) );
   }

   // Now we can iterate over the storageTargetMap and do the actual resync decision.
   for (auto storageTargetIt = this->storageTargetMap.begin();
        storageTargetIt != this->storageTargetMap.end(); ++storageTargetIt)
   {
      uint16_t targetID = storageTargetIt->first;
      StorageTarget& targetData = *storageTargetIt->second;

      TargetStateIterMap::const_iterator newStateFromMgmtdIt = stateFromMgmtdIterMap.find(targetID);
      if (newStateFromMgmtdIt == stateFromMgmtdIterMap.end() )
         continue; // Don't need to log - has been logged above.

      // Note: This still references the state stored in the inOutStatesFromMgmtd map.
      const CombinedTargetState& newStateFromMgmtd = newStateFromMgmtdIt->second->second;

      MirrorBuddyState buddyState = BuddyState_UNMAPPED;

      {
         const auto bgIDIter = targetBuddyGroupMap.find(targetID);

         if (bgIDIter != targetBuddyGroupMap.end())
            buddyState = mirrorBuddyGroupMapper->getBuddyState(targetID, bgIDIter->second);
      }

      if (buddyState == BuddyState_UNMAPPED) // Unmapped targets can never be resyncing.
      {
         LOG_DBG(STATES, DEBUG,
               "Setting target to state good because it is not part of a mirror group.",
               ("oldState", TargetStateStore::stateToStr(targetData.getConsistencyState())),
               targetID);

         targetData.setConsistencyState(TargetConsistencyState_GOOD);

         outLocalStateChanges.insert(TargetStateMapVal(targetID,
            CombinedTargetState(TargetReachabilityState_ONLINE, TargetConsistencyState_GOOD) ) );

         // Setting the cleanShutdown flag has two purposes here:
         // * An unmapped target does not have a buddy to resync from, therefore even if it's not
         //   clean nothing can be done about it.
         // * A newly created target has to be marked as "clean" before it can join any mirror buddy
         //   group.
         targetData.setCleanShutdown(true);

         continue;
      }

      // BAD targets will stay BAD unless server is restarted.
      if (targetData.getConsistencyState() == TargetConsistencyState_BAD)
         continue;

      const TargetConsistencyState oldState = targetData.getConsistencyState();

      const bool isResyncing =
         newStateFromMgmtd.consistencyState == TargetConsistencyState_NEEDS_RESYNC;
      const bool isBad = newStateFromMgmtd.consistencyState == TargetConsistencyState_BAD;
      const bool isClean = targetData.getCleanShutdown();

      // cleanShutdown should only be handled once at startup, so it is reset here after its value
      // has been copied.
      targetData.setCleanShutdown(true);

      if (storageTargetIt->second->getOfflineTimeout())
      {
         // Targets with a waiting-for-offline timeout will always be NEEDS_RESYNC.
         targetData.setConsistencyState(TargetConsistencyState_NEEDS_RESYNC);
         outLocalStateChanges.insert(TargetStateMapVal(targetID, CombinedTargetState(
            TargetReachabilityState_ONLINE, TargetConsistencyState_NEEDS_RESYNC) ) );
      }
      else
      if (oldState == TargetConsistencyState_NEEDS_RESYNC)
      {
         // If our local state is already RESYNCING, this state can only be left
         // when our primary tells us the resync is finished.
         targetData.setConsistencyState(TargetConsistencyState_NEEDS_RESYNC);
         outLocalStateChanges.insert(TargetStateMapVal(targetID, CombinedTargetState(
            TargetReachabilityState_ONLINE, TargetConsistencyState_NEEDS_RESYNC) ) );
      }
      else
      if(!isClean || isResyncing || isBad )
      {
         // This condition implements the following decision graph:
         // RESYNC? ->o                                    ,-->o-->(clean shutdown)--> NO
         //           |\                 ,->(!resyncing)--'     `-(dirty)--.
         //           \ `-------------->o->(resyncing)---------------------,`---> YES
         //            `------->(bad)-------------------------------------'

         targetData.setConsistencyState(TargetConsistencyState_NEEDS_RESYNC);
         outLocalStateChanges.insert(TargetStateMapVal(targetID, CombinedTargetState(
            TargetReachabilityState_ONLINE, TargetConsistencyState_NEEDS_RESYNC) ) );
      }
      else
      {
         // If mgmtd reports the target is (P)OFFLINE, then the storage server knows better and we
         // set the target to GOOD / ONLINE. Otherwise we accept the state reported by the mgmtd.
         if( (newStateFromMgmtd.reachabilityState == TargetReachabilityState_OFFLINE)
            || (newStateFromMgmtd.reachabilityState == TargetReachabilityState_POFFLINE) )
         {
            targetData.setConsistencyState(TargetConsistencyState_GOOD);
            outLocalStateChanges.insert(TargetStateMapVal(targetID, CombinedTargetState(
               TargetReachabilityState_ONLINE, TargetConsistencyState_GOOD) ) );

         }
         else
         {
            targetData.setConsistencyState(newStateFromMgmtd.consistencyState);
            outLocalStateChanges.insert(TargetStateMapVal(targetID, CombinedTargetState(
               TargetReachabilityState_ONLINE, newStateFromMgmtd.consistencyState) ) );
         }
      }

      if ( targetData.getConsistencyState() != oldState
        || targetData.getConsistencyState() != newStateFromMgmtd.consistencyState
        || newStateFromMgmtd.reachabilityState != TargetReachabilityState_ONLINE)
      {
         LOG_DEBUG(logContext, Log_DEBUG, "Target " + StringTk::uintToStr(targetID)
            + "; State (from management node): " + TargetStateStore::stateToStr(newStateFromMgmtd)
            + "; resyncing: " + (isResyncing ? "yes" : "no")
            + "; clean: " + (isClean ? "yes" : "no")
            + "; bad: " + (isBad ? "yes" : "no") + "."
         );

         LogContext(logContext).log(Log_NOTICE, "Target " + StringTk::uintToStr(targetID)
            + ": Setting new target state: "
            + TargetStateStore::stateToStr(targetData.getConsistencyState())
            + " (old state: " + TargetStateStore::stateToStr(oldState) + ")" );
      }
   }
}

/**
 * Checks all local primary buddies whether there is a buddyneedsresync file, and if so, sets the
 * buddy's consistency state on the mgmtd to NEEDS_RESYNC. Afterwards, checks the all the target
 * state of the secondary buddies belonging to local primaries: if any secondary is ONLINE and
 * NEEDS_RESYNC, a ResyncJob is started.
 */
void StorageTargets::checkBuddyNeedsResync()
{
   const char* logContext = "Check buddy needs resync";
   App* app = Program::getApp();
   MirrorBuddyGroupMapper* mirrorBuddyGroupMapper = app->getMirrorBuddyGroupMapper();
   TargetStateStore* targetStateStore = app->getTargetStateStore();
   BuddyResyncer* buddyResyncer = app->getBuddyResyncer();

   // For targets where primary is on this storage server:
   // Maps targetID->targetPath.
   std::map<uint16_t, Path> targetPathMap;
   // Maps primary->secondary. (Note: Not the same as TargetBuddyGroupMap, which maps target->group)
   typedef std::map<uint16_t, uint16_t> BuddyGroupMap;
   typedef BuddyGroupMap::const_iterator BuddyGroupMapCIter;
   typedef BuddyGroupMap::value_type BuddyGroupMapVal;
   BuddyGroupMap buddyGroupMap;

   {
      for (auto targetDataIt = this->storageTargetMap.begin();
            targetDataIt != this->storageTargetMap.end(); ++targetDataIt)
      {
         uint16_t targetID = targetDataIt->first;

         targetPathMap.insert({targetID, targetDataIt->second->getPath()});

         bool isPrimary;
         uint16_t buddyTargetID = mirrorBuddyGroupMapper->getBuddyTargetID(targetID, &isPrimary);

         if (isPrimary)
            buddyGroupMap.insert(BuddyGroupMapVal(targetID, buddyTargetID) );
      }

   }

   // Now, check all the primary targets for the existence of a buddyneedsresync file.
   for (const auto& targetPath : targetPathMap)
   {
      const uint16_t targetID = targetPath.first;

      bool isPrimary;
      const uint16_t buddyTargetID = mirrorBuddyGroupMapper->getBuddyTargetID(targetID, &isPrimary);

      if (!isPrimary)
         continue;

      const bool buddyNeedsResync = storageTargetMap.at(targetID)->getBuddyNeedsResync();

      if (buddyNeedsResync)
      {
         LOG_DEBUG(logContext, Log_DEBUG, "buddyneedsresync indication found for target "
            + StringTk::uintToStr(targetID) );

         CombinedTargetState state = CombinedTargetState(TargetReachabilityState_ONLINE,
            TargetConsistencyState_NEEDS_RESYNC);
         targetStateStore->getState(buddyTargetID, state);

         // Only send message if buddy was still reported as GOOD before (otherwise the mgmtd
         // already knows it needs a resync, or it's BAD and shouldn't be resynced anyway.
         if (state.consistencyState == TargetConsistencyState_GOOD)
         {
            storageTargetMap.at(targetID)->setBuddyNeedsResync(true);

            LogContext(logContext).log(Log_NOTICE, "Set needs-resync state for buddy target "
               + StringTk::uintToStr(buddyTargetID) );
         }
      }
   }

   // And check all secondary targets whether they are in NEEDS_RESYNC state.
   for (BuddyGroupMapCIter buddyGroupIter = buddyGroupMap.begin();
        buddyGroupIter != buddyGroupMap.end(); ++buddyGroupIter)
   {
      const uint16_t targetID = buddyGroupIter->first;
      const uint16_t buddyTargetID = buddyGroupIter->second;

      const auto targetConsistencyState = storageTargetMap.at(targetID)->getConsistencyState();

      // If primary is not GOOD, don't start a resync (wait until InternodeSyncer sets the primary
      // to GOOD again).
      if (targetConsistencyState != TargetConsistencyState_GOOD)
      {
         LOG_DEBUG(logContext, Log_DEBUG, "Target state is not good, won't check buddy target state"
            "; target ID " + StringTk::uintToStr(targetID) );
         continue;
      }

      CombinedTargetState buddyTargetState;
      if (!targetStateStore->getState(buddyTargetID, buddyTargetState) )
      {
         LOG_DEBUG(logContext, Log_DEBUG, "Buddy target state invalid for target ID "
            + StringTk::uintToStr(buddyTargetID) );
         continue;
      }

      if (buddyTargetState ==
          CombinedTargetState(TargetReachabilityState_ONLINE, TargetConsistencyState_NEEDS_RESYNC) )
      {
         FhgfsOpsErr resyncRes = buddyResyncer->startResync(targetID);

         if (resyncRes == FhgfsOpsErr_SUCCESS)
         {
            LogContext(logContext).log(Log_WARNING, "Target: " + StringTk::uintToStr(targetID)
               + " start buddy resync job.");
         }
         else
         {
            LOG_DEBUG(logContext, Log_DEBUG, "Target: " + StringTk::uintToStr(targetID)
               + " start buddy resync job failed ("
               + boost::lexical_cast<std::string>(resyncRes) + ")");
         }
      }
   }
}

void StorageTargets::generateTargetInfoList(StorageTargetInfoList& outTargetInfoList)
{
   for (const auto& mapping : storageTargetMap)
   {
      uint16_t targetID = mapping.first;
      const auto& target = mapping.second;
      std::string targetPathStr;
      int64_t sizeTotal = 0;
      int64_t sizeFree = 0;
      int64_t inodesTotal = 0;
      int64_t inodesFree = 0;
      TargetConsistencyState targetState = TargetConsistencyState_BAD;

      targetPathStr = target->getPath().str();

      getStatInfo(targetPathStr, &sizeTotal, &sizeFree, &inodesTotal, &inodesFree);

      targetState = target->getConsistencyState();

      StorageTargetInfo targetInfo(targetID, targetPathStr, sizeTotal, sizeFree, inodesTotal,
         inodesFree, targetState);
      outTargetInfoList.push_back(targetInfo);
   }

}

/**
 * note: sets "-1" for all out-values if statfs failed.
 */
void StorageTargets::getStatInfo(std::string& targetPathStr, int64_t* outSizeTotal,
   int64_t* outSizeFree, int64_t* outInodesTotal, int64_t* outInodesFree)
{
   const char* logContext = "Get storage target info";

   bool statSuccess = StorageTk::statStoragePath(targetPathStr, outSizeTotal, outSizeFree,
      outInodesTotal, outInodesFree);

   if(unlikely(!statSuccess) )
   { // error
      LogContext(logContext).logErr("Unable to statfs() storage path: " + targetPathStr +
         " (SysErr: " + System::getErrString() );

      *outSizeTotal = -1;
      *outSizeFree = -1;
      *outInodesTotal = -1;
      *outInodesFree = -1;
   }

   // read and use value from manual free space override file (if it exists)
   StorageTk::statStoragePathOverride(targetPathStr, outSizeFree, outInodesFree);
}

/**
 * Fill a storageTargetMap with the contents of the three lists passed.
 * targetIDs, reachabilityStates and consistencyStates is interpreted as a 1:1 mapping.
 */
void StorageTargets::fillTargetStateMap(const UInt16List& targetIDs,
   const UInt8List& reachabilityStates, const UInt8List& consistencyStates,
   TargetStateMap& outStateMap)
{
   for (ZipConstIterRange<UInt16List, UInt8List, UInt8List>
        iter(targetIDs, reachabilityStates, consistencyStates);
        !iter.empty(); ++iter)
   {
      outStateMap.insert(TargetStateMapVal(*iter()->first, CombinedTargetState(
            static_cast<TargetReachabilityState>(*iter()->second),
            static_cast<TargetConsistencyState>(*iter()->third)
         ) ) );
   }
}

max_stars_repo_name: TomatoYoung/beegfs

max_issues_repo_name: TomatoYoung/beegfs

max_forks_repo_name: TomatoYoung/beegfs


text: #include <boost/fusion/functional/adapter/fused.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////

#ifndef BOOST_INTERPROCESS_POSIX_CONDITION_HPP
#define BOOST_INTERPROCESS_POSIX_CONDITION_HPP

#if (defined _MSC_VER) && (_MSC_VER >= 1200)
#  pragma once
#endif

#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/detail/workaround.hpp>

#include <pthread.h>
#include <errno.h>
#include <boost/interprocess/sync/posix/pthread_helpers.hpp>
#include <boost/interprocess/sync/posix/ptime_to_timespec.hpp>
#include <boost/interprocess/detail/posix_time_types_wrk.hpp>
#include <boost/interprocess/sync/posix/mutex.hpp>
#include <boost/assert.hpp>

namespace boost {
namespace interprocess {
namespace ipcdetail {

class posix_condition
{
   //Non-copyable
   posix_condition(const posix_condition &);
   posix_condition &operator=(const posix_condition &);

   public:
   //!Constructs a posix_condition. On error throws interprocess_exception.
   posix_condition();

   //!Destroys *this
   //!liberating system resources.
   ~posix_condition();

   //!If there is a thread waiting on *this, change that
   //!thread's state to ready. Otherwise there is no effect.
   void notify_one();

   //!Change the state of all threads waiting on *this to ready.
   //!If there are no waiting threads, notify_all() has no effect.
   void notify_all();

   //!Releases the lock on the posix_mutex object associated with lock, blocks
   //!the current thread of execution until readied by a call to
   //!this->notify_one() or this->notify_all(), and then reacquires the lock.
   template <typename L>
   void wait(L& lock)
   {
      if (!lock)
         throw lock_exception();
      this->do_wait(*lock.mutex());
   }

   //!The same as:
   //!while (!pred()) wait(lock)
   template <typename L, typename Pr>
   void wait(L& lock, Pr pred)
   {
      if (!lock)
         throw lock_exception();

      while (!pred())
         this->do_wait(*lock.mutex());
   }

   //!Releases the lock on the posix_mutex object associated with lock, blocks
   //!the current thread of execution until readied by a call to
   //!this->notify_one() or this->notify_all(), or until time abs_time is reached,
   //!and then reacquires the lock.
   //!Returns: false if time abs_time is reached, otherwise true.
   template <typename L>
   bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time)
   {
      if(abs_time == boost::posix_time::pos_infin){
         this->wait(lock);
         return true;
      }
      if (!lock)
            throw lock_exception();
      return this->do_timed_wait(abs_time, *lock.mutex());
   }

   //!The same as:   while (!pred()) {
   //!                  if (!timed_wait(lock, abs_time)) return pred();
   //!               } return true;
   template <typename L, typename Pr>
   bool timed_wait(L& lock, const boost::posix_time::ptime &abs_time, Pr pred)
   {
      if(abs_time == boost::posix_time::pos_infin){
         this->wait(lock, pred);
         return true;
      }
      if (!lock)
            throw lock_exception();
      while (!pred()){
         if (!this->do_timed_wait(abs_time, *lock.mutex()))
            return pred();
      }

      return true;
   }

   void do_wait(posix_mutex &mut);

   bool do_timed_wait(const boost::posix_time::ptime &abs_time, posix_mutex &mut);

   private:
   pthread_cond_t   m_condition;
};

inline posix_condition::posix_condition()
{
   int res;
   pthread_condattr_t cond_attr;
   res = pthread_condattr_init(&cond_attr);
   if(res != 0){
      throw interprocess_exception("pthread_condattr_init failed");
   }
   res = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
   if(res != 0){
      pthread_condattr_destroy(&cond_attr);
      throw interprocess_exception(res);
   }
   res = pthread_cond_init(&m_condition, &cond_attr);
   pthread_condattr_destroy(&cond_attr);
   if(res != 0){
      throw interprocess_exception(res);
   }
}

inline posix_condition::~posix_condition()
{
    int res = 0;
    res = pthread_cond_destroy(&m_condition);
    BOOST_ASSERT(res == 0); (void)res;
}

inline void posix_condition::notify_one()
{
    int res = 0;
    res = pthread_cond_signal(&m_condition);
    BOOST_ASSERT(res == 0); (void)res;
}

inline void posix_condition::notify_all()
{
    int res = 0;
    res = pthread_cond_broadcast(&m_condition);
    BOOST_ASSERT(res == 0); (void)res;
}

inline void posix_condition::do_wait(posix_mutex &mut)
{
   pthread_mutex_t* pmutex = &mut.m_mut;
   int res = 0;
   res = pthread_cond_wait(&m_condition, pmutex);
   BOOST_ASSERT(res == 0); (void)res;
}

inline bool posix_condition::do_timed_wait
   (const boost::posix_time::ptime &abs_time, posix_mutex &mut)
{
   timespec ts = ptime_to_timespec(abs_time);
   pthread_mutex_t* pmutex = &mut.m_mut;
   int res = 0;
   res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
   BOOST_ASSERT(res == 0 || res == ETIMEDOUT);

   return res != ETIMEDOUT;
}

}  //namespace ipcdetail
}  //namespace interprocess
}  //namespace boost

#include <boost/interprocess/detail/config_end.hpp>

#endif   //#ifndef BOOST_INTERPROCESS_POSIX_CONDITION_HPP

max_stars_repo_name: iazarov/metrixplusplus

max_issues_repo_name: iazarov/metrixplusplus

max_forks_repo_name: iazarov/metrixplusplus


text:
/**
 *    Copyright (C) 2018-present MongoDB, Inc.
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the Server Side Public License, version 1,
 *    as published by MongoDB, Inc.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    Server Side Public License for more details.
 *
 *    You should have received a copy of the Server Side Public License
 *    along with this program. If not, see
 *    <http://www.mongodb.com/licensing/server-side-public-license>.
 *
 *    As a special exception, the copyright holders give permission to link the
 *    code of portions of this program with the OpenSSL library under certain
 *    conditions as described in each individual source file and distribute
 *    linked combinations including the program with the OpenSSL library. You
 *    must comply with the Server Side Public License in all respects for
 *    all of the code used other than as permitted herein. If you modify file(s)
 *    with this exception, you may extend this exception to your version of the
 *    file(s), but you are not obligated to do so. If you do not wish to do so,
 *    delete this exception statement from your version. If you delete this
 *    exception statement from all source files in the program, then also delete
 *    it in the license file.
 */

#include "mongo/platform/basic.h"

#include "mongo/db/pipeline/document_source_replace_root.h"

#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <fmt/format.h>

#include "mongo/db/exec/document_value/value.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/pipeline/document_source_replace_root_gen.h"
#include "mongo/db/pipeline/lite_parsed_document_source.h"

namespace mongo {

using boost::intrusive_ptr;

Document ReplaceRootTransformation::applyTransformation(const Document& input) {
    // Extract subdocument in the form of a Value.
    Value newRoot = _newRoot->evaluate(input, &_expCtx->variables);
    // The newRoot expression, if it exists, must evaluate to an object.
    uassert(40228,
            fmt::format(kErrorTemplate.rawData(),
                        _errMsgContextForNonObject,
                        newRoot.toString(),
                        typeName(newRoot.getType()),
                        input.toString()),
            newRoot.getType() == BSONType::Object);

    // Turn the value into a document.
    MutableDocument newDoc(newRoot.getDocument());
    newDoc.copyMetaDataFrom(input);
    return newDoc.freeze();
}

REGISTER_DOCUMENT_SOURCE(replaceRoot,
                         LiteParsedDocumentSourceDefault::parse,
                         DocumentSourceReplaceRoot::createFromBson,
                         AllowedWithApiStrict::kAlways);
REGISTER_DOCUMENT_SOURCE(replaceWith,
                         LiteParsedDocumentSourceDefault::parse,
                         DocumentSourceReplaceRoot::createFromBson,
                         AllowedWithApiStrict::kAlways);

intrusive_ptr<DocumentSource> DocumentSourceReplaceRoot::createFromBson(
    BSONElement elem, const intrusive_ptr<ExpressionContext>& expCtx) {
    const auto stageName = elem.fieldNameStringData();
    auto newRootExpression = [&]() {
        if (stageName == kAliasNameReplaceWith) {
            return Expression::parseOperand(expCtx.get(), elem, expCtx->variablesParseState);
        }

        invariant(
            stageName == kStageName,
            str::stream() << "Unexpected stage registered with DocumentSourceReplaceRoot parser: "
                          << stageName);
        uassert(40229,
                str::stream() << "expected an object as specification for " << kStageName
                              << " stage, got " << typeName(elem.type()),
                elem.type() == Object);

        auto spec =
            ReplaceRootSpec::parse(IDLParserErrorContext(kStageName), elem.embeddedObject());

        // The IDL doesn't give us back the type we need to feed into the expression parser, and
        // the expression parser needs the extra state in 'vps' and 'expCtx', so for now we have
        // to adapt the two.
        BSONObj parsingBson = BSON("newRoot" << spec.getNewRoot());
        return Expression::parseOperand(
            expCtx.get(), parsingBson.firstElement(), expCtx->variablesParseState);
    }();

    // Whether this was specified as $replaceWith or $replaceRoot, always use the name $replaceRoot
    // to simplify the serialization process.
    const bool isIndependentOfAnyCollection = false;
    return new DocumentSourceSingleDocumentTransformation(
        expCtx,
        std::make_unique<ReplaceRootTransformation>(
            expCtx,
            newRootExpression,
            (stageName == kStageName) ? "'newRoot' expression " : "'replacement document' "),
        kStageName.rawData(),
        isIndependentOfAnyCollection);
}

boost::intrusive_ptr<DocumentSource> DocumentSourceReplaceRoot::create(
    const boost::intrusive_ptr<ExpressionContext>& expCtx,
    const boost::intrusive_ptr<Expression>& newRootExpression,
    std::string errMsgContextForNonObjects) {
    const bool isIndependentOfAnyCollection = false;
    return new DocumentSourceSingleDocumentTransformation(
        expCtx,
        std::make_unique<ReplaceRootTransformation>(
            expCtx, newRootExpression, std::move(errMsgContextForNonObjects)),
        kStageName.rawData(),
        isIndependentOfAnyCollection);
}
}  // namespace mongo

max_stars_repo_name: benety/mongo

max_issues_repo_name: benety/mongo

max_forks_repo_name: benety/mongo


text:
#ifndef GENTREE_HPP
#define GENTREE_HPP

#include <memory>
// to switch to std::variant when we get GCC 7
#include <boost/variant.hpp>
#include <vector>
#include <utility>
#include <iostream>
// to switch to std::optional when we get GCC 7
#include <experimental/optional>

template<typename T>
using optional = std::experimental::optional<T>;
// note, in_place construction no longer explicit when
// move from std::experimental -> std, so we can remove much verbiage
auto in_place = std::experimental::in_place;

template<typename LT, typename NT>
class gentree {
	private:
		typedef LT leafT;
		struct nodeT;
		typedef boost::variant<leafT,nodeT> treenodeT;
		typedef std::shared_ptr<treenodeT> treeptr;

		struct nodeT {
			NT node;
			std::vector<gentree> ch;

			template<typename... T>
			nodeT(NT &n, T &&...ch) : node(n) {
				addchildren(std::forward<T>(ch)...);
			}
			template<typename... T>
			nodeT(const NT &n, T &&...ch) : node(n) {
				addchildren(std::forward<T>(ch)...);
			}
			template<typename... T>
			nodeT(NT &&n, T &&...ch) : node(std::move(n)) {
				addchildren(std::forward<T>(ch)...);
			}

			void addchildren(std::vector<gentree> &c) {
				ch = c;
			}
			void addchildren(const std::vector<gentree> &c) {
				ch = c;
			}
			void addchildren(std::vector<gentree> &&c) {
				ch = std::move(c);
			}

			void addchildren(std::vector<treeptr> &c) {
				for(auto &x : c) ch.emplace_back(gentree(x));
			}
			void addchildren(const std::vector<treeptr> &c) {
				for(auto &x : c) ch.emplace_back(gentree(x));
			}
			void addchildren(std::vector<treeptr> &&c) {
				for(auto &x : c) ch.emplace_back(gentree(x));
			}

			void addchildren() {
			}

			template<typename... T>
			void addchildren(gentree &c, T &&...cs) {
				ch.emplace_back(c);
				addchildren(std::forward<T>(cs)...);
			}
			template<typename... T>
			void addchildren(const gentree &c, T &&...cs) {
				ch.emplace_back(c);
				addchildren(std::forward<T>(cs)...);
			}
			template<typename... T>
			void addchildren(gentree &&c, T &&...cs) {
				ch.emplace_back(std::move(c));
				addchildren(std::forward<T>(cs)...);
			}
			template<typename... T>

			void addchildren(treeptr &c, T &&...cs) {
				ch.emplace_back(gentree(c));
				addchildren(std::forward<T>(cs)...);
			}
			template<typename... T>
			void addchildren(const treeptr &c, T &&...cs) {
				ch.emplace_back(gentree(c));
				addchildren(std::forward<T>(cs)...);
			}
			template<typename... T>
			void addchildren(treeptr &&c, T &&...cs) {
				ch.emplace_back(gentree(std::move(c)));
				addchildren(std::forward<T>(cs)...);
			}

		};

		treeptr root;

	private:
		gentree(const treeptr &t) : root(t) {}

	public:
		gentree() : root(nullptr) {}

		gentree(const gentree &t) : root(t.root) {}
		gentree(gentree &&t) : root(std::move(t.root)) {}
		// below needed to prevent "T &&" constructor below
		// from matching -- this isn't ideal but works for the moment
		// (see https://mpark.github.io/programming/2014/06/07/beware-of-perfect-forwarding-constructors/)
		gentree(gentree &t) : root(t.root) {}
		gentree(const gentree &&t) : root(std::move(t.root)) {}

		gentree &operator=(const gentree &t) {
			if (&t!=this) root = t.root;
			return *this;
		}
		gentree &operator=(gentree &&t) {
			root = std::move(t.root);
			return *this;
		}

		// do we need/want this??
		template<typename T>
		explicit gentree(T &&l) : root(std::make_shared<treenodeT>(
					leafT(std::forward<T>(l)))) {
		}

		template<typename... Ts>
		gentree(NT &&n, Ts &&...args)
			: root(std::make_shared<treenodeT>(
					nodeT{std::move(n), std::forward<Ts>(args)...})) {
		}
		template<typename... Ts>
		gentree(const NT &n, Ts &&...args)
			: root(std::make_shared<treenodeT>(
					nodeT{n, std::forward<Ts>(args)...})) {
		}

		template<typename LF, typename NF>
		auto fold(LF leaffn, NF nodefn) const
				-> decltype(leaffn(std::declval<leafT>())) {
			if (isleaf()) return leaffn(boost::get<leafT>(*root));
			else {
				typedef decltype(leaffn(std::declval<leafT>())) rT;
				std::vector<rT> chret;
				const nodeT &node = boost::get<nodeT>(*root);
				chret.reserve(node.ch.size());
				for(auto &c : node.ch)
					chret.emplace_back(c.fold(leaffn,nodefn));
				return nodefn(node.node,std::move(chret));
			}
		}

		// F should map gentree -> optional<gentree>
		// (if fn returns no value, then use existing (sub)tree)
		template<typename F>
		gentree map(F fn) const {
			return mapmaybe(fn).value_or(*this);
		}

		/*
		template<typename F>
		optional<gentree> mapmaybe(F fn) const {
			auto newtree = fn(*this);
			if (newtree) return newtree;
			if (isleaf()) return {};
			auto &ch = children();
			std::vector<gentree> newch;
			for(int i=0;i<ch.size();i++) {
				auto nc = ch[i].mapmaybe(fn);
				if (nc) {
					if (newch.empty()) {
						newch.reserve(ch.size());
						for(int j=0;j<i;j++)
							newch.emplace_back(ch[j]);
					}
					newch.emplace_back(*nc);
				} else if (!newch.empty()) newch.emplace_back(ch[i]);
			}
			if (newch.empty()) return {};
			return optional<gentree>{in_place,asnode(),newch};
		}
		*/

		template<typename F>
		optional<gentree> mapmaybe(F fn) const {
			if (isleaf()) return fn(*this);
			auto &ch = children();
			std::vector<gentree> newch;
			for(int i=0;i<ch.size();i++) {
				auto nc = ch[i].mapmaybe(fn);
				if (nc) {
					if (newch.empty()) {
						newch.reserve(ch.size());
						for(int j=0;j<i;j++)
							newch.emplace_back(ch[j]);
					}
					newch.emplace_back(*nc);
				} else if (!newch.empty()) newch.emplace_back(ch[i]);
			}
			if (newch.empty()) return fn(*this);
			gentree newtree{asnode(),newch};
			auto newtree2 = fn(newtree);
			if (newtree2) return newtree2;
			return newtree;
		}

		// belong here or need a different fold?
		bool sameas(const gentree &t) const {
			if (!(isleaf()==t.isleaf())) return false;
			if (isleaf())
				return boost::get<leafT>(*root)==boost::get<leafT>(*t.root);
			const nodeT &n = boost::get<nodeT>(*root);
			const nodeT &tn = boost::get<nodeT>(*t.root);
			if (!(asnode() == t.asnode())) return false;
			auto ch = children(), tch = t.children();
			if (ch.size() != tch.size()) return false;
			for(int i=0;i<ch.size();i++)
				if (!(ch[i].sameas(tch[i]))) return false;
			return true;
		}

		/*
		bool operator!=(const gentree &t) const {
			return !(*this==t);
		}
		*/

		bool sameptr(const gentree &t) const {
			return t.root == root;
		}

		bool isleaf() const { return root->which()==0; }

		const LT &asleaf() const { return boost::get<leafT>(*root); }
		const NT &asnode() const { return boost::get<nodeT>(*root).node; }
		const std::vector<gentree> &children() const {
			const nodeT &n = boost::get<nodeT>(*root);
			return n.ch;
		}

		std::size_t ptrhash() const {
			return std::hash<std::shared_ptr<treenodeT>>{}(root);
		}
};
#endif

max_stars_repo_name: cshelton/tqscas

max_issues_repo_name: cshelton/tqscas

max_forks_repo_name: cshelton/tqscas


text:
/****************************************************************************
 *
 * Copyright (C) 2017  Intel Corporation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include "mainloop.h"

#include <signal.h>
#include <stdio.h>
#include <poll.h>
#include <pthread.h>
#include <boost/format.hpp>

#include <linux/videodev2.h>
#include <opencv2/opencv.hpp>

#include "log.h"
#include "util.h"

#define DEFAULT_PIXEL_FORMAT V4L2_PIX_FMT_YUV420
#define CAMERA_MSEC_TIMEOUT 100

#define POLL_ERROR_EVENTS (POLLERR | POLLHUP | POLLNVAL)

#define EXPOSURE_MASK_SIZE 128
#define EXPOSURE_MSV_TARGET 5.0f
#define EXPOSURE_P_GAIN 100.0f
#define EXPOSURE_I_GAIN 0.5f
#define EXPOSURE_D_GAIN 0.5f
#define GAIN_P_GAIN 50.0f
#define GAIN_I_GAIN 0.5f
#define GAIN_D_GAIN 0.5f
#define EXPOSURE_CHANGE_THRESHOLD 30.0
#define EXPOSURE_ABOSULUTE_MAX_VALUE 1727
#define GAIN_CHANGE_THRESHOLD 15.0
#define GAIN_ABOSULUTE_MAX_VALUE 127
#define CAMERA_FPS_MIN 50

using namespace cv;

static volatile bool _should_run;

static void exit_signal_handler(UNUSED int signum)
{
	_should_run = false;
}

void Mainloop::_signal_handlers_setup(void)
{
	struct sigaction sa = { };

	sa.sa_flags = SA_NOCLDSTOP;
	sa.sa_handler = exit_signal_handler;
	sigaction(SIGTERM, &sa, NULL);
	sigaction(SIGINT, &sa, NULL);

	sa.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &sa, NULL);
}

static void *_thread_callback(void *data)
{
	Mainloop *mainloop = (Mainloop *)data;
	return mainloop->camera_thread();
}

void *Mainloop::camera_thread()
{
	Pollable *pollables[] = { _camera };
	const uint8_t len = sizeof(pollables) / sizeof(Pollable *);
	struct pollfd desc[len];

	for (uint8_t i = 0; i < len; i++) {
		desc[i].fd = pollables[i]->_fd;
		desc[i].events = POLLIN | POLLPRI | POLL_ERROR_EVENTS;
		desc[i].revents = 0;
	}

	while (_should_run) {
		int ret = poll(desc, sizeof(desc) / sizeof(struct pollfd), CAMERA_MSEC_TIMEOUT);
		if (ret == 0) {
			DEBUG("Camera timeout, restarting...");
			_camera->restart();
			continue;
		}
		if (ret < 1) {
			continue;
		}

		for (unsigned i = 0; ret && i < (sizeof(desc) / sizeof(struct pollfd)); i++, ret--) {
			for (uint8_t j = 0; j < len; j++) {
				if (desc[i].fd == pollables[j]->_fd) {
					if (desc[i].revents & (POLLIN | POLLPRI)) {
						pollables[j]->handle_read();
					}
					if (desc[i].revents & POLLOUT) {
						pollables[j]->handle_canwrite();
					}
					if (desc[i].revents & POLL_ERROR_EVENTS) {
						ERROR("Poll error event on camera: %u", desc[i].revents);
					}
					break;
				}
			}
		}
	}

	return NULL;
}

void Mainloop::_loop()
{
	Pollable *pollables[] = { _mavlink };
	uint8_t len = sizeof(pollables) / sizeof(Pollable *);
	struct pollfd desc[len];

	_signal_handlers_setup();
	_should_run = true;

	pthread_mutex_init(&_mainloop_lock, NULL);
	pthread_t thread;
	if (pthread_create(&thread, NULL, _thread_callback, this)) {
		ERROR("Unable to create a thread");
		return;
	}

	for (uint8_t i = 0; i < len; i++) {
		desc[i].fd = pollables[i]->_fd;
		desc[i].events = POLLIN | POLLPRI | POLL_ERROR_EVENTS;
		desc[i].revents = 0;
	}

	while (_should_run) {
		int ret = poll(desc, sizeof(desc) / sizeof(struct pollfd), -1);
		if (ret < 1) {
			continue;
		}

		pthread_mutex_lock(&_mainloop_lock);

		for (unsigned i = 0; ret && i < (sizeof(desc) / sizeof(struct pollfd)); i++, ret--) {
			for (uint8_t j = 0; j < len; j++) {
				if (desc[i].fd == pollables[j]->_fd) {
					if (desc[i].revents & (POLLIN | POLLPRI)) {
						pollables[j]->handle_read();
					}
					if (desc[i].revents & POLLOUT) {
						pollables[j]->handle_canwrite();
					}
					if (desc[i].revents & POLL_ERROR_EVENTS) {
						ERROR("Poll error event: %u fd: %i", desc[i].revents, desc[i].fd);
					}
					break;
				}
			}
		}

		pthread_mutex_unlock(&_mainloop_lock);
	}

	pthread_join(thread, NULL);
}

static void _camera_callback(const void *img, size_t len, const struct timeval *timestamp, void *data)
{
	   Mainloop *mainloop = (Mainloop *)data;
	   mainloop->camera_callback(img, len, timestamp);
}

void Mainloop::_exposure_update(Mat frame, uint64_t timestamp_us)
{
	if (timestamp_us < _next_exposure_update_timestap) {
		return;
	}

	cv::Mat mask(frame.rows, frame.cols, CV_8U,cv::Scalar(0));
	mask(cv::Rect(frame.cols / 2 - EXPOSURE_MASK_SIZE / 2,
			frame.rows / 2 - EXPOSURE_MASK_SIZE / 2,
			EXPOSURE_MASK_SIZE, EXPOSURE_MASK_SIZE)) = 255;

	int channels[] = { 0 };
	cv::Mat hist;
	int histSize[] = { 10 };
	float range[] = { 0, 255 };
	const float* ranges[] = { range };

	calcHist(&frame, 1, channels, mask, hist, 1, histSize, ranges, true, false);

	/* calculate Mean Sample Value (MSV) */
	float msv = 0.0f;
	for (int i = 0; i < histSize[0]; i++) {
		msv += (i + 1) *hist.at<float>(i) / 16384.0f;// 128x128 -> 16384
	}

	/* PID-controller */
	float msv_error = EXPOSURE_MSV_TARGET - msv;
	float msv_error_d = msv_error - _msv_error_old;
	_msv_error_int += msv_error;

	float exposure = _camera->exposure_get();
	float gain = _camera->gain_get();

	exposure += (EXPOSURE_P_GAIN * msv_error) + (EXPOSURE_I_GAIN * _msv_error_int) + (EXPOSURE_D_GAIN * msv_error_d);

	// adjust the gain if exposure is saturated
	if (gain > 1.0f || (exposure > EXPOSURE_ABOSULUTE_MAX_VALUE-1 && _camera->exposure_get() > EXPOSURE_ABOSULUTE_MAX_VALUE-1)) {
		// calculate new gain value based on MSV
		gain += (GAIN_P_GAIN*msv_error) + (GAIN_I_GAIN*_msv_error_int) + (GAIN_D_GAIN*msv_error_d);

		if (gain > GAIN_ABOSULUTE_MAX_VALUE) {
			gain = GAIN_ABOSULUTE_MAX_VALUE;
		} else if (gain < 1.0f) {
			gain = 1.0f;
		}

		/* set new gain value if bigger than threshold */
		if (fabs(gain - _camera->gain_get()) > GAIN_CHANGE_THRESHOLD || (gain < 2.0f && _camera->gain_get() > 1.0f) ||
				(gain > GAIN_ABOSULUTE_MAX_VALUE-1 && _camera->gain_get() < GAIN_ABOSULUTE_MAX_VALUE)) {
#if DEBUG_LEVEL
			DEBUG("gain set %u", (uint16_t)gain);
#endif
			_camera->gain_set(gain);
		}

	} else { // adjust exposure

		if (exposure > EXPOSURE_ABOSULUTE_MAX_VALUE) {
			exposure = EXPOSURE_ABOSULUTE_MAX_VALUE;
		} else if (exposure < 1.0f) {
			exposure = 1.0f;
		}

		/* set new exposure value if bigger than threshold */
		if (fabs(exposure - _camera->exposure_get()) > EXPOSURE_CHANGE_THRESHOLD || (exposure < 2.0f && _camera->exposure_get() > 1.0f) ||
				(exposure > EXPOSURE_ABOSULUTE_MAX_VALUE-1 && _camera->exposure_get() < EXPOSURE_ABOSULUTE_MAX_VALUE)) {
#if DEBUG_LEVEL
			DEBUG("exposure set %u", (uint16_t)exposure);
#endif
			_camera->exposure_set(exposure);
		}

	}

	_msv_error_old = msv_error;

	/* update exposure at 5Hz */
	_next_exposure_update_timestap = timestamp_us + (USEC_PER_SEC / 5);
}

/* Callback called from another thread */
void Mainloop::camera_callback(const void *img, UNUSED size_t len, const struct timeval *timestamp)
{
	ros::Time now = ros::Time::now();
	int dt_us = 0;
	float flow_x_ang = 0, flow_y_ang = 0;

	pthread_mutex_lock(&_mainloop_lock);

	Mat frame_gray = Mat(_camera->height, _camera->width, CV_8UC1);
	frame_gray.data = (uchar*)img;

	cv::Rect clean_crop(0, 0, _camera_width-10, _camera_height-10);
	cv::Mat frame_gray_cleaner = frame_gray(clean_crop);
	sensor_msgs::CameraInfoPtr camera_info(new sensor_msgs::CameraInfo(cinfo_->getCameraInfo()));
	sensor_msgs::ImagePtr image_msg = cv_bridge::CvImage(std_msgs::Header(), "mono8", frame_gray_cleaner).toImageMsg();
	image_msg->header.frame_id = "camera";
	image_msg->header.stamp = now;

	if(camera_info->width != image_msg->width or camera_info->height != image_msg->height) {
		camera_info.reset(new sensor_msgs::CameraInfo());
	    camera_info->height = image_msg->height;
	    camera_info->width = image_msg->width;
	}

	image_publisher.publish(image_msg, camera_info);
	frame_gray_cleaner.release();
	ros::spinOnce();

#if DEBUG_LEVEL
	imshow(_window_name, frame_gray);
#endif

	uint64_t img_time_us = timestamp->tv_usec + timestamp->tv_sec * USEC_PER_SEC;

	// crop the image (optical flow assumes narrow field of view)
	cv::Rect crop(_camera->width / 2 - _optical_flow->getImageWidth() / 2,
			_camera->height / 2 - _optical_flow->getImageHeight() / 2,
			_optical_flow->getImageWidth(), _optical_flow->getImageHeight());
	cv::Mat cropped_image = frame_gray(crop);

	// auto exposure for cropped image
	_exposure_update(cropped_image, img_time_us);

	float fps = 0;

	if (_camera_initial_timestamp) {
		img_time_us -= _camera_initial_timestamp;
		fps = 1.0f / ((float)(img_time_us - _camera_prev_timestamp) / USEC_PER_SEC);
	} else {
		_camera_initial_timestamp = img_time_us;
		img_time_us = 0;
	}

	if (img_time_us > UINT32_MAX) {
		ERROR("img_time_us > UINT32_MAX");
	}

	cv::Mat cropped;
	// Copy the data into new matrix -> cropped_image.data can not be used in calcFlow()...
	cropped_image.copyTo(cropped);
	cropped_image.release();
	int flow_quality = 0;
	if(compute_vio) {
		flow_quality = _optical_flow->calcFlow(cropped.data, (uint32_t)img_time_us, dt_us, flow_x_ang, flow_y_ang);
	}

	cropped.release();
	_camera_prev_timestamp = img_time_us;

	// check if flow is ready/integrated -> flow output rate
	if (flow_quality < 0) {
		pthread_mutex_unlock(&_mainloop_lock);
		return;
	}

	Point3_<double> gyro_data = _gyro_integrated;
	_gyro_integrated.x = _gyro_integrated.y = _gyro_integrated.z = 0;

	// check liveness of gyro data
	if (_gyro_last_usec_timestamp == _gyro_prev_timestamp) {
		DEBUG("No new gyroscope data available");
		pthread_mutex_unlock(&_mainloop_lock);
		return;
	}
	_gyro_last_usec_timestamp = _gyro_prev_timestamp;

	if (fps < CAMERA_FPS_MIN) {
		ERROR("FPS below minimum, actual=%u minimum=%u", (unsigned)fps, CAMERA_FPS_MIN);
	}
#if DEBUG_LEVEL
	DEBUG("Optical flow quality=%i x=%f y=%f timestamp sec=%lu usec=%lu fps=%f", flow_quality, flow_y_ang, -flow_x_ang,
		img_time_us / USEC_PER_SEC, img_time_us % USEC_PER_SEC, fps);
	DEBUG("Gyro data(%f %f %f)", gyro_data.x, gyro_data.y, gyro_data.z);
#endif

	if (!_offset_timestamp_usec) {
		DEBUG("Waiting for timestamp from vehicle");
		pthread_mutex_unlock(&_mainloop_lock);
		return;
	}

	mavlink_optical_flow_rad_t msg;
	msg.time_usec = _offset_timestamp_usec + img_time_us;
	msg.integration_time_us = dt_us;
	msg.integrated_x = flow_x_ang;
	msg.integrated_y = flow_y_ang;
	msg.integrated_xgyro = -gyro_data.y; // switch to match pixel directions
	msg.integrated_ygyro = gyro_data.x; // switch to match pixel directions
	msg.integrated_zgyro = gyro_data.z;
	msg.time_delta_distance_us = 0;
	msg.distance = -1.0;
	msg.temperature = 0;
	msg.sensor_id = 0;
	msg.quality = flow_quality;

	if(compute_vio) {
		_mavlink->optical_flow_rad_msg_write(&msg);
	}

	frame_gray.release();
	pthread_mutex_unlock(&_mainloop_lock);
}

static void _highres_imu_msg_callback(const mavlink_highres_imu_t *msg, void *data)
{
	Mainloop *mainloop = (Mainloop *)data;
	mainloop->highres_imu_msg_callback(msg);
}

void Mainloop::highres_imu_msg_callback(const mavlink_highres_imu_t *msg)
{
	// Integrate
	const double dt = (double)(msg->time_usec - _gyro_prev_timestamp) / (double)USEC_PER_SEC;

	// protect against invalid gyro and timestamp data -> huge random values
	const double max_dt = 0.05; // at least 20Hz
	const double max_gyro = 20.0; // big enough value
	if (_gyro_prev_timestamp && dt < max_dt && abs(msg->xgyro) < max_gyro
		&& abs(msg->ygyro) < max_gyro && abs(msg->zgyro) < max_gyro) {
		_gyro_integrated.x += (msg->xgyro * dt);
		_gyro_integrated.y += (msg->ygyro * dt);
		_gyro_integrated.z += (msg->zgyro * dt);
#if DEBUG_LEVEL
	} else {
		DEBUG("Invalid gyro/timestamp data: gyro = (%f, %f, %f) dt = %f", msg->xgyro, msg->ygyro, msg->zgyro, dt);
#endif
	}
	_gyro_prev_timestamp = msg->time_usec;

	if (!_offset_timestamp_usec)
		_offset_timestamp_usec = msg->time_usec;
}

int Mainloop::init(const char *camera_device, int camera_id,
		uint32_t camera_width, uint32_t camera_height, uint32_t crop_width,
		uint32_t crop_height, const char *mavlink_tcp_ip, unsigned long mavlink_tcp_port,
		int flow_output_rate, float focal_length_x, float focal_length_y)
{
	_camera_width = camera_width;
	_camera_height = camera_height;
	image_transport = new image_transport::ImageTransport(nh);
	image_publisher = image_transport->advertiseCamera("image_raw", 1);
	cinfo_ = boost::make_shared<camera_info_manager::CameraInfoManager>(nh);
	cinfo_->setCameraName("bottom_cam");

	ros::NodeHandle pnh("~");
	pnh.param("compute_vio", compute_vio, compute_vio);
	if(compute_vio) 	ROS_INFO("Computing VIO");
	if(not compute_vio) ROS_INFO("NOT Computing VIO");

	_camera = new Camera(camera_device);
	if (!_camera) {
		ERROR("No memory to allocate Camera");
		return -1;
	}
	_mavlink = new Mavlink_TCP();
	if (!_mavlink) {
		ERROR("No memory to allocate Mavlink_TCP");
		goto mavlink_memory_error;
	}
	// TODO: load parameters from yaml file
	_optical_flow = new OpticalFlowOpenCV(focal_length_x, focal_length_y, flow_output_rate, crop_width,
			crop_height);
	if (!_optical_flow) {
		ERROR("No memory to instantiate OpticalFlowOpenCV");
		goto optical_memory_error;
	}

	if (_camera->init(camera_id, camera_width, camera_height, DEFAULT_PIXEL_FORMAT)) {
		ERROR("Unable to initialize camera");
		goto camera_init_error;
	}
	if (_mavlink->init(mavlink_tcp_ip, mavlink_tcp_port)) {
		ERROR("Unable to initialize Mavlink_TCP");
		goto mavlink_init_error;
	}

	return 0;

mavlink_init_error:
	_camera->shutdown();
camera_init_error:
	delete _optical_flow;
optical_memory_error:
	delete _mavlink;
mavlink_memory_error:
	delete _camera;
	return -1;
}

void Mainloop::shutdown()
{
	_camera->shutdown();

	delete _optical_flow;
	delete _mavlink;
	delete _camera;

	_optical_flow = NULL;
	_mavlink = NULL;
	_camera = NULL;
}

int Mainloop::run()
{
	_camera->callback_set(_camera_callback, this);
	_mavlink->highres_imu_msg_subscribe(_highres_imu_msg_callback, this);

	if (_camera->start()) {
		ERROR("Unable to start camera streaming");
		goto camera_start_error;
	}

#if DEBUG_LEVEL
	namedWindow(_window_name, WINDOW_AUTOSIZE);
	startWindowThread();
#endif

	_loop();

#if DEBUG_LEVEL
	destroyAllWindows();
#endif

	_camera->stop();

	_camera->callback_set(NULL, NULL);

	return 0;

camera_start_error:
	_camera->callback_set(NULL, NULL);
	return -1;
}

max_stars_repo_name: AlexisTM/aero-optical-flow-ros

max_issues_repo_name: AlexisTM/aero-optical-flow-ros

max_forks_repo_name: AlexisTM/aero-optical-flow-ros


text:
#include "ces.h"

#include <vector>
#include <sstream>
#include <boost/shared_ptr.hpp>

#include "aligner.h"
#include "lattice.h"
#include "viterbi_envelope.h"
#include "error_surface.h"

using boost::shared_ptr;
using namespace std;

const bool minimize_segments = true;    // if adjacent segments have equal scores, merge them

void ComputeErrorSurface(const SentenceScorer& ss, const ViterbiEnvelope& ve, ErrorSurface* env, const ScoreType type, const Hypergraph& hg) {
  vector<WordID> prev_trans;
  const vector<shared_ptr<Segment> >& ienv = ve.GetSortedSegs();
  env->resize(ienv.size());
  ScoreP prev_score;
  int j = 0;
  for (int i = 0; i < ienv.size(); ++i) {
    const Segment& seg = *ienv[i];
    vector<WordID> trans;
    if (type == AER) {
      vector<bool> edges(hg.edges_.size(), false);
      seg.CollectEdgesUsed(&edges);  // get the set of edges in the viterbi
                                     // alignment
      ostringstream os;
      const string* psrc = ss.GetSource();
      if (psrc == NULL) {
        cerr << "AER scoring in VEST requires source, but it is missing!\n";
        abort();
      }
      size_t pos = psrc->rfind(" ||| ");
      if (pos == string::npos) {
        cerr << "Malformed source for AER: expected |||\nINPUT: " << *psrc << endl;
        abort();
      }
      Lattice src;
      Lattice ref;
      LatticeTools::ConvertTextOrPLF(psrc->substr(0, pos), &src);
      LatticeTools::ConvertTextOrPLF(psrc->substr(pos + 5), &ref);
      AlignerTools::WriteAlignment(src, ref, hg, &os, true, 0, &edges);
      string tstr = os.str();
      TD::ConvertSentence(tstr.substr(tstr.rfind(" ||| ") + 5), &trans);
    } else {
      seg.ConstructTranslation(&trans);
    }
    // cerr << "Scoring: " << TD::GetString(trans) << endl;
    if (trans == prev_trans) {
      if (!minimize_segments) {
        assert(prev_score); // if this fails, it means
	                    // the decoder can generate null translations
        ErrorSegment& out = (*env)[j];
        out.delta = prev_score->GetZero();
        out.x = seg.x;
	++j;
      }
      // cerr << "Identical translation, skipping scoring\n";
    } else {
      ScoreP score = ss.ScoreCandidate(trans);
      // cerr << "score= " << score->ComputeScore() << "\n";
      ScoreP cur_delta_p = score->GetZero();
      Score* cur_delta = cur_delta_p.get();
      // just record the score diffs
      if (!prev_score)
        prev_score = score->GetZero();

      score->Subtract(*prev_score, cur_delta);
      prev_trans.swap(trans);
      prev_score = score;
      if ((!minimize_segments) || (!cur_delta->IsAdditiveIdentity())) {
        ErrorSegment& out = (*env)[j];
        out.delta = cur_delta_p;
        out.x = seg.x;
        ++j;
      }
    }
  }
  // cerr << " In segments: " << ienv.size() << endl;
  // cerr << "Out segments: " << j << endl;
  assert(j > 0);
  env->resize(j);
}

ext: cc

max_stars_repo_name: agesmundo/FasterCubePruning

max_issues_repo_name: jhclark/cdec

max_forks_repo_name: jhclark/cdec


text:
/**
 * Copyright (c) 2017 Melown Technologies SE
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * *  Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "../include/vts-browser/math.hpp"
#include "../utilities/json.hpp"
#include "../position.hpp"

#include <vts-libs/registry/json.hpp>
#include <vts-libs/registry/io.hpp>
#include <boost/lexical_cast.hpp>

namespace vts
{

Position::Position()
{
    point[0] = point[1] = point[2] = 0;
    orientation[0] = orientation[1] = orientation[2] = 0;
    viewExtent = 0;
    fov = 0;
    subjective = false;
    floatAltitude = false;
}

vtslibs::registry::Position p2p(const Position &p)
{
    vtslibs::registry::Position r;
    r.position = vecToUblas<math::Point3>(rawToVec3(p.point));
    r.orientation = vecToUblas<math::Point3>(rawToVec3(p.orientation));
    r.verticalExtent = p.viewExtent;
    r.verticalFov = p.fov;
    r.type = p.subjective ? vtslibs::registry::Position::Type::subjective : vtslibs::registry::Position::Type::objective;
    r.heightMode = p.floatAltitude ? vtslibs::registry::Position::HeightMode::floating : vtslibs::registry::Position::HeightMode::fixed;
    return r;
}

Position p2p(const vtslibs::registry::Position &p)
{
    Position r;
    vecToRaw(vecFromUblas<vec3>(p.position), r.point);
    vecToRaw(vecFromUblas<vec3>(p.orientation), r.orientation);
    r.viewExtent = p.verticalExtent;
    r.fov = p.verticalFov;
    r.subjective = p.type == vtslibs::registry::Position::Type::subjective;
    r.floatAltitude = p.heightMode == vtslibs::registry::Position::HeightMode::floating;
    return r;
}

Position::Position(const std::string &position)
{
    try
    {
        if (position.find("[") == std::string::npos)
        {
            *this = p2p(boost::lexical_cast<vtslibs::registry::Position>(position));
        }
        else
        {
            Json::Value val = stringToJson(position);
            *this = p2p(vtslibs::registry::positionFromJson(val));
        }
    }
    catch (const std::exception &e)
    {
        LOGTHROW(err2, std::runtime_error) << "Failed parsing position from string <" << position << "> with error <" << e.what() << ">";
    }
    catch (...)
    {
        LOGTHROW(err2, std::runtime_error) << "Failed parsing position from string <" << position << ">";
    }
}

std::string Position::toJson() const
{
    return jsonToString(vtslibs::registry::asJson(p2p(*this)));
}

std::string Position::toUrl() const
{
    std::ostringstream ss;
    ss << std::fixed << std::setprecision(10);
    ss << p2p(*this);
    return ss.str();
}

} // namespace vts

max_stars_repo_name: ExploreWilder/vts-browser-cpp

max_issues_repo_name: ExploreWilder/vts-browser-cpp

max_forks_repo_name: ExploreWilder/vts-browser-cpp


text:
// Copyright (c) 2017 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "maxblocksize.h"
#include "chain.h"
#include "chainparams.h"
#include "options.h"
#include "test/test_bitcoin.h"
#include "test/testutil.h"

#include <boost/test/unit_test.hpp>

#include <algorithm>

BOOST_FIXTURE_TEST_SUITE(maxblocksize_tests, BasicTestingSetup)

void fillBlockIndex(
        Consensus::Params& params, std::vector<CBlockIndex>& blockIndexes,
        bool addVotes, int64_t currMax) {

    auto customizeFunc = [addVotes, currMax](CBlockIndex& index) {
        index.nMaxBlockSize = currMax;

        if (!addVotes) return;

        index.nMaxBlockSizeVote = std::max(index.nHeight * 1000000, 1000000);
    };
    BuildDummyBlockIndex(blockIndexes, customizeFunc);
};

BOOST_AUTO_TEST_CASE(get_next_max_blocksize) {
    auto params = Params(CBaseChainParams::REGTEST).GetConsensus();
    BOOST_CHECK_EQUAL(uint32_t(1512), params.nMaxBlockSizeChangePosition);

    // Genesis block, legacy block size
    BOOST_CHECK_EQUAL(MAX_BLOCK_SIZE, GetNextMaxBlockSize(nullptr, params));

    const int64_t interval = params.nMaxBlockSizeAdjustmentInterval;

    // Not at a difficulty adjustment interval,
    // should not change max block size.
    {
        uint64_t currMax = MAX_BLOCK_SIZE;
        std::vector<CBlockIndex> blockInterval(interval);
        fillBlockIndex(params, blockInterval, true, currMax);
        CBlockIndex index;

        for (auto& b : blockInterval) {
            if ((b.nHeight + 1) % interval == 0)
                continue;
            BOOST_CHECK_EQUAL(currMax,
                GetNextMaxBlockSize(&b, params));

        }
    }

    // No block voted. Keep current size.
    {
        uint64_t currMax = 2000000;
        std::vector<CBlockIndex> blockInterval(interval);
        fillBlockIndex(params, blockInterval, false, currMax);

        BOOST_CHECK_EQUAL(currMax,
                GetNextMaxBlockSize(&blockInterval.back(), params));
    }

    // Everyone votes current size. Keep current size.
    {
        uint64_t currMax = 2000000;
        std::vector<CBlockIndex> blockInterval(interval);
        fillBlockIndex(params, blockInterval, false, currMax);

        for (CBlockIndex& b : blockInterval)
            b.nMaxBlockSizeVote = currMax;

        BOOST_CHECK_EQUAL(currMax,
                GetNextMaxBlockSize(&blockInterval.back(), params));
    }

    // Everyone votes.
    // Blocks vote (vote# * 1MB)
    {
        // Test raise.
        uint64_t currMax = 2000000;
        std::vector<CBlockIndex> blockInterval(interval);
        fillBlockIndex(params, blockInterval, true, currMax);
        uint64_t newLimit = GetNextMaxBlockSize(&blockInterval.back(), params);
        BOOST_CHECK_EQUAL(uint64_t(currMax * 1.05), newLimit);

        // Test lower.
        currMax = 1000 * 2000000;
        fillBlockIndex(params, blockInterval, true, currMax);
        newLimit = GetNextMaxBlockSize(&blockInterval.back(), params);
        BOOST_CHECK_EQUAL(uint64_t(currMax / 1.05), newLimit);
    }
}

std::vector<unsigned char> to_uchar(const std::string& coinbaseStr) {
    return std::vector<unsigned char>(begin(coinbaseStr), end(coinbaseStr));
}

// If we have an explicit /B/ vote, we read it and ignore /EB/.
BOOST_AUTO_TEST_CASE(get_max_blocksize_vote_b) {

    std::vector<unsigned char> vote(to_uchar("/BIP100/B2/EB1/"));
    int32_t height = 600000;

    // Coinbase as in the internal miner
    CScript coinbase = CScript() << height << vote << OP_0;
    BOOST_CHECK_EQUAL(2000000u, GetMaxBlockSizeVote(coinbase, height));

    // Coinbase as created with IncrementExtraNonce
    unsigned int nonce = 1;
    CScript coinbase_flags;
    coinbase = (CScript() << height << vote << CScriptNum(nonce)) + coinbase_flags;
    BOOST_CHECK_EQUAL(2000000u, GetMaxBlockSizeVote(coinbase, height));

    // coinbase without height should also work
    coinbase = (CScript() << vote << CScriptNum(nonce)) + coinbase_flags;
    BOOST_CHECK_EQUAL(2000000u, GetMaxBlockSizeVote(coinbase, height));

    // can't vote twice, only first one counts.
    coinbase = (CScript() << to_uchar("/BIP100/B4/EB6/BIP100/B8/"));
    BOOST_CHECK_EQUAL(4000000u, GetMaxBlockSizeVote(coinbase, height));

    // B-votes override EB, even though EB is first.
    coinbase = (CScript() << to_uchar("/EB6/BIP100/B8/"));
    BOOST_CHECK_EQUAL(8000000u, GetMaxBlockSizeVote(coinbase, height));
}

// If /B/ is not present, we count /EB/ as a vote.
BOOST_AUTO_TEST_CASE(get_max_blocksize_vote_eb) {
    std::vector<unsigned char> vote(to_uchar("/some data/EB1/"));
    int32_t height = 600000;

    CScript coinbase = CScript() << height << vote << OP_0;
    BOOST_CHECK_EQUAL(1000000u, GetMaxBlockSizeVote(coinbase, height));

    unsigned int nonce = 1;
    CScript coinbase_flags;
    coinbase = (CScript() << height << vote << CScriptNum(nonce)) + coinbase_flags;
    BOOST_CHECK_EQUAL(1000000u, GetMaxBlockSizeVote(coinbase, height));

    // Example of a Bitcoin Unlimited coinbase string
    coinbase = CScript() << height << to_uchar("/EB16/AD12/a miner comment");
    BOOST_CHECK_EQUAL(16000000u, GetMaxBlockSizeVote(coinbase, height));

    // can't vote twice, only first one counts.
    coinbase = (CScript() << to_uchar("some data/EB6/EB8/"));
    BOOST_CHECK_EQUAL(6000000u, GetMaxBlockSizeVote(coinbase, height));
}

BOOST_AUTO_TEST_CASE(get_max_blocksize_vote_no_vote) {
    int32_t height = 600000;
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << OP_0, height));

    // votes must begin and end with /
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/EB2"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("EB2/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/BIP100/B2"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("BIP100/B2/"), height));

    // whitespace is not allowed
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/ EB2/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/EB2 /"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/EB 2/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/BIP100/B2 /"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/BIP100/ B2/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/BIP100/B 2/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/BIP100 /B2/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/ BIP100/B2/"), height));

    // decimals not supported
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/EB2.2/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << height << to_uchar("/BIP100/B2.2/"), height));

    // missing mb value
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << to_uchar("/BIP100/B/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << to_uchar("/EB/"), height));

    // missing BIP100 prefix
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << to_uchar("/B2/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << to_uchar("/BIP100/B/B8/"), height));

    //Explicit zeros and garbage
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << to_uchar("/BIP100/B0/BIP100/B2"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << to_uchar("/EB0/EB2/"), height));
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(CScript() << to_uchar("/BIP100/Bgarbage/B2/"), height));
    BOOST_CHECK_EQUAL(2000000u, GetMaxBlockSizeVote(CScript() << to_uchar("/EBgarbage/EB2/"), height));

    // Test that height is not a part of the vote string.
    // Encoded height in this test ends with /.
    // Should not be interpreted as /BIP100/B8/
    CScript coinbase = CScript() << 47;
    BOOST_CHECK_EQUAL('/', coinbase.back());
    std::vector<unsigned char> vote = to_uchar("BIP100/B8/");
    coinbase.insert(coinbase.end(), vote.begin(), vote.end()); // insert instead of << to avoid size being prepended
    BOOST_CHECK_EQUAL(0u, GetMaxBlockSizeVote(coinbase, 47));
}

BOOST_AUTO_TEST_CASE(next_block_raise_cap) {
    BOOST_CHECK_EQUAL(MAX_BLOCK_SIZE * 105 / 100, NextBlockRaiseCap(MAX_BLOCK_SIZE));
    BOOST_CHECK_THROW(NextBlockRaiseCap(MAX_BLOCK_SIZE - 1), std::invalid_argument);
}

BOOST_AUTO_TEST_SUITE_END();