<commit_before>/*
 * Copyright (C) 2017-present ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "schema.hh"
#include "schema_registry.hh"
#include "keys.hh"
#include "mutation_fragment.hh"
#include "mutation.hh"
#include "schema_builder.hh"
#include "sstable_utils.hh"
#include "reader_permit.hh"

// Helper for working with the following table:
//
//   CREATE TABLE ks.cf (pk text, ck text, v text, s1 text static, PRIMARY KEY (pk, ck));
//
class simple_schema {
    friend class global_simple_schema;

    schema_ptr _s;
    api::timestamp_type _timestamp = api::min_timestamp;
    const column_definition* _v_def = nullptr;
    table_schema_version _v_def_version;

    simple_schema(schema_ptr s, api::timestamp_type timestamp)
        : _s(s)
        , _timestamp(timestamp)
    {}
private:
    const column_definition& get_v_def(const schema& s) {
        if (_v_def_version == s.version() && _v_def) {
            return *_v_def;
        }
        _v_def = s.get_column_definition(to_bytes("v"));
        _v_def_version = s.version();
        return *_v_def;
    }
public:
    api::timestamp_type current_timestamp() {
        return _timestamp;
    }
    api::timestamp_type new_timestamp() {
        return _timestamp++;
    }
    tombstone new_tombstone() {
        return {new_timestamp(), gc_clock::now()};
    }
public:
    using with_static = bool_class<class static_tag>;
    simple_schema(with_static ws = with_static::yes)
        : _s(schema_builder("ks", "cf")
            .with_column("pk", utf8_type, column_kind::partition_key)
            .with_column("ck", utf8_type, column_kind::clustering_key)
            .with_column("s1", utf8_type, ws ? column_kind::static_column : column_kind::regular_column)
            .with_column("v", utf8_type)
            .build())
    { }

    sstring cql() const {
        return "CREATE TABLE ks.cf (pk text, ck text, v text, s1 text static, PRIMARY KEY (pk, ck))";
    }

    clustering_key make_ckey(sstring ck) {
        return clustering_key::from_single_value(*_s, serialized(ck));
    }

    query::clustering_range make_ckey_range(uint32_t start_inclusive, uint32_t end_inclusive) {
        return query::clustering_range::make({make_ckey(start_inclusive)}, {make_ckey(end_inclusive)});
    }

    // Make a clustering_key which is n-th in some arbitrary sequence of keys
    clustering_key make_ckey(uint32_t n) {
        return make_ckey(format("ck{:010d}", n));
    }

    // Make a partition key which is n-th in some arbitrary sequence of keys.
    // There is no particular order for the keys, they're not in ring order.
    dht::decorated_key make_pkey(uint32_t n) {
        return make_pkey(format("pk{:010d}", n));
    }

    dht::decorated_key make_pkey(sstring pk) {
        auto key = partition_key::from_single_value(*_s, serialized(pk));
        return dht::decorate_key(*_s, key);
    }

    api::timestamp_type add_row(mutation& m, const clustering_key& key, const sstring& v, api::timestamp_type t = api::missing_timestamp) {
        if (t == api::missing_timestamp) {
            t = new_timestamp();
        }
        const column_definition& v_def = get_v_def(*_s);
        m.set_clustered_cell(key, v_def, atomic_cell::make_live(*v_def.type, t, serialized(v)));
        return t;
    }

    std::pair<sstring, api::timestamp_type> get_value(const schema& s, const clustering_row& row) {
        const column_definition& v_def = get_v_def(s);
        auto cell = row.cells().find_cell(v_def.id);
        if (!cell) {
            throw std::runtime_error("cell not found");
        }
        atomic_cell_view ac = cell->as_atomic_cell(v_def);
        if (!ac.is_live()) {
            throw std::runtime_error("cell is dead");
        }
        return std::make_pair(value_cast<sstring>(utf8_type->deserialize(ac.value().linearize())), ac.timestamp());
    }

    mutation_fragment make_row(const clustering_key& key, sstring v) {
        auto row = clustering_row(key);
        const column_definition& v_def = get_v_def(*_s);
        row.cells().apply(v_def, atomic_cell::make_live(*v_def.type, new_timestamp(), serialized(v)));
        return mutation_fragment(*_s, tests::make_permit(), std::move(row));
    }

    mutation_fragment make_row_from_serialized_value(const clustering_key& key, bytes_view v) {
        auto row = clustering_row(key);
        const column_definition& v_def = get_v_def(*_s);
        row.cells().apply(v_def, atomic_cell::make_live(*v_def.type, new_timestamp(), v));
        return mutation_fragment(*_s, tests::make_permit(), std::move(row));
    }

    mutation_fragment make_static_row(sstring v) {
        static_row row;
        const column_definition& s_def = *_s->get_column_definition(to_bytes("s1"));
        row.cells().apply(s_def, atomic_cell::make_live(*s_def.type, new_timestamp(), serialized(v)));
        return mutation_fragment(*_s, tests::make_permit(), std::move(row));
    }

    void set_schema(schema_ptr s) {
        _s = s;
    }

    api::timestamp_type add_static_row(mutation& m, sstring s1, api::timestamp_type t = api::missing_timestamp) {
        if (t == api::missing_timestamp) {
            t = new_timestamp();
        }
        m.set_static_cell(to_bytes("s1"), data_value(s1), t);

        return t;
    }

    range_tombstone delete_range(mutation& m, const query::clustering_range& range) {
        auto rt = make_range_tombstone(range);
        m.partition().apply_delete(*_s, rt);
        return rt;
    }

    range_tombstone make_range_tombstone(const query::clustering_range& range, tombstone t = {}) {
        auto bv_range = bound_view::from_range(range);
        if (!t) {
            t = tombstone(new_timestamp(), gc_clock::now());
        }
        range_tombstone rt(bv_range.first, bv_range.second, t);
        return rt;
    }
    range_tombstone make_range_tombstone(const query::clustering_range& range, gc_clock::time_point deletion_time) {
        return make_range_tombstone(range, tombstone(new_timestamp(), deletion_time));
    }

    mutation new_mutation(sstring pk) {
        return mutation(_s, make_pkey(pk));
    }

    schema_ptr schema() {
        return _s;
    }

    const schema_ptr schema() const {
        return _s;
    }

    // Creates a sequence of keys in ring order
    std::vector<dht::decorated_key> make_pkeys(int n) {
        auto local_keys = make_local_keys(n, _s);
        return boost::copy_range<std::vector<dht::decorated_key>>(local_keys | boost::adaptors::transformed([this] (sstring& key) {
            return make_pkey(std::move(key));
        }));
    }

    dht::decorated_key make_pkey() {
        return make_pkey(make_local_key(_s));
    }

    static std::vector<dht::ring_position> to_ring_positions(const std::vector<dht::decorated_key>& keys) {
        return boost::copy_range<std::vector<dht::ring_position>>(keys | boost::adaptors::transformed([] (const dht::decorated_key& key) {
            return dht::ring_position(key);
        }));
    }

    // Returns n clustering keys in their natural order
    std::vector<clustering_key> make_ckeys(int n) {
        std::vector<clustering_key> keys;
        for (int i = 0; i < n; ++i) {
            keys.push_back(make_ckey(i));
        }
        return keys;
    }
};

// Allows a simple_schema to be transferred to another shard.
// Must be used in `cql_test_env`.
class global_simple_schema {
    global_schema_ptr _gs;
    api::timestamp_type _timestamp;
public:

    global_simple_schema(simple_schema& s)
        : _gs(s.schema())
        , _timestamp(s.current_timestamp()) {
    }

    simple_schema get() const {
        return simple_schema(_gs.get(), _timestamp);
    }
};
<commit_msg>test: lib: simple_schema: Accept tombstone in delete_range()<commit_after>/*
 * Copyright (C) 2017-present ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "schema.hh"
#include "schema_registry.hh"
#include "keys.hh"
#include "mutation_fragment.hh"
#include "mutation.hh"
#include "schema_builder.hh"
#include "sstable_utils.hh"
#include "reader_permit.hh"

// Helper for working with the following table:
//
//   CREATE TABLE ks.cf (pk text, ck text, v text, s1 text static, PRIMARY KEY (pk, ck));
//
class simple_schema {
    friend class global_simple_schema;

    schema_ptr _s;
    api::timestamp_type _timestamp = api::min_timestamp;
    const column_definition* _v_def = nullptr;
    table_schema_version _v_def_version;

    simple_schema(schema_ptr s, api::timestamp_type timestamp)
        : _s(s)
        , _timestamp(timestamp)
    {}
private:
    const column_definition& get_v_def(const schema& s) {
        if (_v_def_version == s.version() && _v_def) {
            return *_v_def;
        }
        _v_def = s.get_column_definition(to_bytes("v"));
        _v_def_version = s.version();
        return *_v_def;
    }
public:
    api::timestamp_type current_timestamp() {
        return _timestamp;
    }
    api::timestamp_type new_timestamp() {
        return _timestamp++;
    }
    tombstone new_tombstone() {
        return {new_timestamp(), gc_clock::now()};
    }
public:
    using with_static = bool_class<class static_tag>;
    simple_schema(with_static ws = with_static::yes)
        : _s(schema_builder("ks", "cf")
            .with_column("pk", utf8_type, column_kind::partition_key)
            .with_column("ck", utf8_type, column_kind::clustering_key)
            .with_column("s1", utf8_type, ws ? column_kind::static_column : column_kind::regular_column)
            .with_column("v", utf8_type)
            .build())
    { }

    sstring cql() const {
        return "CREATE TABLE ks.cf (pk text, ck text, v text, s1 text static, PRIMARY KEY (pk, ck))";
    }

    clustering_key make_ckey(sstring ck) {
        return clustering_key::from_single_value(*_s, serialized(ck));
    }

    query::clustering_range make_ckey_range(uint32_t start_inclusive, uint32_t end_inclusive) {
        return query::clustering_range::make({make_ckey(start_inclusive)}, {make_ckey(end_inclusive)});
    }

    // Make a clustering_key which is n-th in some arbitrary sequence of keys
    clustering_key make_ckey(uint32_t n) {
        return make_ckey(format("ck{:010d}", n));
    }

    // Make a partition key which is n-th in some arbitrary sequence of keys.
    // There is no particular order for the keys, they're not in ring order.
    dht::decorated_key make_pkey(uint32_t n) {
        return make_pkey(format("pk{:010d}", n));
    }

    dht::decorated_key make_pkey(sstring pk) {
        auto key = partition_key::from_single_value(*_s, serialized(pk));
        return dht::decorate_key(*_s, key);
    }

    api::timestamp_type add_row(mutation& m, const clustering_key& key, const sstring& v, api::timestamp_type t = api::missing_timestamp) {
        if (t == api::missing_timestamp) {
            t = new_timestamp();
        }
        const column_definition& v_def = get_v_def(*_s);
        m.set_clustered_cell(key, v_def, atomic_cell::make_live(*v_def.type, t, serialized(v)));
        return t;
    }

    std::pair<sstring, api::timestamp_type> get_value(const schema& s, const clustering_row& row) {
        const column_definition& v_def = get_v_def(s);
        auto cell = row.cells().find_cell(v_def.id);
        if (!cell) {
            throw std::runtime_error("cell not found");
        }
        atomic_cell_view ac = cell->as_atomic_cell(v_def);
        if (!ac.is_live()) {
            throw std::runtime_error("cell is dead");
        }
        return std::make_pair(value_cast<sstring>(utf8_type->deserialize(ac.value().linearize())), ac.timestamp());
    }

    mutation_fragment make_row(const clustering_key& key, sstring v) {
        auto row = clustering_row(key);
        const column_definition& v_def = get_v_def(*_s);
        row.cells().apply(v_def, atomic_cell::make_live(*v_def.type, new_timestamp(), serialized(v)));
        return mutation_fragment(*_s, tests::make_permit(), std::move(row));
    }

    mutation_fragment make_row_from_serialized_value(const clustering_key& key, bytes_view v) {
        auto row = clustering_row(key);
        const column_definition& v_def = get_v_def(*_s);
        row.cells().apply(v_def, atomic_cell::make_live(*v_def.type, new_timestamp(), v));
        return mutation_fragment(*_s, tests::make_permit(), std::move(row));
    }

    mutation_fragment make_static_row(sstring v) {
        static_row row;
        const column_definition& s_def = *_s->get_column_definition(to_bytes("s1"));
        row.cells().apply(s_def, atomic_cell::make_live(*s_def.type, new_timestamp(), serialized(v)));
        return mutation_fragment(*_s, tests::make_permit(), std::move(row));
    }

    void set_schema(schema_ptr s) {
        _s = s;
    }

    api::timestamp_type add_static_row(mutation& m, sstring s1, api::timestamp_type t = api::missing_timestamp) {
        if (t == api::missing_timestamp) {
            t = new_timestamp();
        }
        m.set_static_cell(to_bytes("s1"), data_value(s1), t);

        return t;
    }

    range_tombstone delete_range(mutation& m, const query::clustering_range& range, tombstone t = {}) {
        auto rt = make_range_tombstone(range, t);
        m.partition().apply_delete(*_s, rt);
        return rt;
    }

    range_tombstone make_range_tombstone(const query::clustering_range& range, tombstone t = {}) {
        auto bv_range = bound_view::from_range(range);
        if (!t) {
            t = tombstone(new_timestamp(), gc_clock::now());
        }
        range_tombstone rt(bv_range.first, bv_range.second, t);
        return rt;
    }
    range_tombstone make_range_tombstone(const query::clustering_range& range, gc_clock::time_point deletion_time) {
        return make_range_tombstone(range, tombstone(new_timestamp(), deletion_time));
    }

    mutation new_mutation(sstring pk) {
        return mutation(_s, make_pkey(pk));
    }

    schema_ptr schema() {
        return _s;
    }

    const schema_ptr schema() const {
        return _s;
    }

    // Creates a sequence of keys in ring order
    std::vector<dht::decorated_key> make_pkeys(int n) {
        auto local_keys = make_local_keys(n, _s);
        return boost::copy_range<std::vector<dht::decorated_key>>(local_keys | boost::adaptors::transformed([this] (sstring& key) {
            return make_pkey(std::move(key));
        }));
    }

    dht::decorated_key make_pkey() {
        return make_pkey(make_local_key(_s));
    }

    static std::vector<dht::ring_position> to_ring_positions(const std::vector<dht::decorated_key>& keys) {
        return boost::copy_range<std::vector<dht::ring_position>>(keys | boost::adaptors::transformed([] (const dht::decorated_key& key) {
            return dht::ring_position(key);
        }));
    }

    // Returns n clustering keys in their natural order
    std::vector<clustering_key> make_ckeys(int n) {
        std::vector<clustering_key> keys;
        for (int i = 0; i < n; ++i) {
            keys.push_back(make_ckey(i));
        }
        return keys;
    }
};

// Allows a simple_schema to be transferred to another shard.
// Must be used in `cql_test_env`.
class global_simple_schema {
    global_schema_ptr _gs;
    api::timestamp_type _timestamp;
public:

    global_simple_schema(simple_schema& s)
        : _gs(s.schema())
        , _timestamp(s.current_timestamp()) {
    }

    simple_schema get() const {
        return simple_schema(_gs.get(), _timestamp);
    }
};
<|endoftext|>


<commit_before>#include "gamebox.h"

gamebox::gamebox() {
}

void gamebox::begin() {
	Serial.begin(115200);
	tft.begin();
	tft.fillScreen(WHITE);
	tft.setTextColor(BLACK);
	tft.setCursor(32,100);
	tft.println("Ardtendo(c)");
	tft.setCursor(32,112);
	tft.println("ardtendo.de");
	pinMode(LEFT_KEY, INPUT_PULLUP);
	pinMode(UP_KEY, INPUT_PULLUP);
	pinMode(RIGHT_KEY, INPUT_PULLUP);
	pinMode(DOWN_KEY, INPUT_PULLUP);
	pinMode(START_KEY, INPUT_PULLUP);
	pinMode(SELECT_KEY, INPUT_PULLUP);
	pinMode(B_KEY, INPUT_PULLUP);
	pinMode(A_KEY, INPUT_PULLUP);
	delay(150);
	uint16_t colors[] = {YELLOW, RED, MAGENTA, GREEN, BLUE};
	#ifdef SIMPLE_SETUP
	tft.setTextSize(2);
	char* gb = "GAME BOX";

	for (uint8_t i = 0; i < 20; i++) {
		tft.setCursor(15,50);
		for (uint8_t c = 0; c < 8; c++) {
			if (i - c < 0) break;
			tft.setTextColor(colors[min((i-c)/2, 4)]);
			tft.write(gb[c]);
		}
		delay(50);
	}
	#else
	static const uint8_t logo [21][16] = {
		{ 0x0,  0x0, 0x30,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x6,  0x0,  0x0,  0x0},
		{ 0x0,  0x7, 0xfe, 0x1f, 0xc0, 0x7c, 0x1f, 0x87, 0xff, 0x81, 0xff, 0xc0, 0x3f, 0xcf, 0x83, 0xe0},
		{ 0x0, 0x1f, 0xfe, 0x1f, 0xc0, 0x7c, 0x1f, 0x87, 0xff, 0x81, 0xff, 0xe0, 0xff, 0xef, 0x87, 0xc0},
		{ 0x0, 0x7f, 0xfe, 0x1f, 0xc0, 0xfc, 0x1f, 0x87, 0xff, 0x81, 0xff, 0xf1, 0xff, 0xf7, 0x8f, 0xc0},
		{ 0x0, 0xff, 0xfe, 0x3f, 0xc0, 0xfe, 0x3f, 0x87, 0xff,  0x3, 0xff, 0xf1, 0xff, 0xff, 0xcf, 0x80},
		{ 0x1, 0xfc,  0x0, 0x3f, 0xc0, 0xfe, 0x3f, 0x87, 0x80,  0x3, 0xe1, 0xf3, 0xe0, 0xfb, 0xdf,  0x0},
		{ 0x1, 0xf8,  0x0, 0x3f, 0xc1, 0xfe, 0x3f, 0xc7, 0x80,  0x3, 0xe0, 0xf3, 0xe0, 0x7b, 0xff,  0x0},
		{ 0x3, 0xe0,  0x0, 0x7f, 0xc1, 0xfe, 0x7f, 0xcf, 0x80,  0x3, 0xe1, 0xf7, 0xc0, 0x7b, 0xfe,  0x0},
		{ 0x3, 0xe0,  0x0, 0x7b, 0xe1, 0xfe, 0x7f, 0xcf, 0xfe,  0x3, 0xff, 0xf7, 0xc0, 0x7d, 0xfc,  0x0},
		{ 0x7, 0xc0,  0x0, 0xfb, 0xe3, 0xfe, 0xff, 0xcf, 0xfe,  0x3, 0xff, 0xe7, 0x80, 0x7d, 0xfc,  0x0},
		{ 0x7, 0xc0,  0x0, 0xf1, 0xe3, 0xfe, 0xf7, 0xcf, 0xfe,  0x3, 0xff, 0xe7, 0x80, 0x78, 0xf8,  0x0},
		{ 0x7, 0x83, 0xfd, 0xff, 0xe3, 0xdf, 0xf7, 0xcf, 0xfc,  0x7, 0xff, 0xe7, 0x80, 0x78, 0xf8,  0x0},
		{ 0x7, 0x83, 0xfd, 0xff, 0xe7, 0xdf, 0xf7, 0xcf, 0xfc,  0x7, 0xff, 0xf7, 0x80, 0x79, 0xfc,  0x0},
		{ 0x7, 0xc3, 0xfd, 0xff, 0xe7, 0xcf, 0xe7, 0xcf,  0x0,  0x7, 0xc1, 0xf7, 0x80, 0xf9, 0xfc,  0x0},
		{ 0x7, 0xc3, 0xfb, 0xff, 0xe7, 0x8f, 0xe3, 0xdf,  0x0,  0x7, 0xc1, 0xf7, 0x80, 0xfb, 0xfe,  0x0},
		{ 0x3, 0xe0, 0x7b, 0xe1, 0xff, 0x8f, 0xe3, 0xdf,  0x0,  0x7, 0xc1, 0xf7, 0xc1, 0xf3, 0xfe,  0x0},
		{ 0x3, 0xf8, 0xff, 0xc1, 0xff, 0x8f, 0xc3, 0xdf, 0xfe,  0x7, 0xff, 0xe7, 0xf7, 0xf7, 0xcf,  0x0},
		{ 0x1, 0xff, 0xff, 0xc1, 0xff,  0xf, 0xc3, 0xdf, 0xfe,  0x7, 0xff, 0xe3, 0xff, 0xe7, 0x8f, 0x80},
		{ 0x0, 0xff, 0xff, 0x80, 0xff,  0xf, 0x83, 0xdf, 0xfc,  0xf, 0xff, 0xc1, 0xff, 0xcf, 0x87, 0x80},
		{ 0x0, 0x7f, 0xff, 0x80, 0xff,  0x7, 0x83, 0xdf, 0xfc,  0xf, 0xff, 0x80, 0xff,  0xf,  0x7, 0xc0},
		{ 0x0, 0x1f, 0xcf, 0x80, 0xfe,  0x7, 0x83, 0xdf, 0xfc,  0xf, 0xfe,  0x0, 0x3c, 0x1f,  0x3, 0xc0}
	};
	uint16_t color;
	uint32_t nextFrame;
	for (int8_t i = 0; i < 50; i++) {
		nextFrame = millis()+40;
		for (uint8_t col = 0; col < 16; col++) {
			uint8_t prev = ((i-1)/2 - col) / 2;
			uint8_t now  = (i/2 - col) / 2;
			if (prev == now && now != 0) continue;
			if (prev  >= 4) continue;
			if (i/2 < col) break;
			color = colors[min(now, 4)];
			for (uint8_t row = 0; row < 21; row++) {
				for (uint8_t b = 7; b < 8; b--) {
					if ((logo[row][col] >> b) & 1) {
						tft.drawPixel(col * 8 + 7 - b, 50 + row, color);
					}
				}
			}
		}
		while (millis() < nextFrame);
	}
	#endif
	delay(1500);
	tft.fillScreen(WHITE);
}

uint8_t gamebox::startMultiplayer() {
	tft.fillScreen(BLACK);
	tft.setTextColor(WHITE);
	tft.setTextSize(3);
	tft.setCursor(38,40);
	tft.print("> <");
	tft.setTextSize(1);
	tft.setCursor(32,64);
	tft.print("Mehrspieler");
	tft.setCursor(12,72);
	tft.print("Auf Gegner warten");
	tft.setTextSize(3);
	uint8_t playerN = 1;
	unsigned long started = millis();
	//while(Serial.available()) Serial.read();
	if (Serial.peek() != 1)
		Serial.write(1);
	while (true) {
		tft.setTextColor((millis()/300)%2 ? WHITE : BLACK);
		tft.setCursor(40,40);
		tft.print(" ?");
		if (Serial.available()) {
			char c = Serial.read();
			switch (c) {
			case 1:
				playerN = 2;
				Serial.write(2);
				break;
			case 2:
				Serial.write(3);
			case 3:
				tft.fillScreen(BLACK);
				return playerN;
			}
		}
		if (started+10000 < millis()) {
			break;
		}
	}
	tft.setTextColor(BLACK);
	tft.setCursor(40,40);
	tft.print(" ?");
	tft.setTextColor(WHITE);
	tft.setCursor(40,40);
	tft.print(" X");
	tft.setTextSize(1);
	tft.setCursor(44,80);
	tft.print("Fehler:");
	tft.setCursor(5,88);
	switch (playerN) {
		case 1:
			tft.print("Kein Gegner gefunden");break;
		case 2:
			tft.print("    Keine Antwort   ");break;
	}
	while (!getStartKey());
	return false;
}

uint8_t gamebox::getMovement() {
	return ((!digitalRead(LEFT_KEY))*LEFT_BIT)|((!digitalRead(UP_KEY))*UP_BIT)|((!digitalRead(RIGHT_KEY))*RIGHT_BIT)|((!digitalRead(DOWN_KEY))*DOWN_BIT);
}

boolean gamebox::getLeftKey() {
	return !digitalRead(LEFT_KEY);
}
boolean gamebox::getUpKey() {
	return !digitalRead(UP_KEY);
}
boolean gamebox::getRightKey() {
	return !digitalRead(RIGHT_KEY);
}
boolean gamebox::getDownKey() {
	return !digitalRead(DOWN_KEY);
}
boolean gamebox::getStartKey() {
	return !digitalRead(START_KEY);
}
boolean gamebox::getSelectKey() {
	return !digitalRead(SELECT_KEY);
}
boolean gamebox::getBKey() {
	return !digitalRead(B_KEY);
}
boolean gamebox::getAKey() {
	return !digitalRead(A_KEY);
}

int16_t gamebox::recvMessage() {
	unsigned long started = millis();
	while (started+1000 > millis()) {
		if (Serial.available()) {
			Serial.write(255);
			return Serial.read();
		}
	}
	return -1;
}

boolean gamebox::sendMessage(byte msg) {
	Serial.write(msg);
	unsigned long sent = millis();
	while (sent+1000 > millis()) {
		if (Serial.available()) {
			if (Serial.read() == 255) return true;
		}
	}
	tft.fillScreen(BLACK);
	tft.setTextColor(WHITE);
	tft.setTextSize(3);
	tft.setCursor(40,40);
	tft.print(">X<");
	tft.setTextSize(1);
	tft.setCursor(6,64);
	tft.print("Verbindung verloren");
	tft.setCursor(10,72);
	tft.print("Gleiches Spiel an?");
	while(!getStartKey());
	return false;
}

gamebox Gamebox = gamebox();
TFT_ILI9163C tft = TFT_ILI9163C(__CS, __DC);
<commit_msg>Delete gamebox.cpp<commit_after><|endoftext|>


<commit_before>#include "channel.h"

namespace SleepyDiscord {
	Channel::Channel(const std::string * rawJSON) : Channel(json::getValues(rawJSON->c_str(), fields)) {}

	Channel::Channel(const std::vector<std::string> values) :
		//felid                modifier                       value
		ID                   (                                values[index(fields, "id"                   )]  ),
		type                 (static_cast<ChannelType>(toInt( values[index(fields, "type"                 )]))),
		serverID             (                                values[index(fields, "guild_id"             )]  ),
		position             (toInt                         ( values[index(fields, "position"             )]) ),
		permissionOverwrites (modIfElse(isSpecified, JSON_getArray<Overwrite>, values[index(fields, "permission_overwrites" )], std::vector<Overwrite>())),
		name                 (                                values[index(fields, "name"                 )]  ),
		topic                (                                values[index(fields, "topic"                )]  ),
		isNSFW               (getBool                       ( values[index(fields, "nsfw"                 )]) ),
		lastMessageID        (                                values[index(fields, "last_message_id"      )]  ),
		bitrate              (toInt                         ( values[index(fields, "bitrate"              )]) ),
		userLimit            (toInt                         ( values[index(fields, "user_limit"           )]) ),
		//recipients
		icon                 (                                values[index(fields, "icon"                 )]  ),
		ownerID              (                                values[index(fields, "owner_id"             )]  ),
		//applicationID
		parentID             (                                values[index(fields, "parent_id"            )]  ),
		lastPinTimestamp     (                                values[index(fields, "last_pin_timestamp"   )]  )
	{}

	const std::initializer_list<const char*const> Channel::fields = {
		"id", "guild_id", "name", "type", "position", "is_private",
		"permission_overwrites", "topic", "last_message_id", "bitrate", "user_limit"
	};

	Channel::~Channel() {

	}

	DirectMessageChannel::~DirectMessageChannel() {

	}

	DirectMessageChannel::DirectMessageChannel(const std::string * rawJSON) : DirectMessageChannel(json::getValues(rawJSON->c_str(), fields)) {}

	DirectMessageChannel::DirectMessageChannel(const std::vector<std::string> values) :
		//variable       modifier value                    felid
		ID             (         values[index(fields, "id"             )] ),
		is_private     ( getBool(values[index(fields, "is_private"     )])),
		recipient      ( User(  &values[index(fields, "recipient"      )])),
		lastMessageID  (         values[index(fields, "last_message_id")] )
	{}

	const std::initializer_list<const char*const> DirectMessageChannel::fields = {
		"id", "is_private", "recipient", "last_message_id"
	};

	Overwrite::Overwrite() : allow(Permission::NONE), deny(Permission::NONE)
	{}

	Overwrite::Overwrite(const std::string * rawJSON) : Overwrite(json::getValues(rawJSON->c_str(), fields)) {}

	Overwrite::Overwrite(const std::vector<std::string> values) :
		//variable modifier value              felid
		ID    (      values[index(fields, "id"   )] ),
		type  (      values[index(fields, "type" )] ),
		allow (toPermission(toLongLong(values[index(fields, "allow")]))),
		deny  (toPermission(toLongLong(values[index(fields, "deny" )])))
	{}
	const std::initializer_list<const char*const> Overwrite::fields = {
		"id", "type", "allow", "deny"
	};
}
<commit_msg>Fixed cannot read memory in Channel constructor, for real this time<commit_after>#include "channel.h"

namespace SleepyDiscord {
	Channel::Channel(const std::string * rawJSON) : Channel(json::getValues(rawJSON->c_str(), fields)) {}

	Channel::Channel(const std::vector<std::string> values) :
		//felid                modifier                       value
		ID                   (                                values[index(fields, "id"                   )]  ),
		type                 (static_cast<ChannelType>(toInt( values[index(fields, "type"                 )]))),
		serverID             (                                values[index(fields, "guild_id"             )]  ),
		position             (toInt                         ( values[index(fields, "position"             )]) ),
		permissionOverwrites (modIfElse(isSpecified, JSON_getArray<Overwrite>, values[index(fields, "permission_overwrites" )], std::vector<Overwrite>())),
		name                 (                                values[index(fields, "name"                 )]  ),
		topic                (                                values[index(fields, "topic"                )]  ),
		isNSFW               (getBool                       ( values[index(fields, "nsfw"                 )]) ),
		lastMessageID        (                                values[index(fields, "last_message_id"      )]  ),
		bitrate              (toInt                         ( values[index(fields, "bitrate"              )]) ),
		userLimit            (toInt                         ( values[index(fields, "user_limit"           )]) ),
		//recipients
		icon                 (                                values[index(fields, "icon"                 )]  ),
		ownerID              (                                values[index(fields, "owner_id"             )]  ),
		//applicationID
		parentID             (                                values[index(fields, "parent_id"            )]  ),
		lastPinTimestamp     (                                values[index(fields, "last_pin_timestamp"   )]  )
	{}

	const std::initializer_list<const char*const> Channel::fields = {
		"id", "type", "guild_id", "position", "permission_overwrites",
		"name", "topic", "nsfw", "last_message_id", "bitrate",
		"user_limit", "recipients", "icon", "owner_id",
		"application_id", "parent_id", "last_pin_timestamp"
	};

	Channel::~Channel() {

	}

	DirectMessageChannel::~DirectMessageChannel() {

	}

	DirectMessageChannel::DirectMessageChannel(const std::string * rawJSON) : DirectMessageChannel(json::getValues(rawJSON->c_str(), fields)) {}

	DirectMessageChannel::DirectMessageChannel(const std::vector<std::string> values) :
		//variable       modifier value                    felid
		ID             (         values[index(fields, "id"             )] ),
		is_private     ( getBool(values[index(fields, "is_private"     )])),
		recipient      ( User(  &values[index(fields, "recipient"      )])),
		lastMessageID  (         values[index(fields, "last_message_id")] )
	{}

	const std::initializer_list<const char*const> DirectMessageChannel::fields = {
		"id", "is_private", "recipient", "last_message_id"
	};

	Overwrite::Overwrite() : allow(Permission::NONE), deny(Permission::NONE)
	{}

	Overwrite::Overwrite(const std::string * rawJSON) : Overwrite(json::getValues(rawJSON->c_str(), fields)) {}

	Overwrite::Overwrite(const std::vector<std::string> values) :
		//variable modifier value              felid
		ID    (      values[index(fields, "id"   )] ),
		type  (      values[index(fields, "type" )] ),
		allow (toPermission(toLongLong(values[index(fields, "allow")]))),
		deny  (toPermission(toLongLong(values[index(fields, "deny" )])))
	{}
	const std::initializer_list<const char*const> Overwrite::fields = {
		"id", "type", "allow", "deny"
	};
}
<|endoftext|>


<commit_before>// -*- mode: c++; coding: utf-8 -*-
#pragma once
#ifndef WTL_GENETIC_HPP_
#define WTL_GENETIC_HPP_

#include <vector>
#include <algorithm>

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
namespace wtl {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

template <class RNG> inline
std::vector<size_t> roulette_select(const std::vector<double>& fitnesses,
                                    RNG& rng,
                                    const size_t elites=0) {
    // make a roulette
    const size_t pop_size = fitnesses.size();
    std::vector<double> upper_bounds(pop_size);
    std::partial_sum(begin(fitnesses), end(fitnesses), begin(upper_bounds));
    const double sum_fitness = upper_bounds.back();

    std::vector<size_t> candidates(pop_size);
    std::iota(begin(candidates), end(candidates), 0);
    std::vector<size_t> children;
    children.reserve(pop_size * 1.1);

    // elite selection
    if (elites) {
        const size_t i = std::distance(
                begin(fitnesses),
                std::max_element(begin(fitnesses), end(fitnesses))
                );
        children.assign(elites, i);
    }

    // poisson selection
    const double num_fittest_children = pop_size / sum_fitness;
    for (size_t i=0; i<pop_size; ++i) {
        double expected = fitnesses[i];
        expected *= num_fittest_children;
        children.insert(children.end(),
                        std::poisson_distribution<size_t>(expected)(rng), i);
    }

    // roulette selection (slow)
    if (children.size() > pop_size) {
        std::shuffle(std::begin(children), std::end(children), rng);
        children.resize(pop_size);
    }
    else {
        std::uniform_real_distribution<double> uniform(0.0, sum_fitness);
        while (children.size() < pop_size) {
            size_t i = 0;
            const double dart(uniform(rng));
            while (upper_bounds[i] < dart) {++i;}
            children.push_back(i);
        }
    }
    return children;
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
} // namespace wtl
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

#endif /* WTL_GENETIC_HPP_ */
<commit_msg>Add low level functions to genetic.hpp<commit_after>// -*- mode: c++; coding: utf-8 -*-
#pragma once
#ifndef WTL_GENETIC_HPP_
#define WTL_GENETIC_HPP_

#include <vector>
#include <algorithm>

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
namespace wtl {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

//! Make upper bounds from fitness vector
inline std::vector<double> make_ubounds(std::vector<double> v) {
    std::partial_sum(v.begin(), v.end(), v.begin());
    return v;
}

inline size_t throw_dart(const std::vector<double>& ubounds, const double dart) {
    size_t idx = 0;
    while (ubounds[idx] < dart) {++idx;}
    return idx;
}

template <class RNG> inline
size_t roulette_select(const std::vector<double>& fitnesses, RNG& rng) {
    const std::vector<double> ubounds = make_ubounds(fitnesses);
    std::uniform_real_distribution<double> uniform(0.0, ubounds.back());
    return throw_dart(make_ubounds(fitnesses), uniform(rng));
}

template <class RNG> inline
std::vector<size_t> roulette_select(
    const std::vector<double>& fitnesses, const size_t n, RNG& rng) {

    const std::vector<double> ubounds = make_ubounds(fitnesses);
    std::uniform_real_distribution<double> uniform(0.0, ubounds.back());
    std::vector<size_t> selected_idx;
    selected_idx.reserve(n);
    for (size_t i=0; i<n; ++i) {
        selected_idx.push_back(throw_dart(ubounds, uniform(rng)));
    }
    return selected_idx;
}

template <class RNG> inline
std::vector<size_t> roulette_select(
    const std::vector<double>& fitnesses,
    RNG& rng,
    const size_t pop_size,
    const size_t elites=0) {

    const std::vector<double> upper_bounds = make_ubounds(fitnesses);
    const double sum_fitness = upper_bounds.back();

    std::vector<size_t> candidates(pop_size);
    std::iota(begin(candidates), end(candidates), 0);
    std::vector<size_t> children;
    children.reserve(pop_size * 1.1);

    // elite selection
    if (elites) {
        const size_t i = std::distance(
                begin(fitnesses),
                std::max_element(begin(fitnesses), end(fitnesses))
                );
        children.assign(elites, i);
    }

    // poisson selection
    const double num_fittest_children = pop_size / sum_fitness;
    for (size_t i=0; i<pop_size; ++i) {
        double expected = fitnesses[i];
        expected *= num_fittest_children;
        children.insert(children.end(),
                        std::poisson_distribution<size_t>(expected)(rng), i);
    }

    // roulette selection (slow)
    if (children.size() > pop_size) {
        std::shuffle(std::begin(children), std::end(children), rng);
        children.resize(pop_size);
    }
    else {
        std::uniform_real_distribution<double> uniform(0.0, sum_fitness);
        while (children.size() < pop_size) {
            children.push_back(throw_dart(upper_bounds, uniform(rng)));
        }
    }
    return children;
}

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
} // namespace wtl
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

#endif /* WTL_GENETIC_HPP_ */
<|endoftext|>


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

#include "mbed.h"
#include "rtos/rtos_idle.h"
#include "mbed_assert.h"

#define ALIGN_UP(pos, align) ((pos) % (align) ? (pos) +  ((align) - (pos) % (align)) : (pos))
MBED_STATIC_ASSERT(ALIGN_UP(0, 8) == 0, "ALIGN_UP macro error");
MBED_STATIC_ASSERT(ALIGN_UP(1, 8) == 8, "ALIGN_UP macro error");

#define ALIGN_DOWN(pos, align) ((pos) - ((pos) % (align)))
MBED_STATIC_ASSERT(ALIGN_DOWN(7, 8) == 0, "ALIGN_DOWN macro error");
MBED_STATIC_ASSERT(ALIGN_DOWN(8, 8) == 8, "ALIGN_DOWN macro error");

static void (*terminate_hook)(osThreadId_t id) = 0;
extern "C" void thread_terminate_hook(osThreadId_t id)
{
    if (terminate_hook != (void (*)(osThreadId_t))NULL) {
        terminate_hook(id);
    }
}

namespace rtos {

void Thread::constructor(osPriority priority,
        uint32_t stack_size, unsigned char *stack_mem, const char *name) {

    const uintptr_t unaligned_mem = reinterpret_cast<uintptr_t>(stack_mem);
    const uintptr_t aligned_mem = ALIGN_UP(unaligned_mem, 8);
    const uint32_t offset = aligned_mem - unaligned_mem;
    const uint32_t aligned_size = ALIGN_DOWN(stack_size - offset, 8);

    _tid = 0;
    _dynamic_stack = (stack_mem == NULL);
    _finished = false;
    memset(&_obj_mem, 0, sizeof(_obj_mem));
    memset(&_attr, 0, sizeof(_attr));
    _attr.priority = priority;
    _attr.stack_size = aligned_size;
    _attr.name = name ? name : "application_unnamed_thread";
    _attr.stack_mem = reinterpret_cast<uint32_t*>(aligned_mem);
}

void Thread::constructor(Callback<void()> task,
        osPriority priority, uint32_t stack_size, unsigned char *stack_mem, const char *name) {
    constructor(priority, stack_size, stack_mem, name);

    switch (start(task)) {
        case osErrorResource:
            error("OS ran out of threads!\n");
            break;
        case osErrorParameter:
            error("Thread already running!\n");
            break;
        case osErrorNoMemory:
            error("Error allocating the stack memory\n");
        default:
            break;
    }
}

osStatus Thread::start(Callback<void()> task) {
    _mutex.lock();

    if ((_tid != 0) || _finished) {
        _mutex.unlock();
        return osErrorParameter;
    }

    if (_attr.stack_mem == NULL) {
        _attr.stack_mem = new uint32_t[_attr.stack_size/sizeof(uint32_t)];
        MBED_ASSERT(_attr.stack_mem != NULL);
    }

    //Fill the stack with a magic word for maximum usage checking
    for (uint32_t i = 0; i < (_attr.stack_size / sizeof(uint32_t)); i++) {
        ((uint32_t *)_attr.stack_mem)[i] = 0xE25A2EA5;
    }

    memset(&_obj_mem, 0, sizeof(_obj_mem));
    _attr.cb_size = sizeof(_obj_mem);
    _attr.cb_mem = &_obj_mem;
    _task = task;
    _tid = osThreadNew(Thread::_thunk, this, &_attr);
    if (_tid == NULL) {
        if (_dynamic_stack) {
            delete[] (uint32_t *)(_attr.stack_mem);
            _attr.stack_mem = (uint32_t*)NULL;
        }
        _mutex.unlock();
        _join_sem.release();
        return osErrorResource;
    }

    _mutex.unlock();
    return osOK;
}

osStatus Thread::terminate() {
    osStatus_t ret = osOK;
    _mutex.lock();

    // Set the Thread's tid to NULL and
    // release the semaphore before terminating
    // since this thread could be terminating itself
    osThreadId_t local_id = _tid;
    _join_sem.release();
    _tid = (osThreadId_t)NULL;
    if (!_finished) {
        _finished = true;
        ret = osThreadTerminate(local_id);
    }
    _mutex.unlock();
    return ret;
}

osStatus Thread::join() {
    int32_t ret = _join_sem.wait();
    if (ret < 0) {
        return osError;
    }

    // The semaphore has been released so this thread is being
    // terminated or has been terminated. Once the mutex has
    // been locked it is ensured that the thread is deleted.
    _mutex.lock();
    MBED_ASSERT(NULL == _tid);
    _mutex.unlock();

    // Release sem so any other threads joining this thread wake up
    _join_sem.release();
    return osOK;
}

osStatus Thread::set_priority(osPriority priority) {
    osStatus_t ret;
    _mutex.lock();

    ret = osThreadSetPriority(_tid, priority);

    _mutex.unlock();
    return ret;
}

osPriority Thread::get_priority() {
    osPriority_t ret;
    _mutex.lock();

    ret = osThreadGetPriority(_tid);

    _mutex.unlock();
    return ret;
}

int32_t Thread::signal_set(int32_t flags) {
    return osThreadFlagsSet(_tid, flags);
}

Thread::State Thread::get_state() {
    uint8_t state = osThreadTerminated;

    _mutex.lock();

    if (_tid != NULL) {
#if defined(MBED_OS_BACKEND_RTX5)
        state = _obj_mem.state;
#else
        state = osThreadGetState(_tid);
#endif
    }

    _mutex.unlock();

    State user_state;

    switch(state) {
        case osThreadInactive:
            user_state = Inactive;
            break;
        case osThreadReady:
            user_state = Ready;
            break;
        case osThreadRunning:
            user_state = Running;
            break;
#if defined(MBED_OS_BACKEND_RTX5)
        case osRtxThreadWaitingDelay:
            user_state = WaitingDelay;
            break;
        case osRtxThreadWaitingJoin:
            user_state = WaitingJoin;
            break;
        case osRtxThreadWaitingThreadFlags:
            user_state = WaitingThreadFlag;
            break;
        case osRtxThreadWaitingEventFlags:
            user_state = WaitingEventFlag;
            break;
        case osRtxThreadWaitingMutex:
            user_state = WaitingMutex;
            break;
        case osRtxThreadWaitingSemaphore:
            user_state = WaitingSemaphore;
            break;
        case osRtxThreadWaitingMemoryPool:
            user_state = WaitingMemoryPool;
            break;
        case osRtxThreadWaitingMessageGet:
            user_state = WaitingMessageGet;
            break;
        case osRtxThreadWaitingMessagePut:
            user_state = WaitingMessagePut;
            break;
#endif
        case osThreadTerminated:
        default:
            user_state = Deleted;
            break;
    }

    return user_state;
}

uint32_t Thread::stack_size() {
    uint32_t size = 0;
    _mutex.lock();

    if (_tid != NULL) {
        size = osThreadGetStackSize(_tid);
    }

    _mutex.unlock();
    return size;
}

uint32_t Thread::free_stack() {
    uint32_t size = 0;
    _mutex.lock();

#if defined(MBED_OS_BACKEND_RTX5)
    if (_tid != NULL) {
        os_thread_t *thread = (os_thread_t *)_tid;
        size = (uint32_t)thread->sp - (uint32_t)thread->stack_mem;
    }
#endif

    _mutex.unlock();
    return size;
}

uint32_t Thread::used_stack() {
    uint32_t size = 0;
    _mutex.lock();

#if defined(MBED_OS_BACKEND_RTX5)
    if (_tid != NULL) {
        os_thread_t *thread = (os_thread_t *)_tid;
        size = ((uint32_t)thread->stack_mem + thread->stack_size) - thread->sp;
    }
#endif

    _mutex.unlock();
    return size;
}

uint32_t Thread::max_stack() {
    uint32_t size = 0;
    _mutex.lock();

    if (_tid != NULL) {
#if defined(MBED_OS_BACKEND_RTX5)
        os_thread_t *thread = (os_thread_t *)_tid;
        uint32_t high_mark = 0;
        while (((uint32_t *)(thread->stack_mem))[high_mark] == 0xE25A2EA5)
            high_mark++;
        size = thread->stack_size - (high_mark * sizeof(uint32_t));
#else
        size = osThreadGetStackSize(_tid) - osThreadGetStackSpace(_tid);
#endif
    }

    _mutex.unlock();
    return size;
}

const char *Thread::get_name() {
    return _attr.name;
}

int32_t Thread::signal_clr(int32_t flags) {
    return osThreadFlagsClear(flags);
}

osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) {
    uint32_t res;
    osEvent evt;
    uint32_t options = osFlagsWaitAll;
    if (signals == 0) {
        options = osFlagsWaitAny;
        signals = 0x7FFFFFFF;
    }
    res = osThreadFlagsWait(signals, options, millisec);
    if (res & osFlagsError) {
        switch (res) {
            case osFlagsErrorISR:
                evt.status = osErrorISR;
                break;
            case osFlagsErrorResource:
                evt.status = osOK;
                break;
            case osFlagsErrorTimeout:
                evt.status = (osStatus)osEventTimeout;
                break;
            case osFlagsErrorParameter:
            default:
                evt.status = (osStatus)osErrorValue;
                break;
        }
    } else {
        evt.status = (osStatus)osEventSignal;
        evt.value.signals = res;
    }

    return evt;
}

osStatus Thread::wait(uint32_t millisec) {
    return osDelay(millisec);
}

osStatus Thread::yield() {
    return osThreadYield();
}

osThreadId Thread::gettid() {
    return osThreadGetId();
}

void Thread::attach_idle_hook(void (*fptr)(void)) {
    rtos_attach_idle_hook(fptr);
}

void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id)) {
    terminate_hook = fptr;
}

Thread::~Thread() {
    // terminate is thread safe
    terminate();
    if (_dynamic_stack) {
        delete[] (uint32_t*)(_attr.stack_mem);
        _attr.stack_mem = (uint32_t*)NULL;
    }
}

void Thread::_thunk(void * thread_ptr)
{
    Thread *t = (Thread*)thread_ptr;
    t->_task();
    t->_mutex.lock();
    t->_tid = (osThreadId)NULL;
    t->_finished = true;
    t->_join_sem.release();
    // rtos will release the mutex automatically
}

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

#include "mbed.h"
#include "rtos/rtos_idle.h"
#include "mbed_assert.h"

#define ALIGN_UP(pos, align) ((pos) % (align) ? (pos) +  ((align) - (pos) % (align)) : (pos))
MBED_STATIC_ASSERT(ALIGN_UP(0, 8) == 0, "ALIGN_UP macro error");
MBED_STATIC_ASSERT(ALIGN_UP(1, 8) == 8, "ALIGN_UP macro error");

#define ALIGN_DOWN(pos, align) ((pos) - ((pos) % (align)))
MBED_STATIC_ASSERT(ALIGN_DOWN(7, 8) == 0, "ALIGN_DOWN macro error");
MBED_STATIC_ASSERT(ALIGN_DOWN(8, 8) == 8, "ALIGN_DOWN macro error");

static void (*terminate_hook)(osThreadId_t id) = 0;
extern "C" void thread_terminate_hook(osThreadId_t id)
{
    if (terminate_hook != (void (*)(osThreadId_t))NULL) {
        terminate_hook(id);
    }
}

namespace rtos {

void Thread::constructor(osPriority priority,
        uint32_t stack_size, unsigned char *stack_mem, const char *name) {

    const uintptr_t unaligned_mem = reinterpret_cast<uintptr_t>(stack_mem);
    const uintptr_t aligned_mem = ALIGN_UP(unaligned_mem, 8);
    const uint32_t offset = aligned_mem - unaligned_mem;
    const uint32_t aligned_size = ALIGN_DOWN(stack_size - offset, 8);

    _tid = 0;
    _dynamic_stack = (stack_mem == NULL);
    _finished = false;
    memset(&_obj_mem, 0, sizeof(_obj_mem));
    memset(&_attr, 0, sizeof(_attr));
    _attr.priority = priority;
    _attr.stack_size = aligned_size;
    _attr.name = name ? name : "application_unnamed_thread";
    _attr.stack_mem = reinterpret_cast<uint32_t*>(aligned_mem);
}

void Thread::constructor(Callback<void()> task,
        osPriority priority, uint32_t stack_size, unsigned char *stack_mem, const char *name) {
    constructor(priority, stack_size, stack_mem, name);

    switch (start(task)) {
        case osErrorResource:
            error("OS ran out of threads!\n");
            break;
        case osErrorParameter:
            error("Thread already running!\n");
            break;
        case osErrorNoMemory:
            error("Error allocating the stack memory\n");
        default:
            break;
    }
}

osStatus Thread::start(Callback<void()> task) {
    _mutex.lock();

    if ((_tid != 0) || _finished) {
        _mutex.unlock();
        return osErrorParameter;
    }

    if (_attr.stack_mem == NULL) {
        _attr.stack_mem = new uint32_t[_attr.stack_size/sizeof(uint32_t)];
        MBED_ASSERT(_attr.stack_mem != NULL);
    }

    //Fill the stack with a magic word for maximum usage checking
    for (uint32_t i = 0; i < (_attr.stack_size / sizeof(uint32_t)); i++) {
        ((uint32_t *)_attr.stack_mem)[i] = 0xE25A2EA5;
    }

    memset(&_obj_mem, 0, sizeof(_obj_mem));
    _attr.cb_size = sizeof(_obj_mem);
    _attr.cb_mem = &_obj_mem;
    _task = task;
    _tid = osThreadNew(Thread::_thunk, this, &_attr);
    if (_tid == NULL) {
        if (_dynamic_stack) {
            delete[] (uint32_t *)(_attr.stack_mem);
            _attr.stack_mem = (uint32_t*)NULL;
        }
        _mutex.unlock();
        _join_sem.release();
        return osErrorResource;
    }

    _mutex.unlock();
    return osOK;
}

osStatus Thread::terminate() {
    osStatus_t ret = osOK;
    _mutex.lock();

    // Set the Thread's tid to NULL and
    // release the semaphore before terminating
    // since this thread could be terminating itself
    osThreadId_t local_id = _tid;
    _join_sem.release();
    _tid = (osThreadId_t)NULL;
    if (!_finished) {
        _finished = true;
        // if local_id == 0 Thread was not started in first place
        // and does not have to be terminated
        if(local_id != 0) {
            ret = osThreadTerminate(local_id);
        }
    }
    _mutex.unlock();
    return ret;
}

osStatus Thread::join() {
    int32_t ret = _join_sem.wait();
    if (ret < 0) {
        return osError;
    }

    // The semaphore has been released so this thread is being
    // terminated or has been terminated. Once the mutex has
    // been locked it is ensured that the thread is deleted.
    _mutex.lock();
    MBED_ASSERT(NULL == _tid);
    _mutex.unlock();

    // Release sem so any other threads joining this thread wake up
    _join_sem.release();
    return osOK;
}

osStatus Thread::set_priority(osPriority priority) {
    osStatus_t ret;
    _mutex.lock();

    ret = osThreadSetPriority(_tid, priority);

    _mutex.unlock();
    return ret;
}

osPriority Thread::get_priority() {
    osPriority_t ret;
    _mutex.lock();

    ret = osThreadGetPriority(_tid);

    _mutex.unlock();
    return ret;
}

int32_t Thread::signal_set(int32_t flags) {
    return osThreadFlagsSet(_tid, flags);
}

Thread::State Thread::get_state() {
    uint8_t state = osThreadTerminated;

    _mutex.lock();

    if (_tid != NULL) {
#if defined(MBED_OS_BACKEND_RTX5)
        state = _obj_mem.state;
#else
        state = osThreadGetState(_tid);
#endif
    }

    _mutex.unlock();

    State user_state;

    switch(state) {
        case osThreadInactive:
            user_state = Inactive;
            break;
        case osThreadReady:
            user_state = Ready;
            break;
        case osThreadRunning:
            user_state = Running;
            break;
#if defined(MBED_OS_BACKEND_RTX5)
        case osRtxThreadWaitingDelay:
            user_state = WaitingDelay;
            break;
        case osRtxThreadWaitingJoin:
            user_state = WaitingJoin;
            break;
        case osRtxThreadWaitingThreadFlags:
            user_state = WaitingThreadFlag;
            break;
        case osRtxThreadWaitingEventFlags:
            user_state = WaitingEventFlag;
            break;
        case osRtxThreadWaitingMutex:
            user_state = WaitingMutex;
            break;
        case osRtxThreadWaitingSemaphore:
            user_state = WaitingSemaphore;
            break;
        case osRtxThreadWaitingMemoryPool:
            user_state = WaitingMemoryPool;
            break;
        case osRtxThreadWaitingMessageGet:
            user_state = WaitingMessageGet;
            break;
        case osRtxThreadWaitingMessagePut:
            user_state = WaitingMessagePut;
            break;
#endif
        case osThreadTerminated:
        default:
            user_state = Deleted;
            break;
    }

    return user_state;
}

uint32_t Thread::stack_size() {
    uint32_t size = 0;
    _mutex.lock();

    if (_tid != NULL) {
        size = osThreadGetStackSize(_tid);
    }

    _mutex.unlock();
    return size;
}

uint32_t Thread::free_stack() {
    uint32_t size = 0;
    _mutex.lock();

#if defined(MBED_OS_BACKEND_RTX5)
    if (_tid != NULL) {
        os_thread_t *thread = (os_thread_t *)_tid;
        size = (uint32_t)thread->sp - (uint32_t)thread->stack_mem;
    }
#endif

    _mutex.unlock();
    return size;
}

uint32_t Thread::used_stack() {
    uint32_t size = 0;
    _mutex.lock();

#if defined(MBED_OS_BACKEND_RTX5)
    if (_tid != NULL) {
        os_thread_t *thread = (os_thread_t *)_tid;
        size = ((uint32_t)thread->stack_mem + thread->stack_size) - thread->sp;
    }
#endif

    _mutex.unlock();
    return size;
}

uint32_t Thread::max_stack() {
    uint32_t size = 0;
    _mutex.lock();

    if (_tid != NULL) {
#if defined(MBED_OS_BACKEND_RTX5)
        os_thread_t *thread = (os_thread_t *)_tid;
        uint32_t high_mark = 0;
        while (((uint32_t *)(thread->stack_mem))[high_mark] == 0xE25A2EA5)
            high_mark++;
        size = thread->stack_size - (high_mark * sizeof(uint32_t));
#else
        size = osThreadGetStackSize(_tid) - osThreadGetStackSpace(_tid);
#endif
    }

    _mutex.unlock();
    return size;
}

const char *Thread::get_name() {
    return _attr.name;
}

int32_t Thread::signal_clr(int32_t flags) {
    return osThreadFlagsClear(flags);
}

osEvent Thread::signal_wait(int32_t signals, uint32_t millisec) {
    uint32_t res;
    osEvent evt;
    uint32_t options = osFlagsWaitAll;
    if (signals == 0) {
        options = osFlagsWaitAny;
        signals = 0x7FFFFFFF;
    }
    res = osThreadFlagsWait(signals, options, millisec);
    if (res & osFlagsError) {
        switch (res) {
            case osFlagsErrorISR:
                evt.status = osErrorISR;
                break;
            case osFlagsErrorResource:
                evt.status = osOK;
                break;
            case osFlagsErrorTimeout:
                evt.status = (osStatus)osEventTimeout;
                break;
            case osFlagsErrorParameter:
            default:
                evt.status = (osStatus)osErrorValue;
                break;
        }
    } else {
        evt.status = (osStatus)osEventSignal;
        evt.value.signals = res;
    }

    return evt;
}

osStatus Thread::wait(uint32_t millisec) {
    return osDelay(millisec);
}

osStatus Thread::yield() {
    return osThreadYield();
}

osThreadId Thread::gettid() {
    return osThreadGetId();
}

void Thread::attach_idle_hook(void (*fptr)(void)) {
    rtos_attach_idle_hook(fptr);
}

void Thread::attach_terminate_hook(void (*fptr)(osThreadId_t id)) {
    terminate_hook = fptr;
}

Thread::~Thread() {
    // terminate is thread safe
    terminate();
    if (_dynamic_stack) {
        delete[] (uint32_t*)(_attr.stack_mem);
        _attr.stack_mem = (uint32_t*)NULL;
    }
}

void Thread::_thunk(void * thread_ptr)
{
    Thread *t = (Thread*)thread_ptr;
    t->_task();
    t->_mutex.lock();
    t->_tid = (osThreadId)NULL;
    t->_finished = true;
    t->_join_sem.release();
    // rtos will release the mutex automatically
}

}
<|endoftext|>


<commit_before>
#include <SFML/Config.hpp>
#include <SFML/Graphics.hpp>
#include <sfeMovie/Movie.hpp>
#include <iostream>
#include <algorithm>

/*
 * Here is a little use sample for sfeMovie.
 * It'll open and display the movie specified by MOVIE_FILE above.
 *
 * This sample implements basic controls as follow:
 *  - Escape key to exit
 *  - Space key to play/pause the movie playback
 *  - S key to stop and go back to the beginning of the movie
 *  - F key to toggle between windowed and fullscreen mode
 *  - A key to select the next audio stream
 *  - V key to select the next video stream
 */

void my_pause()
{
#ifdef SFML_SYSTEM_WINDOWS
    system("PAUSE");
#endif
}

std::string StatusToString(sfe::Status status)
{
    switch (status)
    {
        case sfe::Stopped:  return "Stopped";
        case sfe::Paused:   return "Paused";
        case sfe::Playing:  return "Playing";
        default:            return "unknown status";
    }
}

std::string mediaTypeToString(sfe::MediaType type)
{
    switch (type)
    {
        case sfe::Audio:    return "audio";
        case sfe::Subtitle:    return "subtitle";
        case sfe::Video:    return "video";
        case sfe::Unknown:    return "unknown";
        default:            return "(null)";
    }
}

void drawControls(sf::RenderWindow& window, const sfe::Movie& movie)
{
    const int kHorizontalMargin = 10;
    const int kVerticalMargin = 10;
    const int kTimelineBackgroundHeight = 20;
    const int kTimelineInnerMargin = 4;

    sf::RectangleShape background(sf::Vector2f(window.getSize().x - 2 * kHorizontalMargin, kTimelineBackgroundHeight));
    background.setPosition(kHorizontalMargin, window.getSize().y - kTimelineBackgroundHeight - kVerticalMargin);
    background.setFillColor(sf::Color(0, 0, 0, 255/2));

    sf::RectangleShape border(sf::Vector2f(background.getSize().x - 2 * kTimelineInnerMargin, background.getSize().y - 2 * kTimelineInnerMargin));
    border.setPosition(background.getPosition().x + kTimelineInnerMargin, background.getPosition().y + kTimelineInnerMargin);
    border.setFillColor(sf::Color::Transparent);
    border.setOutlineColor(sf::Color::White);
    border.setOutlineThickness(1.0);

    float fprogress = movie.getPlayingOffset().asSeconds() / movie.getDuration().asSeconds();
    sf::RectangleShape progress(sf::Vector2f(1, border.getSize().y - 2 * border.getOutlineThickness()));
    progress.setPosition(border.getPosition().x + border.getOutlineThickness() + fprogress * (border.getSize().x - 2 * border.getOutlineThickness()), border.getPosition().y + border.getOutlineThickness());
    progress.setFillColor(sf::Color::White);

    window.draw(background);
    window.draw(border);
    window.draw(progress);
}

void printMovieInfo(const sfe::Movie& movie)
{
    std::cout << "Status: " << StatusToString(movie.getStatus()) << std::endl;
    std::cout << "Position: " << movie.getPlayingOffset().asSeconds() << "s" << std::endl;
    std::cout << "Duration: " << movie.getDuration().asSeconds() << "s" << std::endl;
    std::cout << "Size: " << movie.getSize().x << "x" << movie.getSize().y << std::endl;
    std::cout << "Framerate: " << movie.getFramerate() << " FPS (average)" << std::endl;
    std::cout << "Volume: " << movie.getVolume() << std::endl;
    std::cout << "Sample rate: " << movie.getSampleRate() << std::endl;
    std::cout << "Channel count: " << movie.getChannelCount() << std::endl;

    const sfe::Streams& videoStreams = movie.getStreams(sfe::Video);
    const sfe::Streams& audioStreams = movie.getStreams(sfe::Audio);
    const sfe::Streams& subtitleStreams = movie.getStreams(sfe::Subtitle);

    std::cout << videoStreams.size() + audioStreams.size() + subtitleStreams.size() << " streams found in the media" << std::endl;

    for (sfe::Streams::const_iterator it = videoStreams.begin(); it != videoStreams.end(); ++it)
    {
        std::cout << " #" << it->identifier << " : " << mediaTypeToString(it->type) << std::endl;
    }

    for (sfe::Streams::const_iterator it = audioStreams.begin(); it != audioStreams.end(); ++it)
    {
        std::cout << " #" << it->identifier << " : " << mediaTypeToString(it->type);

        if (!it->language.empty())
            std::cout << " (language: " << it->language << ")";
        std::cout << std::endl;
    }

    for (sfe::Streams::const_iterator it = subtitleStreams.begin(); it != subtitleStreams.end(); ++it)
    {
        std::cout << " #" << it->identifier << " : " << mediaTypeToString(it->type);

        if (!it->language.empty())
            std::cout << " (language: " << it->language << ")";
        std::cout << std::endl;
    }
}

int main(int argc, const char *argv[])
{
    if (argc < 2)
    {
        std::cout << "Usage: " << std::string(argv[0]) << " movie_path" << std::endl;
        my_pause();
        return 1;
    }

    std::string mediaFile = std::string(argv[1]);
    std::cout << "Going to open movie file \"" << mediaFile << "\"" << std::endl;

    sfe::Movie movie;
    if (!movie.openFromFile(mediaFile))
    {
        my_pause();
        return 1;
    }

    bool fullscreen = false;
    sf::VideoMode desktopMode = sf::VideoMode::getDesktopMode();
    int width = std::min((int)desktopMode.width, movie.getSize().x);
    int height = std::min((int)desktopMode.height, movie.getSize().y);

    // Create window
    sf::RenderWindow window(sf::VideoMode(width, height), "sfeMovie Player",
                            sf::Style::Close | sf::Style::Resize);
    movie.fit(0, 0, width, height);
    printMovieInfo(movie);

    // Allow stream selection
    const sfe::Streams& audioStreams = movie.getStreams(sfe::Audio);
    const sfe::Streams& videoStreams = movie.getStreams(sfe::Video);
    const sfe::Streams& subtitleStreams = movie.getStreams(sfe::Subtitle);
    int selectedVideoStreamId = 0;
    int selectedAudioStreamId = 0;
    int selectedSubtitleStreamId = 0;

    // Scale movie to the window drawing area and enable VSync
    window.setFramerateLimit(60);
    window.setVerticalSyncEnabled(true);
    movie.play();

    while (window.isOpen())
    {
        sf::Event ev;
        while (window.pollEvent(ev))
        {
            // Window closure
            if (ev.type == sf::Event::Closed ||
                (ev.type == sf::Event::KeyPressed &&
                 ev.key.code == sf::Keyboard::Escape))
            {
                window.close();
            }

            if (ev.type == sf::Event::KeyPressed)
            {
                if (ev.key.code == sf::Keyboard::Space)
                {
                    if (movie.getStatus() == sfe::Playing)
                    {
                        movie.pause();
                    }
                    else
                    {
                        movie.play();
                    }
                }
                else if (ev.key.code == sf::Keyboard::P)
                {
                    movie.stop();
                }
                else if (ev.key.code == sf::Keyboard::F)
                {
                    fullscreen = !fullscreen;

                    if (fullscreen)
                        window.create(desktopMode, "sfeMovie Player", sf::Style::Fullscreen);
                    else
                        window.create(sf::VideoMode(width, height), "sfeMovie Player",
                                      sf::Style::Close | sf::Style::Resize);

                    movie.fit(0, 0, window.getSize().x, window.getSize().y);
                }
                else if (ev.key.code == sf::Keyboard::I)
                {
                    printMovieInfo(movie);
                }
                else if (ev.key.code == sf::Keyboard::V)
                {
                    if (videoStreams.size() > 1)
                    {
                        selectedVideoStreamId++;
                        selectedVideoStreamId %= videoStreams.size();
                        movie.selectStream(videoStreams[selectedVideoStreamId]);
                        std::cout << "Selected video stream #" << videoStreams[selectedVideoStreamId].identifier
                        << std::endl;
                    }
                }
                else if (ev.key.code == sf::Keyboard::A)
                {
                    if (audioStreams.size() > 1)
                    {
                        selectedAudioStreamId++;
                        selectedAudioStreamId %= audioStreams.size();
                        movie.selectStream(audioStreams[selectedAudioStreamId]);
                        std::cout << "Selected audio stream #" << audioStreams[selectedAudioStreamId].identifier
                        << std::endl;
                    }
                }
                else if (ev.key.code == sf::Keyboard::S)
                {
                    if (subtitleStreams.size() > 0)
                    {
                        selectedSubtitleStreamId++;
                        selectedSubtitleStreamId %= subtitleStreams.size() + 1;

                        if (selectedSubtitleStreamId == subtitleStreams.size())
                        {
                            movie.selectStream(sfe::StreamDescriptor::NoSelection(sfe::Subtitle));
                            std::cout << "Unselected subtitle stream" << std::endl;
                        }
                        else
                        {
                            movie.selectStream(subtitleStreams[selectedSubtitleStreamId]);
                            std::cout << "Selected subtitle stream #" << subtitleStreams[selectedSubtitleStreamId].identifier
                            << std::endl;
                        }
                    }
                }
            }
            else if (ev.type == sf::Event::MouseWheelMoved)
            {
                float volume = movie.getVolume() + 10 * ev.mouseWheel.delta;
                volume = std::min(volume, 100.f);
                volume = std::max(volume, 0.f);
                movie.setVolume(volume);
            }
            else if (ev.type == sf::Event::Resized)
            {
                movie.fit(0, 0, window.getSize().x, window.getSize().y);
                window.setView(sf::View(sf::FloatRect(0, 0, window.getSize().x, window.getSize().y)));
            }
        }

        movie.update();

        // Render movie
        window.clear();
        window.draw(movie);
        drawControls(window, movie);
        window.display();
    }

    return 0;
}

<commit_msg>#7 Fix bug that requires pressing S twice to select the first subtitle stream<commit_after>
#include <SFML/Config.hpp>
#include <SFML/Graphics.hpp>
#include <sfeMovie/Movie.hpp>
#include <iostream>
#include <algorithm>

/*
 * Here is a little use sample for sfeMovie.
 * It'll open and display the movie specified by MOVIE_FILE above.
 *
 * This sample implements basic controls as follow:
 *  - Escape key to exit
 *  - Space key to play/pause the movie playback
 *  - S key to stop and go back to the beginning of the movie
 *  - F key to toggle between windowed and fullscreen mode
 *  - A key to select the next audio stream
 *  - V key to select the next video stream
 */

void my_pause()
{
#ifdef SFML_SYSTEM_WINDOWS
    system("PAUSE");
#endif
}

std::string StatusToString(sfe::Status status)
{
    switch (status)
    {
        case sfe::Stopped:  return "Stopped";
        case sfe::Paused:   return "Paused";
        case sfe::Playing:  return "Playing";
        default:            return "unknown status";
    }
}

std::string mediaTypeToString(sfe::MediaType type)
{
    switch (type)
    {
        case sfe::Audio:    return "audio";
        case sfe::Subtitle:    return "subtitle";
        case sfe::Video:    return "video";
        case sfe::Unknown:    return "unknown";
        default:            return "(null)";
    }
}

void drawControls(sf::RenderWindow& window, const sfe::Movie& movie)
{
    const int kHorizontalMargin = 10;
    const int kVerticalMargin = 10;
    const int kTimelineBackgroundHeight = 20;
    const int kTimelineInnerMargin = 4;

    sf::RectangleShape background(sf::Vector2f(window.getSize().x - 2 * kHorizontalMargin, kTimelineBackgroundHeight));
    background.setPosition(kHorizontalMargin, window.getSize().y - kTimelineBackgroundHeight - kVerticalMargin);
    background.setFillColor(sf::Color(0, 0, 0, 255/2));

    sf::RectangleShape border(sf::Vector2f(background.getSize().x - 2 * kTimelineInnerMargin, background.getSize().y - 2 * kTimelineInnerMargin));
    border.setPosition(background.getPosition().x + kTimelineInnerMargin, background.getPosition().y + kTimelineInnerMargin);
    border.setFillColor(sf::Color::Transparent);
    border.setOutlineColor(sf::Color::White);
    border.setOutlineThickness(1.0);

    float fprogress = movie.getPlayingOffset().asSeconds() / movie.getDuration().asSeconds();
    sf::RectangleShape progress(sf::Vector2f(1, border.getSize().y - 2 * border.getOutlineThickness()));
    progress.setPosition(border.getPosition().x + border.getOutlineThickness() + fprogress * (border.getSize().x - 2 * border.getOutlineThickness()), border.getPosition().y + border.getOutlineThickness());
    progress.setFillColor(sf::Color::White);

    window.draw(background);
    window.draw(border);
    window.draw(progress);
}

void printMovieInfo(const sfe::Movie& movie)
{
    std::cout << "Status: " << StatusToString(movie.getStatus()) << std::endl;
    std::cout << "Position: " << movie.getPlayingOffset().asSeconds() << "s" << std::endl;
    std::cout << "Duration: " << movie.getDuration().asSeconds() << "s" << std::endl;
    std::cout << "Size: " << movie.getSize().x << "x" << movie.getSize().y << std::endl;
    std::cout << "Framerate: " << movie.getFramerate() << " FPS (average)" << std::endl;
    std::cout << "Volume: " << movie.getVolume() << std::endl;
    std::cout << "Sample rate: " << movie.getSampleRate() << std::endl;
    std::cout << "Channel count: " << movie.getChannelCount() << std::endl;

    const sfe::Streams& videoStreams = movie.getStreams(sfe::Video);
    const sfe::Streams& audioStreams = movie.getStreams(sfe::Audio);
    const sfe::Streams& subtitleStreams = movie.getStreams(sfe::Subtitle);

    std::cout << videoStreams.size() + audioStreams.size() + subtitleStreams.size() << " streams found in the media" << std::endl;

    for (sfe::Streams::const_iterator it = videoStreams.begin(); it != videoStreams.end(); ++it)
    {
        std::cout << " #" << it->identifier << " : " << mediaTypeToString(it->type) << std::endl;
    }

    for (sfe::Streams::const_iterator it = audioStreams.begin(); it != audioStreams.end(); ++it)
    {
        std::cout << " #" << it->identifier << " : " << mediaTypeToString(it->type);

        if (!it->language.empty())
            std::cout << " (language: " << it->language << ")";
        std::cout << std::endl;
    }

    for (sfe::Streams::const_iterator it = subtitleStreams.begin(); it != subtitleStreams.end(); ++it)
    {
        std::cout << " #" << it->identifier << " : " << mediaTypeToString(it->type);

        if (!it->language.empty())
            std::cout << " (language: " << it->language << ")";
        std::cout << std::endl;
    }
}

int main(int argc, const char *argv[])
{
    if (argc < 2)
    {
        std::cout << "Usage: " << std::string(argv[0]) << " movie_path" << std::endl;
        my_pause();
        return 1;
    }

    std::string mediaFile = std::string(argv[1]);
    std::cout << "Going to open movie file \"" << mediaFile << "\"" << std::endl;

    sfe::Movie movie;
    if (!movie.openFromFile(mediaFile))
    {
        my_pause();
        return 1;
    }

    bool fullscreen = false;
    sf::VideoMode desktopMode = sf::VideoMode::getDesktopMode();
    int width = std::min((int)desktopMode.width, movie.getSize().x);
    int height = std::min((int)desktopMode.height, movie.getSize().y);

    // Create window
    sf::RenderWindow window(sf::VideoMode(width, height), "sfeMovie Player",
                            sf::Style::Close | sf::Style::Resize);
    movie.fit(0, 0, width, height);
    printMovieInfo(movie);

    // Allow stream selection
    const sfe::Streams& audioStreams = movie.getStreams(sfe::Audio);
    const sfe::Streams& videoStreams = movie.getStreams(sfe::Video);
    const sfe::Streams& subtitleStreams = movie.getStreams(sfe::Subtitle);
    int selectedVideoStreamId = 0;
    int selectedAudioStreamId = 0;
    int selectedSubtitleStreamId = -1; // No selected subtitle by default

    // Scale movie to the window drawing area and enable VSync
    window.setFramerateLimit(60);
    window.setVerticalSyncEnabled(true);
    movie.play();

    while (window.isOpen())
    {
        sf::Event ev;
        while (window.pollEvent(ev))
        {
            // Window closure
            if (ev.type == sf::Event::Closed ||
                (ev.type == sf::Event::KeyPressed &&
                 ev.key.code == sf::Keyboard::Escape))
            {
                window.close();
            }

            if (ev.type == sf::Event::KeyPressed)
            {
                if (ev.key.code == sf::Keyboard::Space)
                {
                    if (movie.getStatus() == sfe::Playing)
                    {
                        movie.pause();
                    }
                    else
                    {
                        movie.play();
                    }
                }
                else if (ev.key.code == sf::Keyboard::P)
                {
                    movie.stop();
                }
                else if (ev.key.code == sf::Keyboard::F)
                {
                    fullscreen = !fullscreen;

                    if (fullscreen)
                        window.create(desktopMode, "sfeMovie Player", sf::Style::Fullscreen);
                    else
                        window.create(sf::VideoMode(width, height), "sfeMovie Player",
                                      sf::Style::Close | sf::Style::Resize);

                    movie.fit(0, 0, window.getSize().x, window.getSize().y);
                }
                else if (ev.key.code == sf::Keyboard::I)
                {
                    printMovieInfo(movie);
                }
                else if (ev.key.code == sf::Keyboard::V)
                {
                    if (videoStreams.size() > 1)
                    {
                        selectedVideoStreamId++;
                        selectedVideoStreamId %= videoStreams.size();
                        movie.selectStream(videoStreams[selectedVideoStreamId]);
                        std::cout << "Selected video stream #" << videoStreams[selectedVideoStreamId].identifier
                        << std::endl;
                    }
                }
                else if (ev.key.code == sf::Keyboard::A)
                {
                    if (audioStreams.size() > 1)
                    {
                        selectedAudioStreamId++;
                        selectedAudioStreamId %= audioStreams.size();
                        movie.selectStream(audioStreams[selectedAudioStreamId]);
                        std::cout << "Selected audio stream #" << audioStreams[selectedAudioStreamId].identifier
                        << std::endl;
                    }
                }
                else if (ev.key.code == sf::Keyboard::S)
                {
                    if (subtitleStreams.size() > 0)
                    {
                        selectedSubtitleStreamId++;
                        selectedSubtitleStreamId %= subtitleStreams.size() + 1;

                        if (selectedSubtitleStreamId == subtitleStreams.size())
                        {
                            movie.selectStream(sfe::StreamDescriptor::NoSelection(sfe::Subtitle));
                            std::cout << "Unselected subtitle stream" << std::endl;
                        }
                        else
                        {
                            movie.selectStream(subtitleStreams[selectedSubtitleStreamId]);
                            std::cout << "Selected subtitle stream #" << subtitleStreams[selectedSubtitleStreamId].identifier
                            << std::endl;
                        }
                    }
                }
            }
            else if (ev.type == sf::Event::MouseWheelMoved)
            {
                float volume = movie.getVolume() + 10 * ev.mouseWheel.delta;
                volume = std::min(volume, 100.f);
                volume = std::max(volume, 0.f);
                movie.setVolume(volume);
            }
            else if (ev.type == sf::Event::Resized)
            {
                movie.fit(0, 0, window.getSize().x, window.getSize().y);
                window.setView(sf::View(sf::FloatRect(0, 0, window.getSize().x, window.getSize().y)));
            }
        }

        movie.update();

        // Render movie
        window.clear();
        window.draw(movie);
        drawControls(window, movie);
        window.display();
    }

    return 0;
}

<|endoftext|>