<commit_before>/*
 * This file is part of liblcf. Copyright (c) 2018 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include "lcf_options.h"
#include "rpg_actor.h"
#include "rpg_event.h"
#include "rpg_map.h"
#include "rpg_mapinfo.h"
#include "rpg_system.h"
#include "rpg_save.h"
#include "rpg_chipset.h"
#include "rpg_parameters.h"
#include "data.h"

void RPG::SaveActor::Setup(int actor_id) {
	const RPG::Actor& actor = Data::actors[actor_id - 1];
	ID = actor.ID;
	name = actor.name;
	title = actor.title;
	sprite_name = actor.character_name;
	sprite_id = actor.character_index;
	sprite_flags = actor.transparent ? 3 : 0;
	face_name = actor.face_name;
	face_id = actor.face_index;
	level = actor.initial_level;
	exp = 0;
	hp_mod = 0;
	sp_mod = 0;
	attack_mod = 0;
	defense_mod = 0;
	spirit_mod = 0;
	agility_mod = 0;
	skills_size = 0;
	skills.clear();
	equipped.clear();
	equipped.push_back(actor.initial_equipment.weapon_id);
	equipped.push_back(actor.initial_equipment.shield_id);
	equipped.push_back(actor.initial_equipment.armor_id);
	equipped.push_back(actor.initial_equipment.helmet_id);
	equipped.push_back(actor.initial_equipment.accessory_id);
	current_hp = 0;
	current_sp = 0;
	battle_commands.resize(7, -1);
	status_size = 0;
	status.clear();
	changed_battle_commands = false;
	class_id = -1;
	row = -1;
	two_weapon = actor.two_weapon;
	lock_equipment = actor.lock_equipment;
	auto_battle = actor.auto_battle;
	super_guard = actor.super_guard;
}

void RPG::SaveInventory::Setup() {
	party = Data::system.party;
	party_size = party.size();
}

void RPG::SaveMapEvent::Setup(const RPG::Event& event) {
	ID = event.ID;
	position_x = event.x;
	position_y = event.y;
}

void RPG::SaveMapInfo::Setup() {
	position_x = 0;
	position_y = 0;
	lower_tiles.resize(144);
	upper_tiles.resize(144);
	for (int i = 0; i < 144; i++) {
		lower_tiles[i] = i;
		upper_tiles[i] = i;
	}
}

void RPG::SaveMapInfo::Setup(const RPG::Map& map) {
	chipset_id = map.chipset_id;
	parallax_name = map.parallax_name;
	parallax_horz = map.parallax_loop_x;
	parallax_vert = map.parallax_loop_y;
	parallax_horz_auto = map.parallax_auto_loop_x;
	parallax_vert_auto = map.parallax_auto_loop_y;
	parallax_horz_speed = map.parallax_sx;
	parallax_vert_speed = map.parallax_sy;
}

void RPG::SaveSystem::Setup() {
	const RPG::System& system = Data::system;
	screen = 0;
	frame_count = 0;
	graphics_name = system.system_name;
	switches_size = Data::switches.size();
	switches.clear();
	switches.resize(switches_size);
	variables_size = Data::variables.size();
	variables.clear();
	variables.resize(variables_size);
	face_name = "";
	face_id = -1;
	face_right = false;
	face_flip = false;
	transparent = false;
	music_stopping = false;
	title_music = system.title_music;
	battle_music = system.battle_music;
	battle_end_music = system.battle_end_music;
	inn_music = system.inn_music;
	// current_music
	// unknown1_music FIXME
	// unknown2_music FIXME
	// stored_music
	boat_music = system.boat_music;
	ship_music = system.ship_music;
	airship_music = system.airship_music;
	gameover_music = system.gameover_music;
	cursor_se = system.cursor_se;
	decision_se = system.decision_se;
	cancel_se = system.cancel_se;
	buzzer_se = system.buzzer_se;
	battle_se = system.battle_se;
	escape_se = system.escape_se;
	enemy_attack_se = system.enemy_attack_se;
	enemy_damaged_se = system.enemy_damaged_se;
	actor_damaged_se = system.actor_damaged_se;
	dodge_se = system.dodge_se;
	enemy_death_se = system.enemy_death_se;
	item_se = system.item_se;
	transition_out = system.transition_out;
	transition_in = system.transition_in;
	battle_start_fadeout = system.battle_start_fadeout;
	battle_start_fadein = system.battle_start_fadein;
	battle_end_fadeout = system.battle_end_fadeout;
	battle_end_fadein = system.battle_end_fadein;
	message_stretch = system.message_stretch;
	font_id = system.font_id;
	teleport_allowed = true;
	escape_allowed = true;
	save_allowed = true;
	menu_allowed = true;
	background = "";
	save_count = 0;
	save_slot = -1;
}

void RPG::Save::Setup() {
	system.Setup();
	screen = RPG::SaveScreen();
	pictures.clear();
	pictures.resize(50);
	for (int i = 1; i <= (int)pictures.size(); i++) {
		pictures[i - 1].ID = i;
	}
	actors.clear();
	actors.resize(Data::actors.size());
	for (int i = 1; i <= (int) actors.size(); i++)
		actors[i - 1].Setup(i);
	map_info.Setup();
}

void RPG::Actor::Setup() {
	int max_final_level = 0;
	if (Data::system.ldb_id == 2003) {
		max_final_level = 99;
		if (final_level == -1) {
			final_level = max_final_level;
		}
		exp_base = exp_base == -1 ? 300 : exp_base;
		exp_inflation = exp_inflation == -1 ? 300 : exp_inflation;
	}
	else {
		max_final_level = 50;
		if (final_level == -1) {
			final_level = max_final_level;
		}
		exp_base = exp_base == -1 ? 30 : exp_base;
		exp_inflation = exp_inflation == -1 ? 30 : exp_inflation;
	}
	parameters.Setup(max_final_level);
}

void RPG::Chipset::Init() {
	terrain_data.resize(162, 1);
	passable_data_lower.resize(162, 15);
	passable_data_upper.resize(144, 15);
	passable_data_upper.front() = 31;
}

void RPG::System::Init() {
	party.resize(1, 1);
	menu_commands.resize(1, 1);
}

void RPG::Parameters::Setup(int final_level) {
	if (maxhp.size() < final_level) maxhp.resize(final_level, 1);
	if (maxsp.size() < final_level) maxsp.resize(final_level, 0);
	if (attack.size() < final_level) attack.resize(final_level, 1);
	if (defense.size() < final_level) defense.resize(final_level, 1);
	if (spirit.size() < final_level) spirit.resize(final_level, 1);
	if (agility.size() < final_level) agility.resize(final_level, 1);
}
<commit_msg>Correctly SaveVehicleLocation::vehicle<commit_after>/*
 * This file is part of liblcf. Copyright (c) 2018 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include "lcf_options.h"
#include "rpg_actor.h"
#include "rpg_event.h"
#include "rpg_map.h"
#include "rpg_mapinfo.h"
#include "rpg_system.h"
#include "rpg_save.h"
#include "rpg_chipset.h"
#include "rpg_parameters.h"
#include "data.h"

void RPG::SaveActor::Setup(int actor_id) {
	const RPG::Actor& actor = Data::actors[actor_id - 1];
	ID = actor.ID;
	name = actor.name;
	title = actor.title;
	sprite_name = actor.character_name;
	sprite_id = actor.character_index;
	sprite_flags = actor.transparent ? 3 : 0;
	face_name = actor.face_name;
	face_id = actor.face_index;
	level = actor.initial_level;
	exp = 0;
	hp_mod = 0;
	sp_mod = 0;
	attack_mod = 0;
	defense_mod = 0;
	spirit_mod = 0;
	agility_mod = 0;
	skills_size = 0;
	skills.clear();
	equipped.clear();
	equipped.push_back(actor.initial_equipment.weapon_id);
	equipped.push_back(actor.initial_equipment.shield_id);
	equipped.push_back(actor.initial_equipment.armor_id);
	equipped.push_back(actor.initial_equipment.helmet_id);
	equipped.push_back(actor.initial_equipment.accessory_id);
	current_hp = 0;
	current_sp = 0;
	battle_commands.resize(7, -1);
	status_size = 0;
	status.clear();
	changed_battle_commands = false;
	class_id = -1;
	row = -1;
	two_weapon = actor.two_weapon;
	lock_equipment = actor.lock_equipment;
	auto_battle = actor.auto_battle;
	super_guard = actor.super_guard;
}

void RPG::SaveInventory::Setup() {
	party = Data::system.party;
	party_size = party.size();
}

void RPG::SaveMapEvent::Setup(const RPG::Event& event) {
	ID = event.ID;
	position_x = event.x;
	position_y = event.y;
}

void RPG::SaveMapInfo::Setup() {
	position_x = 0;
	position_y = 0;
	lower_tiles.resize(144);
	upper_tiles.resize(144);
	for (int i = 0; i < 144; i++) {
		lower_tiles[i] = i;
		upper_tiles[i] = i;
	}
}

void RPG::SaveMapInfo::Setup(const RPG::Map& map) {
	chipset_id = map.chipset_id;
	parallax_name = map.parallax_name;
	parallax_horz = map.parallax_loop_x;
	parallax_vert = map.parallax_loop_y;
	parallax_horz_auto = map.parallax_auto_loop_x;
	parallax_vert_auto = map.parallax_auto_loop_y;
	parallax_horz_speed = map.parallax_sx;
	parallax_vert_speed = map.parallax_sy;
}

void RPG::SaveSystem::Setup() {
	const RPG::System& system = Data::system;
	screen = 0;
	frame_count = 0;
	graphics_name = system.system_name;
	switches_size = Data::switches.size();
	switches.clear();
	switches.resize(switches_size);
	variables_size = Data::variables.size();
	variables.clear();
	variables.resize(variables_size);
	face_name = "";
	face_id = -1;
	face_right = false;
	face_flip = false;
	transparent = false;
	music_stopping = false;
	title_music = system.title_music;
	battle_music = system.battle_music;
	battle_end_music = system.battle_end_music;
	inn_music = system.inn_music;
	// current_music
	// unknown1_music FIXME
	// unknown2_music FIXME
	// stored_music
	boat_music = system.boat_music;
	ship_music = system.ship_music;
	airship_music = system.airship_music;
	gameover_music = system.gameover_music;
	cursor_se = system.cursor_se;
	decision_se = system.decision_se;
	cancel_se = system.cancel_se;
	buzzer_se = system.buzzer_se;
	battle_se = system.battle_se;
	escape_se = system.escape_se;
	enemy_attack_se = system.enemy_attack_se;
	enemy_damaged_se = system.enemy_damaged_se;
	actor_damaged_se = system.actor_damaged_se;
	dodge_se = system.dodge_se;
	enemy_death_se = system.enemy_death_se;
	item_se = system.item_se;
	transition_out = system.transition_out;
	transition_in = system.transition_in;
	battle_start_fadeout = system.battle_start_fadeout;
	battle_start_fadein = system.battle_start_fadein;
	battle_end_fadeout = system.battle_end_fadeout;
	battle_end_fadein = system.battle_end_fadein;
	message_stretch = system.message_stretch;
	font_id = system.font_id;
	teleport_allowed = true;
	escape_allowed = true;
	save_allowed = true;
	menu_allowed = true;
	background = "";
	save_count = 0;
	save_slot = -1;
}

void RPG::Save::Setup() {
	system.Setup();
	screen = RPG::SaveScreen();
	pictures.clear();
	pictures.resize(50);
	for (int i = 1; i <= (int)pictures.size(); i++) {
		pictures[i - 1].ID = i;
	}
	actors.clear();
	actors.resize(Data::actors.size());
	for (int i = 1; i <= (int) actors.size(); i++)
		actors[i - 1].Setup(i);
	map_info.Setup();

	boat_location.vehicle = RPG::SaveVehicleLocation::VehicleType_skiff;
	ship_location.vehicle = RPG::SaveVehicleLocation::VehicleType_ship;
	airship_location.vehicle = RPG::SaveVehicleLocation::VehicleType_airship;
}

void RPG::Actor::Setup() {
	int max_final_level = 0;
	if (Data::system.ldb_id == 2003) {
		max_final_level = 99;
		if (final_level == -1) {
			final_level = max_final_level;
		}
		exp_base = exp_base == -1 ? 300 : exp_base;
		exp_inflation = exp_inflation == -1 ? 300 : exp_inflation;
	}
	else {
		max_final_level = 50;
		if (final_level == -1) {
			final_level = max_final_level;
		}
		exp_base = exp_base == -1 ? 30 : exp_base;
		exp_inflation = exp_inflation == -1 ? 30 : exp_inflation;
	}
	parameters.Setup(max_final_level);
}

void RPG::Chipset::Init() {
	terrain_data.resize(162, 1);
	passable_data_lower.resize(162, 15);
	passable_data_upper.resize(144, 15);
	passable_data_upper.front() = 31;
}

void RPG::System::Init() {
	party.resize(1, 1);
	menu_commands.resize(1, 1);
}

void RPG::Parameters::Setup(int final_level) {
	if (maxhp.size() < final_level) maxhp.resize(final_level, 1);
	if (maxsp.size() < final_level) maxsp.resize(final_level, 0);
	if (attack.size() < final_level) attack.resize(final_level, 1);
	if (defense.size() < final_level) defense.resize(final_level, 1);
	if (spirit.size() < final_level) spirit.resize(final_level, 1);
	if (agility.size() < final_level) agility.resize(final_level, 1);
}
<|endoftext|>


<commit_before>#include <nan.h>

#include <v8.h>

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include <algorithm>

extern "C" {
  #include "rpi_ws281x/ws2811.h"
}

using namespace v8;

#define DEFAULT_TARGET_FREQ     800000
#define DEFAULT_GPIO_PIN        18
#define DEFAULT_DMANUM          5

ws2811_t ledstring;
ws2811_channel_t
  channel0data,
  channel1data;

/**
 * exports.render(Uint32Array data) - sends the data to the LED-strip,
 *   if data is longer than the number of leds, remaining data will be ignored.
 *   Otherwise, data
 */
void render(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  if(info.Length() != 1) {
    Nan::ThrowTypeError("render(): missing argument.");
    return;
  }

  if(!node::Buffer::HasInstance(info[0])) {
    Nan::ThrowTypeError("render(): expected argument to be a Buffer.");
    return;
  }

  Local<Object> buffer = info[0]->ToObject();

  int numBytes = std::min((int)node::Buffer::Length(buffer),
      4 * ledstring.channel[0].count);

  uint32_t* data = (uint32_t*) node::Buffer::Data(buffer);
  memcpy(ledstring.channel[0].leds, data, numBytes);

  ws2811_wait(&ledstring);
  ws2811_render(&ledstring);

  info.GetReturnValue().SetUndefined();
}

/**
 * exports.init(Number ledCount [, Object config]) - setup the configuration and initialize the library.
 */
void init(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  ledstring.freq    = DEFAULT_TARGET_FREQ;
  ledstring.dmanum  = DEFAULT_DMANUM;

  channel0data.gpionum = DEFAULT_GPIO_PIN;
  channel0data.invert = 0;
  channel0data.count = 0;
  channel0data.brightness = 255;

  channel1data.gpionum = 0;
  channel1data.invert = 0;
  channel1data.count = 0;
  channel1data.brightness = 255;

  ledstring.channel[0] = channel0data;
  ledstring.channel[1] = channel1data;

  if(info.Length() < 1) {
    return Nan::ThrowTypeError("init(): expected at least 1 argument");
  }

  // first argument is a number
  if(!info[0]->IsNumber()) {
    return Nan::ThrowTypeError("init(): argument 0 is not a number");
  }

  ledstring.channel[0].count = info[0]->Int32Value();

  // second (optional) an Object
  if(info.Length() >= 2 && info[1]->IsObject()) {
    Local<Object> config = info[1]->ToObject();

    Local<String>
        symFreq = Nan::New<String>("frequency").ToLocalChecked(),
        symDmaNum = Nan::New<String>("dmaNum").ToLocalChecked(),
        symGpioPin = Nan::New<String>("gpioPin").ToLocalChecked(),
        symInvert = Nan::New<String>("invert").ToLocalChecked(),
        symBrightness = Nan::New<String>("brightness").ToLocalChecked();

    if(config->HasOwnProperty(symFreq)) {
      ledstring.freq = config->Get(symFreq)->Uint32Value();
    }

    if(config->HasOwnProperty(symDmaNum)) {
      ledstring.dmanum = config->Get(symDmaNum)->Int32Value();
    }

    if(config->HasOwnProperty(symGpioPin)) {
      ledstring.channel[0].gpionum = config->Get(symGpioPin)->Int32Value();
    }

    if(config->HasOwnProperty(symInvert)) {
      ledstring.channel[0].invert = config->Get(symInvert)->Int32Value();
    }

    if(config->HasOwnProperty(symBrightness)) {
      ledstring.channel[0].brightness = config->Get(symBrightness)->Int32Value();
    }
  }

  // FIXME: handle errors, throw JS-Exception
  int err = ws2811_init(&ledstring);

  if(err) {
      return Nan::ThrowError("init(): initialization failed. sorry – no idea why.");
  }
  info.GetReturnValue().SetUndefined();
}

/**
 * exports.setBrightness()
 */
void setBrightness(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  if(info.Length() != 1) {
      return Nan::ThrowError("setBrightness(): no value given");
  }

  // first argument is a number
  if(!info[0]->IsNumber()) {
    return Nan::ThrowTypeError("setBrightness(): argument 0 is not a number");
  }

  ledstring.channel[0].brightness = info[0]->Int32Value();

  info.GetReturnValue().SetUndefined();
}

/**
 * exports.reset() – blacks out the LED-strip and finalizes the library
 * (disable PWM, free DMA-pages etc).
 */
void reset(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  memset(ledstring.channel[0].leds, 0, sizeof(*ledstring.channel[0].leds) * ledstring.channel[0].count);

  ws2811_render(&ledstring);
  ws2811_wait(&ledstring);
  ws2811_fini(&ledstring);

  info.GetReturnValue().SetUndefined();
}

/**
 * initializes the module.
 */
void initialize(Handle<Object> exports) {
  NAN_EXPORT(exports, init);
  NAN_EXPORT(exports, reset);
  NAN_EXPORT(exports, render);
  NAN_EXPORT(exports, setBrightness);
}

NODE_MODULE(rpi_ws281x, initialize)

// vi: ts=2 sw=2 expandtab
<commit_msg>blind rewrite of native bindings<commit_after>#include <nan.h>

#include <v8.h>

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#include <algorithm>

extern "C" {
#include "rpi_ws281x/ws2811.h"
}

using namespace v8;

#define DEFAULT_TARGET_FREQ 800000
#define DEFAULT_GPIO_PIN 18
#define DEFAULT_DMANUM 5

#define PARAM_FREQ 1
#define PARAM_DMANUM 2
#define PARAM_GPIONUM 3
#define PARAM_COUNT 4
#define PARAM_INVERT 5
#define PARAM_BRIGHTNESS 6
#define PARAM_STRIP_TYPE 7

ws2811_t ws281x =
    {
        .freq = DEFAULT_TARGET_FREQ,
        .dmanum = DEFAULT_DMANUM,
        .channel =
            {
                [0] =
                    {
                        .gpionum = DEFAULT_GPIO_PIN,
                        .count = 0,
                        .invert = 0,
                        .brightness = 255,
                        .strip_type = 0,
                    },
                [1] =
                    {
                        .gpionum = 0,
                        .count = 0,
                        .invert = 0,
                        .brightness = 0,
                    },
            },
};

/**
 * ws281x.setParam(param:Number, value:Number)
 * wrap setting global params in ws2811_t
 */
void setParam(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  if (info.Length() != 2)
  {
    Nan::ThrowTypeError("setParam(): expected two params");
    return;
  }

  if (!info[0]->IsNumber())
  {
    Nan::ThrowTypeError("setParam(): expected argument 1 to be the parameter-id");
    return;
  }

  if (!info[1]->IsNumber())
  {
    Nan::ThrowTypeError("setParam(): expected argument 2 to be the value");
    return;
  }

  int param = info[0]->Int32Value();
  int value = info[1]->Int32Value();

  switch (param)
  {
  case PARAM_FREQ:
    ws281x.freq = value;
    break;
  case PARAM_DMANUM:
    ws281x.dmanum = value;
    break;

  default:
    Nan::ThrowTypeError("setParam(): invalid parameter-id");
    return;
  }

  info.GetReturnValue.SetUndefined();
}

/**
 * ws281x.setChannelParam(channel:Number, param:Number, value:Number)
 *
 * wrap setting params in ws2811_channel_t
 */
void setChannelParam(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  if (info.Length() != 3)
  {
    Nan::ThrowTypeError("setChannelParam(): missing argument");
    return;
  }

  // retrieve channelNumber from argument 1
  if (!info[0]->IsNumber())
  {
    Nan::ThrowTypeError("setChannelParam(): expected argument 1 to be the channel-number");
    return;
  }

  int channelNumber = info[0]->Int32Value();
  if (channelNumber > 1 || channelNumber < 0)
  {
    Nan::ThrowError("setChannelParam(): invalid chanel-number");
    return;
  }

  if (!info[1]->IsNumber())
  {
    Nan::ThrowTypeError("setChannelParam(): expected argument 2 to be the parameter-id");
    return;
  }

  if (!info[2]->IsNumber())
  {
    Nan::ThrowTypeError("setChannelParam(): expected argument 3 to be the value");
    return;
  }

  ws2811_channel_t channel = ws281x.channel[channelNumber];
  int param = info[1]->Int32Value();
  int value = info[2]->Int32Value();

  switch (param)
  {
  case PARAM_GPIONUM:
    channel.gpionum = value;
    break;
  case PARAM_COUNT:
    channel.count = value;
    break;
  case PARAM_INVERT:
    channel.invert = value;
    break;
  case PARAM_BRIGHTNESS:
    channel.brightness = (uint8_t)value;
    break;
  case PARAM_STRIP_TYPE:
    channel.strip_type = value;
    break;

  default:
    Nan::ThrowTypeError("setChannelParam(): invalid parameter-id");
    return;
  }

  info.GetReturnValue().SetUndefined();
}

/**
 * ws281x.setChannelData(channel:Number, buffer:Buffer)
 *
 * wrap copying data to ws2811_channel_t.leds
 */
void setChannelData(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  if (info.Length() != 2)
  {
    Nan::ThrowTypeError("setChannelData(): missing argument.");
    return;
  }

  // retrieve channelNumber from argument 1
  if (!info[0]->IsNumber())
  {
    Nan::ThrowTypeError("setChannelData(): expected argument 1 to be the channel-number.");
    return;
  }

  int channelNumber = info[0]->Int32Value();
  if (channelNumber > 1 || channelNumber < 0)
  {
    Nan::ThrowError("setChannelData(): invalid chanel-number");
    return;
  }
  ws2811_channel_t channel = ws281x.channel[channelNumber];

  // retrieve buffer from argument 2
  if (!node::Buffer::HasInstance(info[1]))
  {
    Nan::ThrowTypeError("setChannelData(): expected argument 2 to be a Buffer");
    return;
  }
  Local<Object> buffer = info[0]->ToObject();
  uint32_t *data = (uint32_t *)node::Buffer::Data(buffer);

  if (channel.count == 0 || channel.leds == NULL)
  {
    Nan::ThrowError("setChannelData(): channel not ready");
    return;
  }

  int numBytes = std::min(
      node::Buffer::Length(buffer),
      sizeof(ws2811_led_t) * ws281x.channel[0].count);

  memcpy(channel.leds, data, numBytes);

  info.GetReturnValue.SetUndefined();
}

/**
 * wrap ws2811_init()
 */
void init(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  ws2811_return_t ret;

  ret = ws2811_init(&ws281x);
  if (ret != WS2811_SUCCESS)
  {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  info.GetReturnValue.SetUndefined();
}

/**
 * wrap ws2811_wait() and ws2811_render()
 */
void render(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  ws2811_return_t ret;

  ret = ws2811_wait(&ws281x);
  if (ret != WS2811_SUCCESS)
  {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  ret = ws2811_render(&ws281x);
  if (ret != WS2811_SUCCESS)
  {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  info.GetReturnValue.SetUndefined();
}

/**
 * wrap ws2811_wait() and ws2811_fini()
 */
void finalize(const Nan::FunctionCallbackInfo<v8::Value> &info)
{
  ws2811_return_t ret;

  ret = ws2811_wait(&ws281x);
  if (ret != WS2811_SUCCESS)
  {
    Nan::ThrowError(ws2811_get_return_t_str(ret));
    return;
  }

  ws2811_fini(&ws281x);
  info.GetReturnValue.SetUndefined();
}

/**
 * initializes the module.
 */
void initialize(Local<Object> exports)
{
  NAN_EXPORT(exports, setParam);
  NAN_EXPORT(exports, setChannelParam);
  NAN_EXPORT(exports, setChannelData);
  NAN_EXPORT(exports, init);
  NAN_EXPORT(exports, render);
  NAN_EXPORT(exports, finalize);
}

NODE_MODULE(rpi_ws281x, initialize)

// vi: ts=2 sw=2 expandtab
<|endoftext|>


<commit_before>#include "scheduler.h"
#include "thread_state.h"
#include "util.h"
#include <future>
#include <thread>
#include <chrono>
#include <cassert>

using std::future;
using std::unique_lock;
using std::mutex;
using std::make_shared;
using std::make_unique;

class LocalThreadScheduler : public Scheduler
{
public:
  LocalThreadScheduler(uint num_threads_ = 0);

  void add_task(shared_ptr<LocalTask> t) override;

  /* blocks until all current tasks are complete. */
  void complete_pending() override;

  ~LocalThreadScheduler();

private:
  class SchedulerTask
  {
  public:
    virtual bool run(uint worker)
    {
      return false;
    }
    SchedulerTask() { }
  };

  class LocalTaskWrapper : public SchedulerTask
  {
  public:
    LocalTaskWrapper(shared_ptr<LocalTask> task_) : task(task_) { }

    bool run(uint worker) override
    {
      task->run(worker);
      return true;
    }

  private:
    shared_ptr<LocalTask> task;
  };

  static void worker(LocalThreadScheduler& sched, int worker_id);

  void add_task(shared_ptr<SchedulerTask> t);

  void on_task_started(int worker_id, const shared_ptr<SchedulerTask>& task);
  void on_task_completed(int worker_id, const shared_ptr<SchedulerTask>& task);

  std::queue<shared_ptr<SchedulerTask>> task_queue;
  std::mutex queue_mutex;
  std::atomic<int> pending_task_count;

  std::atomic<uint> num_threads_initialized;
  std::atomic<uint> num_threads_free;

  std::vector<std::thread> pool;
};

/**
 * The blocking scheduler is the baseline, stupid scheduler. It runs tasks as
 * soon as they are added, on the same thread.
 */
class BlockingScheduler : public Scheduler
{
public:
  BlockingScheduler()
  {
    register_thread();
  }

  void add_task(shared_ptr<LocalTask> t) override
  {
    t->run(0);
  }

  void complete_pending() override { }

  ~BlockingScheduler() { }
};

void LocalThreadScheduler::worker(LocalThreadScheduler& scheduler, int worker_id)
{
  bool keep_running = true;

  register_thread();
  ++scheduler.num_threads_initialized;

  while (keep_running)
  {
    int task_count = scheduler.pending_task_count;
    if (task_count == 0)
    {
      std::this_thread::yield();
      continue;
    }

    if (std::atomic_compare_exchange_weak(&scheduler.pending_task_count, &task_count, task_count - 1))
    {
      std::unique_lock<std::mutex> lock(scheduler.queue_mutex);

      auto task = scheduler.task_queue.front();
      scheduler.task_queue.pop();
      lock.unlock();

      scheduler.on_task_started(worker_id, task);
      keep_running = task->run(worker_id);
      scheduler.on_task_completed(worker_id, task);
    }
  }
}

LocalThreadScheduler::LocalThreadScheduler(uint num_threads_)
  : pending_task_count(0), num_threads_initialized(0)
{
  if (num_threads_ == 0)
    num_threads_ = num_system_procs();

  for (auto i = 0u; i < num_threads_; ++i)
    pool.emplace_back(LocalThreadScheduler::worker, std::ref(*this), i);

  num_threads_free = num_threads_;
}

void LocalThreadScheduler::add_task(shared_ptr<SchedulerTask> task)
{
  {
    unique_lock<std::mutex> lock(queue_mutex);
    task_queue.push(task);
  }
  ++pending_task_count;
}

void LocalThreadScheduler::add_task(shared_ptr<LocalTask> task)
{
  add_task(std::make_shared<LocalTaskWrapper>(task));
}

void LocalThreadScheduler::on_task_started(int worker_id, const shared_ptr<SchedulerTask>& task)
{
  --num_threads_free;
}

void LocalThreadScheduler::on_task_completed(int worker_id, const shared_ptr<SchedulerTask>& task)
{
  ++num_threads_free;
}

void LocalThreadScheduler::complete_pending()
{
  while (num_threads_initialized < pool.size());

  // wait for the queue to be empty
  while (pending_task_count > 0);

  // {
  //   unique_lock<std::mutex> queue_lock(queue_mutex, std::try_to_lock);

  //   if (queue_lock && task_queue.empty())
  //     break;
  // }

  // // wait for all of the threads to be free
  while (num_threads_free != pool.size())
    std::this_thread::yield();
  std::cerr << num_threads_free << ", " << pending_task_count << "\n";
}

LocalThreadScheduler::~LocalThreadScheduler()
{
  for (auto& thread: pool)
    add_task(std::make_shared<SchedulerTask>());

  for (auto& thread: pool)
    thread.join();
}

////////////////////////////////////////////////////////////////////////////////

unique_ptr<Scheduler> make_scheduler(uint num_threads)
{
  assert(num_threads > 0);
  if (num_threads == 1)
  {
    return make_unique<BlockingScheduler>();
  }
  else
  {
    return make_unique<LocalThreadScheduler>(num_threads);
  }
}
<commit_msg>scheduler comments/cleanup<commit_after>#include "scheduler.h"
#include "thread_state.h"
#include "util.h"
#include <future>
#include <thread>
#include <chrono>
#include <cassert>

using std::future;
using std::unique_lock;
using std::mutex;
using std::make_shared;
using std::make_unique;

class LocalThreadScheduler : public Scheduler
{
public:
  LocalThreadScheduler(uint num_threads_ = 0);

  void add_task(shared_ptr<LocalTask> t) override;

  /* blocks until all current tasks are complete. */
  void complete_pending() override;

  ~LocalThreadScheduler();

private:
  class SchedulerTask
  {
  public:
    virtual bool run(uint worker)
    {
      return false;
    }
    SchedulerTask() { }
  };

  class LocalTaskWrapper : public SchedulerTask
  {
  public:
    LocalTaskWrapper(shared_ptr<LocalTask> task_) : task(task_) { }

    bool run(uint worker) override
    {
      task->run(worker);
      return true;
    }

  private:
    shared_ptr<LocalTask> task;
  };

  static void worker(LocalThreadScheduler& sched, int worker_id);

  void add_task(shared_ptr<SchedulerTask> t);

  void on_task_started(int worker_id, const shared_ptr<SchedulerTask>& task);
  void on_task_completed(int worker_id, const shared_ptr<SchedulerTask>& task);

  std::queue<shared_ptr<SchedulerTask>> task_queue;
  std::mutex queue_mutex;
  std::atomic<int> pending_task_count;

  std::atomic<uint> num_threads_initialized;
  std::atomic<uint> num_threads_free;

  std::vector<std::thread> pool;
};

/**
 * The blocking scheduler is the baseline, stupid scheduler. It runs tasks as
 * soon as they are added, on the same thread.
 */
class BlockingScheduler : public Scheduler
{
public:
  BlockingScheduler()
  {
    register_thread();
  }

  void add_task(shared_ptr<LocalTask> t) override
  {
    t->run(0);
  }

  void complete_pending() override { }

  ~BlockingScheduler() { }
};

void LocalThreadScheduler::worker(LocalThreadScheduler& scheduler, int worker_id)
{
  bool keep_running = true;

  register_thread();
  ++scheduler.num_threads_initialized;

  while (keep_running)
  {
    int task_count = scheduler.pending_task_count;
    if (task_count == 0)
    {
      std::this_thread::yield();
      continue;
    }

    if (std::atomic_compare_exchange_weak(&scheduler.pending_task_count, &task_count, task_count - 1))
    {
      std::unique_lock<std::mutex> lock(scheduler.queue_mutex);

      auto task = scheduler.task_queue.front();
      scheduler.task_queue.pop();
      lock.unlock();

      scheduler.on_task_started(worker_id, task);
      keep_running = task->run(worker_id);
      scheduler.on_task_completed(worker_id, task);
    }
  }
}

LocalThreadScheduler::LocalThreadScheduler(uint num_threads_)
  : pending_task_count(0), num_threads_initialized(0)
{
  if (num_threads_ == 0)
    num_threads_ = num_system_procs();

  for (auto i = 0u; i < num_threads_; ++i)
    pool.emplace_back(LocalThreadScheduler::worker, std::ref(*this), i);

  num_threads_free = num_threads_;
}

void LocalThreadScheduler::add_task(shared_ptr<SchedulerTask> task)
{
  {
    unique_lock<std::mutex> lock(queue_mutex);
    task_queue.push(task);
  }
  ++pending_task_count;
}

void LocalThreadScheduler::add_task(shared_ptr<LocalTask> task)
{
  add_task(std::make_shared<LocalTaskWrapper>(task));
}

void LocalThreadScheduler::on_task_started(int worker_id, const shared_ptr<SchedulerTask>& task)
{
  --num_threads_free;
}

void LocalThreadScheduler::on_task_completed(int worker_id, const shared_ptr<SchedulerTask>& task)
{
  ++num_threads_free;
}

void LocalThreadScheduler::complete_pending()
{
  // wait for all threads to initialize
  while (num_threads_initialized < pool.size());

  // wait for the queue to be empty
  while (pending_task_count > 0);

  // wait for all of the threads to be free
  while (num_threads_free != pool.size())
    std::this_thread::yield();
}

LocalThreadScheduler::~LocalThreadScheduler()
{
  for (auto& thread: pool)
    add_task(std::make_shared<SchedulerTask>());

  for (auto& thread: pool)
    thread.join();
}

////////////////////////////////////////////////////////////////////////////////

unique_ptr<Scheduler> make_scheduler(uint num_threads)
{
  assert(num_threads > 0);
  if (num_threads == 1)
  {
    return make_unique<BlockingScheduler>();
  }
  else
  {
    return make_unique<LocalThreadScheduler>(num_threads);
  }
}
<|endoftext|>


<commit_before>#include "../../include/debug.h"
#include "../../include/sim/conver.h"
#include "../../include/sim/judge_worker.h"
#include "../../include/sim/problem_package.h"
#include "../../include/spawner.h"
#include "../../include/utilities.h"
#include "../../include/zip.h"
#include "default_checker_dump.h"

using std::string;
using std::vector;

namespace sim {

Conver::ConstructionResult Conver::constructSimfile(const Options& opts) {
	/* Load contents of the package */

	PackageContents pc;
	// Directory
	if (isDirectory(package_path_)) {
		throw_assert(package_path_.size() > 0);
		if (package_path_.back() != '/')
			package_path_ += '/';
		// From now on, package_path_ has trailing '/' iff it is a directory

		pc.load_from_directory(package_path_);

	// Zip archive
	} else
		pc.load_from_zip(package_path_);

	// Find master directory if exists
	StringView master_dir = pc.master_dir();

	auto exists_in_pkg = [&](StringView file) {
		return (not file.empty() and pc.exists(concat(master_dir, file)));
	};

	// "utils/" directory is ignored by Conver
	pc.remove_with_prefix(concat(master_dir, "utils/"));

	// Load the Simfile from the package
	Simfile sf;
	bool simfile_is_loaded = false;
	if (!opts.ignore_simfile && exists_in_pkg("Simfile")) {
		simfile_is_loaded = true;
		try {
			sf = Simfile(package_path_.back() == '/' ?
				getFileContents(concat(package_path_, master_dir, "Simfile")
					.to_cstr())
				: extract_file_from_zip(package_path_,
					concat(master_dir, "Simfile").to_cstr()));
		} catch (const ConfigFile::ParseError& e) {
			THROW(concat_tostr("(Simfile) ", e.what(), '\n', e.diagnostics()));
		}
	}

	// Name
	if (opts.name.size()) {
		sf.name = opts.name;
		if (verbose_)
			report_.append("Problem's name (specified in options): ", sf.name);
	} else {
		if (verbose_)
			report_.append("Problem's name is not specified in options -"
				" loading it from Simfile");
		sf.loadName();
		if (verbose_)
			report_.append("  name loaded from Simfile: ", sf.name);
	}

	// Label
	if (opts.label.size()) {
		sf.label = opts.label;
		if (verbose_)
			report_.append("Problem's label (specified in options): ",
				sf.label);
	} else {
		if (verbose_)
			report_.append("Problem's label is not specified in options -"
				" loading it from Simfile");
		try {
			sf.loadLabel();
			if (verbose_)
				report_.append("  label loaded from Simfile: ", sf.label);

		} catch (const std::exception& e) {
			if (verbose_)
				report_.append("  ", e.what(), " -> generating label from the"
					" problem's name");

			sf.label = shortenName(sf.name);
			if (verbose_)
				report_.append("  label generated from name: ", sf.label);
		}
	}

	auto is_source = [](StringView file) {
		return hasSuffixIn(file, {".c", ".cc", ".cpp", ".cxx"});
	};

	auto collect_files = [&pc](StringView prefix, auto&& cond) {
		vector<StringView> res;
		pc.for_each_with_prefix(prefix, [&](StringView file) {
			if (cond(file))
				res.emplace_back(file);
		});
		return res;
	};

	// Checker
	try { sf.loadChecker(); } catch (...) {}
	if (not exists_in_pkg(sf.checker)) {
		if (verbose_ && simfile_is_loaded)
			report_.append("Missing / invalid checker specified in the "
				"package's Simfile - searching for one");

		// Scan check/ directory
		auto x = collect_files(concat(master_dir, "check/"), is_source);
		if (x.size()) {
			sf.checker = x.front().substr(master_dir.size()).to_string();
			if (verbose_)
				report_.append("Chosen checker: ", sf.checker);
		// We have to put the checker in the package
		} else {
			if (verbose_)
				report_.append("No checker was found - placing the default"
					" checker");

			sf.checker = concat_tostr("check/checker.c");
			if (package_path_.back() == '/') {
				(void)mkdir(concat(package_path_, "check").to_cstr());
				putFileContents(
					concat(package_path_, master_dir, sf.checker).to_cstr(),
					(const char*)default_checker_c, default_checker_c_len);
			} else
				update_add_data_to_zip(
					{(const char*)default_checker_c, default_checker_c_len},
					concat(master_dir, sf.checker).to_cstr(), package_path_);
		}
	}

	// Exclude check/ directory from future searches
	pc.remove_with_prefix(concat(master_dir, "check/"));

	// Statement
	try { sf.loadStatement(); } catch (...) {}
	if (not exists_in_pkg(sf.statement)) {
		if (verbose_ && simfile_is_loaded)
			report_.append("Missing / invalid statement specified in the "
				"package's Simfile - searching for one");

		auto is_statement = [](StringView file) {
			return hasSuffixIn(file, {".pdf", ".html", ".htm", ".md", ".txt"});
		};

		// Scan doc/ directory
		auto x = collect_files(concat(master_dir, "doc/"), is_statement);
		if (x.empty())
			x = collect_files("", is_statement); // Scan whole directory tree

		// If there is no statement
		if (x.empty())
			THROW("No statement was found");

		// Prefer PDF to other formats
		auto it = find_if(x.begin(), x.end(),
			[](StringView s) { return hasSuffix(s, ".pdf"); });
		sf.statement = (it != x.end() ? *it : x.front())
			.substr(master_dir.size()).to_string();

		if (verbose_)
			report_.append("Chosen statement: ", sf.statement);
	}

	// Solutions
	try { sf.loadSolutions(); } catch (...) {}
	{
		vector<std::string> solutions;
		AVLDictSet<std::string> solutions_set; // Used to detect and eliminate
		                                // solutions duplication
		for (auto&& sol : sf.solutions) {
			if (exists_in_pkg(sol) && not solutions_set.find(sol)) {
				solutions.emplace_back(sol);
				solutions_set.emplace(sol);
			} else if (verbose_)
				report_.append("Ignoring invalid solution: `", sol, '`');
		}

		auto x = collect_files("", is_source);
		if (solutions.empty()) { // The main solution has to be set
			if (x.empty())
				THROW("No solution was found");

			// Choose the one with the shortest path to be the model solution
			std::swap(x.front(), *std::min_element(x.begin(), x.end(),
				[](auto&& a, auto&& b) {
					return a.size() < b.size();
				}));
		}

		// Merge solutions
		for (auto&& s : x) {
			s.removePrefix(master_dir.size());
			if (solutions_set.emplace(s.to_string()))
				solutions.emplace_back(s.to_string());
		}

		// Put the solutions into the Simfile
		sf.solutions = std::move(solutions);
	}

	// TODO: allow specifying scoring without limits
	//

	// Tests
	try { sf.loadTests(); } catch (...) {
		sf.tgroups.clear();
	}

	bool run_time_limits_setting = opts.force_auto_time_limits_setting &&
		opts.global_time_limit == 0;
	do {
		// If limits were loaded successfully
		if (sf.tgroups.size())
			try {
				sf.loadTestsFiles();
				break;
			} catch (...) {}

		auto ins = collect_files("",
			[](StringView file) { return hasSuffix(file, ".in"); });
		auto outs = collect_files("",
			[](StringView file) { return hasSuffix(file, ".out"); });

		AVLDictMap<string, string> in; // test name => path
		for (auto&& s : ins) {
			StringView name {s};
			name.removeSuffix(3);
			name = name.extractTrailing([](char c) { return (c != '/'); });
			in.emplace(name.to_string(),
				s.substr(master_dir.size()).to_string());
		}

		// Construct a vector of the valid tests
		vector<Simfile::Test> tests;
		{
			string name_s; // Placed here to save useless allocations
			for (auto&& s : outs) {
				StringView name {s};
				name.removeSuffix(4);
				name = name.extractTrailing([](char c) { return (c != '/'); });
				name_s.assign(name.begin(), name.end()); // Place in a string

				auto it = in.find(name_s);
				if (not it) // No matching .in file
					continue;

				tests.emplace_back(std::move(it->first), 0, 0);
				tests.back().in = std::move(it->second);
				tests.back().out = s.substr(master_dir.size()).to_string();
				// Now *it is not valid, so it's better to remove it
				in.erase(it->first);
			}
		}

		// Sort to speed up searching
		auto test_cmp = [](const Simfile::Test& a, const Simfile::Test& b) {
			return a.name < b.name;
		};
		sort(tests, test_cmp);

		// If there are tests limits specified, but we have to load tests' files
		if (sf.tgroups.size()) {
			for (auto&& group : sf.tgroups)
				for (auto&& test : group.tests) {
					auto it = binaryFind(tests, test, test_cmp);
					if (it == tests.end())
						THROW("Input and output files not found for the test `",
							test.name, '`');

					test.in = std::move(it->in);
					test.out = std::move(it->out);
				}

			break;
		}

		// There are no tests limits specified
		AVLDictMap<string, Simfile::TestGroup, StrNumCompare> tg; // gid => test
		for (auto&& t : tests) {
			auto p = Simfile::TestNameComparator::split(t.name);
			// tid == "ocen" belongs to the same group as tests with gid == "0"
			string gid = (p.second == "ocen" ? "0" : p.first.to_string()); //
			    // Needed (.to_string()) because since t is moved, p.first may
			    // not be valid
			tg[std::move(gid)].tests.emplace_back(std::move(t));
		}

		// Move tests groups from tg to sf.tgroups
		int groups_no = tg.size() - bool(tg.find("0"));
		int total_score = 100;
		tg.for_each([&](auto&& git) {
			// Take care of the scoring
			StringView x = git.first;
			x.removeLeading('0');
			if (git.first.size() && x.empty()) // We have to compare as numbers
				git.second.score = 0;
			else
				total_score -= (git.second.score = total_score / groups_no--);

			sf.tgroups.emplace_back(std::move(git.second));
		});

		// Take care of the time limit
		if (opts.global_time_limit == 0)
			run_time_limits_setting = true;

		// Take care of the memory limit
		if (opts.memory_limit == 0) {
			if (sf.global_mem_limit == 0)
				THROW("No memory limit is specified in both Simfile and"
					" options");

			for (auto&& g : sf.tgroups)
				for (auto&& t : g.tests)
					t.memory_limit = sf.global_mem_limit;
		}
	} while(false);

	// Overwrite the time limit
	if (opts.global_time_limit > 0)
		for (auto&& g : sf.tgroups)
			for (auto&& t : g.tests)
				t.time_limit = opts.global_time_limit;

	// Overwrite the memory limit
	if (opts.memory_limit > 0) {
		sf.global_mem_limit = opts.memory_limit << 20; // Convert from MB to
		                                               // bytes
			for (auto&& g : sf.tgroups)
				for (auto&& t : g.tests)
					t.memory_limit = sf.global_mem_limit;
	}

	if (!run_time_limits_setting) {
		normalize_time_limits(sf);
		// Nothing more to do
		return {Status::COMPLETE, std::move(sf), master_dir.to_string()};
	}

	/* The model solution's judge report is needed */

	// Set the time limits for the model solution
	for (auto&& g : sf.tgroups)
		for (auto&& t : g.tests)
			t.time_limit = MODEL_SOL_TLIMIT;

	return {Status::NEED_MODEL_SOLUTION_JUDGE_REPORT, std::move(sf),
		master_dir.to_string()};
}

void Conver::finishConstructingSimfile(Simfile &sf, const JudgeReport &jrep1,
	const JudgeReport &jrep2)
{
	// Map every test to its time limit
	AVLDictMap<string, uint64_t> tls; // test name => time limit
	for (auto ptr : {&jrep1, &jrep2}) {
		auto&& rep = *ptr;
		for (auto&& g : rep.groups)
			for (auto&& t : g.tests){
				// Only allow OK and WA to pass through
				if (!isIn(t.status,
					{JudgeReport::Test::OK, JudgeReport::Test::WA}))
				{
					THROW("Error on test `", t.name, "`: ", JudgeReport::Test::description(t.status));
				}

				tls[std::move(t.name)] = time_limit(t.runtime / 1e6) * 1e6;
			}
	}

	// Assign time limits to the tests
	for (auto&& tg : sf.tgroups)
		for (auto&& t : tg.tests)
			t.time_limit = tls[t.name];

	normalize_time_limits(sf);
}

} // namespace sim
<commit_msg>Fixed (provisionally) a bug in Conver<commit_after>#include "../../include/debug.h"
#include "../../include/sim/conver.h"
#include "../../include/sim/judge_worker.h"
#include "../../include/sim/problem_package.h"
#include "../../include/spawner.h"
#include "../../include/utilities.h"
#include "../../include/zip.h"
#include "default_checker_dump.h"

using std::string;
using std::vector;

namespace sim {

Conver::ConstructionResult Conver::constructSimfile(const Options& opts) {
	/* Load contents of the package */

	PackageContents pc;
	// Directory
	if (isDirectory(package_path_)) {
		throw_assert(package_path_.size() > 0);
		if (package_path_.back() != '/')
			package_path_ += '/';
		// From now on, package_path_ has trailing '/' iff it is a directory

		pc.load_from_directory(package_path_);

	// Zip archive
	} else
		pc.load_from_zip(package_path_);

	// Find master directory if exists
	InplaceBuff<PATH_MAX> master_dir_b; // Needed to avoid memory corruption as remove_with_prefix may reallocate the internal buffer of the pc
	// TODO: prevent such problems in the future
	master_dir_b.append(pc.master_dir());
	StringView master_dir = master_dir_b;

	auto exists_in_pkg = [&](StringView file) {
		return (not file.empty() and pc.exists(concat(master_dir, file)));
	};

	// "utils/" directory is ignored by Conver
	pc.remove_with_prefix(concat(master_dir, "utils/"));

	// Load the Simfile from the package
	Simfile sf;
	bool simfile_is_loaded = false;
	if (!opts.ignore_simfile && exists_in_pkg("Simfile")) {
		simfile_is_loaded = true;
		try {
			sf = Simfile(package_path_.back() == '/' ?
				getFileContents(concat(package_path_, master_dir, "Simfile")
					.to_cstr())
				: extract_file_from_zip(package_path_,
					concat(master_dir, "Simfile").to_cstr()));
		} catch (const ConfigFile::ParseError& e) {
			THROW(concat_tostr("(Simfile) ", e.what(), '\n', e.diagnostics()));
		}
	}

	// Name
	if (opts.name.size()) {
		sf.name = opts.name;
		if (verbose_)
			report_.append("Problem's name (specified in options): ", sf.name);
	} else {
		if (verbose_)
			report_.append("Problem's name is not specified in options -"
				" loading it from Simfile");
		sf.loadName();
		if (verbose_)
			report_.append("  name loaded from Simfile: ", sf.name);
	}

	// Label
	if (opts.label.size()) {
		sf.label = opts.label;
		if (verbose_)
			report_.append("Problem's label (specified in options): ",
				sf.label);
	} else {
		if (verbose_)
			report_.append("Problem's label is not specified in options -"
				" loading it from Simfile");
		try {
			sf.loadLabel();
			if (verbose_)
				report_.append("  label loaded from Simfile: ", sf.label);

		} catch (const std::exception& e) {
			if (verbose_)
				report_.append("  ", e.what(), " -> generating label from the"
					" problem's name");

			sf.label = shortenName(sf.name);
			if (verbose_)
				report_.append("  label generated from name: ", sf.label);
		}
	}

	auto is_source = [](StringView file) {
		return hasSuffixIn(file, {".c", ".cc", ".cpp", ".cxx"});
	};

	auto collect_files = [&pc](StringView prefix, auto&& cond) {
		vector<StringView> res;
		pc.for_each_with_prefix(prefix, [&](StringView file) {
			if (cond(file))
				res.emplace_back(file);
		});
		return res;
	};

	// Checker
	try { sf.loadChecker(); } catch (...) {}
	if (not exists_in_pkg(sf.checker)) {
		if (verbose_ && simfile_is_loaded)
			report_.append("Missing / invalid checker specified in the "
				"package's Simfile - searching for one");

		// Scan check/ directory
		auto x = collect_files(concat(master_dir, "check/"), is_source);
		if (x.size()) {
			sf.checker = x.front().substr(master_dir.size()).to_string();
			if (verbose_)
				report_.append("Chosen checker: ", sf.checker);
		// We have to put the checker in the package
		} else {
			if (verbose_)
				report_.append("No checker was found - placing the default"
					" checker");

			sf.checker = concat_tostr("check/checker.c");
			if (package_path_.back() == '/') {
				(void)mkdir(concat(package_path_, "check").to_cstr());
				putFileContents(
					concat(package_path_, master_dir, sf.checker).to_cstr(),
					(const char*)default_checker_c, default_checker_c_len);
			} else
				update_add_data_to_zip(
					{(const char*)default_checker_c, default_checker_c_len},
					concat(master_dir, sf.checker).to_cstr(), package_path_);
		}
	}

	// Exclude check/ directory from future searches
	pc.remove_with_prefix(concat(master_dir, "check/"));

	// Statement
	try { sf.loadStatement(); } catch (...) {}
	if (not exists_in_pkg(sf.statement)) {
		if (verbose_ && simfile_is_loaded)
			report_.append("Missing / invalid statement specified in the "
				"package's Simfile - searching for one");

		auto is_statement = [](StringView file) {
			return hasSuffixIn(file, {".pdf", ".html", ".htm", ".md", ".txt"});
		};

		// Scan doc/ directory
		auto x = collect_files(concat(master_dir, "doc/"), is_statement);
		if (x.empty())
			x = collect_files("", is_statement); // Scan whole directory tree

		// If there is no statement
		if (x.empty())
			THROW("No statement was found");

		// Prefer PDF to other formats
		auto it = find_if(x.begin(), x.end(),
			[](StringView s) { return hasSuffix(s, ".pdf"); });
		sf.statement = (it != x.end() ? *it : x.front())
			.substr(master_dir.size()).to_string();

		if (verbose_)
			report_.append("Chosen statement: ", sf.statement);
	}

	// Solutions
	try { sf.loadSolutions(); } catch (...) {}
	{
		vector<std::string> solutions;
		AVLDictSet<std::string> solutions_set; // Used to detect and eliminate
		                                // solutions duplication
		for (auto&& sol : sf.solutions) {
			if (exists_in_pkg(sol) && not solutions_set.find(sol)) {
				solutions.emplace_back(sol);
				solutions_set.emplace(sol);
			} else if (verbose_)
				report_.append("Ignoring invalid solution: `", sol, '`');
		}

		auto x = collect_files("", is_source);
		if (solutions.empty()) { // The main solution has to be set
			if (x.empty())
				THROW("No solution was found");

			// Choose the one with the shortest path to be the model solution
			std::swap(x.front(), *std::min_element(x.begin(), x.end(),
				[](auto&& a, auto&& b) {
					return a.size() < b.size();
				}));
		}

		// Merge solutions
		for (auto&& s : x) {
			s.removePrefix(master_dir.size());
			if (solutions_set.emplace(s.to_string()))
				solutions.emplace_back(s.to_string());
		}

		// Put the solutions into the Simfile
		sf.solutions = std::move(solutions);
	}

	// TODO: allow specifying scoring without limits
	//

	// Tests
	try { sf.loadTests(); } catch (...) {
		sf.tgroups.clear();
	}

	bool run_time_limits_setting = opts.force_auto_time_limits_setting &&
		opts.global_time_limit == 0;
	do {
		// If limits were loaded successfully
		if (sf.tgroups.size())
			try {
				sf.loadTestsFiles();
				break;
			} catch (...) {}

		auto ins = collect_files("",
			[](StringView file) { return hasSuffix(file, ".in"); });
		auto outs = collect_files("",
			[](StringView file) { return hasSuffix(file, ".out"); });

		AVLDictMap<string, string> in; // test name => path
		for (auto&& s : ins) {
			StringView name {s};
			name.removeSuffix(3);
			name = name.extractTrailing([](char c) { return (c != '/'); });
			in.emplace(name.to_string(),
				s.substr(master_dir.size()).to_string());
		}

		// Construct a vector of the valid tests
		vector<Simfile::Test> tests;
		{
			string name_s; // Placed here to save useless allocations
			for (auto&& s : outs) {
				StringView name {s};
				name.removeSuffix(4);
				name = name.extractTrailing([](char c) { return (c != '/'); });
				name_s.assign(name.begin(), name.end()); // Place in a string

				auto it = in.find(name_s);
				if (not it) // No matching .in file
					continue;

				tests.emplace_back(std::move(it->first), 0, 0);
				tests.back().in = std::move(it->second);
				tests.back().out = s.substr(master_dir.size()).to_string();
				// Now *it is not valid, so it's better to remove it
				in.erase(it->first);
			}
		}

		// Sort to speed up searching
		auto test_cmp = [](const Simfile::Test& a, const Simfile::Test& b) {
			return a.name < b.name;
		};
		sort(tests, test_cmp);

		// If there are tests limits specified, but we have to load tests' files
		if (sf.tgroups.size()) {
			for (auto&& group : sf.tgroups)
				for (auto&& test : group.tests) {
					auto it = binaryFind(tests, test, test_cmp);
					if (it == tests.end())
						THROW("Input and output files not found for the test `",
							test.name, '`');

					test.in = std::move(it->in);
					test.out = std::move(it->out);
				}

			break;
		}

		// There are no tests limits specified
		AVLDictMap<string, Simfile::TestGroup, StrNumCompare> tg; // gid => test
		for (auto&& t : tests) {
			auto p = Simfile::TestNameComparator::split(t.name);
			// tid == "ocen" belongs to the same group as tests with gid == "0"
			string gid = (p.second == "ocen" ? "0" : p.first.to_string()); //
			    // Needed (.to_string()) because since t is moved, p.first may
			    // not be valid
			tg[std::move(gid)].tests.emplace_back(std::move(t));
		}

		// Move tests groups from tg to sf.tgroups
		int groups_no = tg.size() - bool(tg.find("0"));
		int total_score = 100;
		tg.for_each([&](auto&& git) {
			// Take care of the scoring
			StringView x = git.first;
			x.removeLeading('0');
			if (git.first.size() && x.empty()) // We have to compare as numbers
				git.second.score = 0;
			else
				total_score -= (git.second.score = total_score / groups_no--);

			sf.tgroups.emplace_back(std::move(git.second));
		});

		// Take care of the time limit
		if (opts.global_time_limit == 0)
			run_time_limits_setting = true;

		// Take care of the memory limit
		if (opts.memory_limit == 0) {
			if (sf.global_mem_limit == 0)
				THROW("No memory limit is specified in both Simfile and"
					" options");

			for (auto&& g : sf.tgroups)
				for (auto&& t : g.tests)
					t.memory_limit = sf.global_mem_limit;
		}
	} while(false);

	// Overwrite the time limit
	if (opts.global_time_limit > 0)
		for (auto&& g : sf.tgroups)
			for (auto&& t : g.tests)
				t.time_limit = opts.global_time_limit;

	// Overwrite the memory limit
	if (opts.memory_limit > 0) {
		sf.global_mem_limit = opts.memory_limit << 20; // Convert from MB to
		                                               // bytes
			for (auto&& g : sf.tgroups)
				for (auto&& t : g.tests)
					t.memory_limit = sf.global_mem_limit;
	}

	if (!run_time_limits_setting) {
		normalize_time_limits(sf);
		// Nothing more to do
		return {Status::COMPLETE, std::move(sf), master_dir.to_string()};
	}

	/* The model solution's judge report is needed */

	// Set the time limits for the model solution
	for (auto&& g : sf.tgroups)
		for (auto&& t : g.tests)
			t.time_limit = MODEL_SOL_TLIMIT;

	return {Status::NEED_MODEL_SOLUTION_JUDGE_REPORT, std::move(sf),
		master_dir.to_string()};
}

void Conver::finishConstructingSimfile(Simfile &sf, const JudgeReport &jrep1,
	const JudgeReport &jrep2)
{
	// Map every test to its time limit
	AVLDictMap<string, uint64_t> tls; // test name => time limit
	for (auto ptr : {&jrep1, &jrep2}) {
		auto&& rep = *ptr;
		for (auto&& g : rep.groups)
			for (auto&& t : g.tests){
				// Only allow OK and WA to pass through
				if (!isIn(t.status,
					{JudgeReport::Test::OK, JudgeReport::Test::WA}))
				{
					THROW("Error on test `", t.name, "`: ", JudgeReport::Test::description(t.status));
				}

				tls[std::move(t.name)] = time_limit(t.runtime / 1e6) * 1e6;
			}
	}

	// Assign time limits to the tests
	for (auto&& tg : sf.tgroups)
		for (auto&& t : tg.tests)
			t.time_limit = tls[t.name];

	normalize_time_limits(sf);
}

} // namespace sim
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cmath>

#include "media/base/filter_host.h"
#include "media/filters/null_audio_renderer.h"

namespace media {

// How "long" our buffer should be in terms of milliseconds.  In OnInitialize
// we calculate the size of one second of audio data and use this number to
// allocate a buffer to pass to FillBuffer.
static const size_t kBufferSizeInMilliseconds = 100;

NullAudioRenderer::NullAudioRenderer()
    : AudioRendererBase(kDefaultMaxQueueSize),
      playback_rate_(0.0f),
      bytes_per_millisecond_(0),
      buffer_size_(0),
      thread_(NULL),
      shutdown_(false) {
}

NullAudioRenderer::~NullAudioRenderer() {
  Stop();
}

// static
bool NullAudioRenderer::IsMediaFormatSupported(
    const MediaFormat& media_format) {
  int channels;
  int sample_rate;
  int sample_bits;
  return ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits);
}

void NullAudioRenderer::SetPlaybackRate(float playback_rate) {
  playback_rate_ = playback_rate;
}

void NullAudioRenderer::SetVolume(float volume) {
  // Do nothing.
}

void NullAudioRenderer::ThreadMain() {
  // Loop until we're signaled to stop.
  while (!shutdown_) {
    float sleep_in_milliseconds = 0.0f;

    // Only consume buffers when actually playing.
    if (playback_rate_ > 0.0f)  {
      size_t bytes = FillBuffer(buffer_.get(), buffer_size_, playback_rate_);

      // Calculate our sleep duration, taking playback rate into consideration.
      sleep_in_milliseconds =
          floor(bytes / static_cast<float>(bytes_per_millisecond_));
      sleep_in_milliseconds /= playback_rate_;
    }

    PlatformThread::Sleep(static_cast<int>(sleep_in_milliseconds));
  }
}

bool NullAudioRenderer::OnInitialize(const MediaFormat& media_format) {
  // Parse out audio parameters.
  int channels;
  int sample_rate;
  int sample_bits;
  if (!ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits)) {
    return false;
  }

  // Calculate our bytes per millisecond value and allocate our buffer.
  bytes_per_millisecond_ = (channels * sample_rate * sample_bits / 8)
      / base::Time::kMillisecondsPerSecond;
  buffer_size_ = bytes_per_millisecond_ * kBufferSizeInMilliseconds;
  buffer_.reset(new uint8[buffer_size_]);
  DCHECK(buffer_.get());

  // It's safe to start the thread now because it simply sleeps when playback
  // rate is 0.0f.
  return PlatformThread::Create(0, this, &thread_);
}

void NullAudioRenderer::OnStop() {
  shutdown_ = true;
  if (thread_)
    PlatformThread::Join(thread_);
}

}  // namespace media
<commit_msg>Fixes bug where NullAudioRenderer would join a previously joined thread.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cmath>

#include "media/base/filter_host.h"
#include "media/filters/null_audio_renderer.h"

namespace media {

// How "long" our buffer should be in terms of milliseconds.  In OnInitialize
// we calculate the size of one second of audio data and use this number to
// allocate a buffer to pass to FillBuffer.
static const size_t kBufferSizeInMilliseconds = 100;

NullAudioRenderer::NullAudioRenderer()
    : AudioRendererBase(kDefaultMaxQueueSize),
      playback_rate_(0.0f),
      bytes_per_millisecond_(0),
      buffer_size_(0),
      thread_(NULL),
      shutdown_(false) {
}

NullAudioRenderer::~NullAudioRenderer() {
  Stop();
}

// static
bool NullAudioRenderer::IsMediaFormatSupported(
    const MediaFormat& media_format) {
  int channels;
  int sample_rate;
  int sample_bits;
  return ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits);
}

void NullAudioRenderer::SetPlaybackRate(float playback_rate) {
  playback_rate_ = playback_rate;
}

void NullAudioRenderer::SetVolume(float volume) {
  // Do nothing.
}

void NullAudioRenderer::ThreadMain() {
  // Loop until we're signaled to stop.
  while (!shutdown_) {
    float sleep_in_milliseconds = 0.0f;

    // Only consume buffers when actually playing.
    if (playback_rate_ > 0.0f)  {
      size_t bytes = FillBuffer(buffer_.get(), buffer_size_, playback_rate_);

      // Calculate our sleep duration, taking playback rate into consideration.
      sleep_in_milliseconds =
          floor(bytes / static_cast<float>(bytes_per_millisecond_));
      sleep_in_milliseconds /= playback_rate_;
    }

    PlatformThread::Sleep(static_cast<int>(sleep_in_milliseconds));
  }
}

bool NullAudioRenderer::OnInitialize(const MediaFormat& media_format) {
  // Parse out audio parameters.
  int channels;
  int sample_rate;
  int sample_bits;
  if (!ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits)) {
    return false;
  }

  // Calculate our bytes per millisecond value and allocate our buffer.
  bytes_per_millisecond_ = (channels * sample_rate * sample_bits / 8)
      / base::Time::kMillisecondsPerSecond;
  buffer_size_ = bytes_per_millisecond_ * kBufferSizeInMilliseconds;
  buffer_.reset(new uint8[buffer_size_]);
  DCHECK(buffer_.get());

  // It's safe to start the thread now because it simply sleeps when playback
  // rate is 0.0f.
  return PlatformThread::Create(0, this, &thread_);
}

void NullAudioRenderer::OnStop() {
  shutdown_ = true;
  if (thread_) {
    PlatformThread::Join(thread_);
    thread_ = NULL;
  }
}

}  // namespace media
<|endoftext|>


<commit_before>/*
  Copyright 2012-2015 David Robillard <http://drobilla.net>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
   @file pugl.hpp C++ API for Pugl, a minimal portable API for OpenGL.
*/

#ifndef PUGL_HPP_INCLUDED
#define PUGL_HPP_INCLUDED

#include "pugl/pugl.h"

/**
   @defgroup puglmm Puglmm
   C++ API wrapper for Pugl.
   @{
*/

namespace pugl {

class View {
public:
	View(int* pargc, char** argv)
		: _view(puglInit(pargc, argv))
	{
		puglSetHandle(_view, this);
		puglSetEventFunc(_view, _onEvent);
		puglSetCloseFunc(_view, _onClose);
		puglSetReshapeFunc(_view, _onReshape);
		puglSetDisplayFunc(_view, _onDisplay);
	}

	~View() { puglDestroy(_view); }

	virtual void initWindowParent(PuglNativeWindow parent) {
		puglInitWindowParent(_view, parent);
	}

	virtual void initWindowSize(int width, int height) {
		puglInitWindowSize(_view, width, height);
	}

	virtual void initWindowMinSize(int width, int height) {
		puglInitWindowMinSize(_view, width, height);
	}

	virtual void initWindowAspectRatio(int min_x, int min_y, int max_x, int max_y) {
		puglInitWindowAspectRatio(_view, min_x, min_y, max_x, max_y);
	}

	virtual void initResizable(bool resizable) {
		puglInitResizable(_view, resizable);
	}

	virtual void initTransientFor(uintptr_t parent) {
		puglInitTransientFor(_view, parent);
	}

	virtual void initContextType(PuglContextType type) {
		puglInitContextType(_view, type);
	}

	virtual void createWindow(const char* title) {
		puglCreateWindow(_view, title);
	}

	virtual void             showWindow()      { puglShowWindow(_view); }
	virtual void             hideWindow()      { puglHideWindow(_view); }
	virtual PuglNativeWindow getNativeWindow() { return puglGetNativeWindow(_view); }

	virtual void onEvent(const PuglEvent* event) {}
	virtual void onClose() {}
	virtual void onReshape(int width, int height) {}
	virtual void onDisplay() {}

	virtual void*      getContext()                 { return puglGetContext(_view); }
	virtual uint32_t   getEventTimestamp()          { return puglGetEventTimestamp(_view); }
	virtual int        getModifiers()               { return puglGetModifiers(_view); }
	virtual void       ignoreKeyRepeat(bool ignore) { puglIgnoreKeyRepeat(_view, ignore); }
	virtual void       grabFocus()                  { puglGrabFocus(_view); }
	virtual PuglStatus waitForEvent()               { return puglWaitForEvent(_view); }
	virtual PuglStatus processEvents()              { return puglProcessEvents(_view); }
	virtual void       postRedisplay()              { puglPostRedisplay(_view); }

	PuglView* cobj() { return _view; }

private:
	static void _onEvent(PuglView* view, const PuglEvent* event) {
		((View*)puglGetHandle(view))->onEvent(event);
	}
	static void _onClose(PuglView* view) {
		((View*)puglGetHandle(view))->onClose();
	}
	static void _onReshape(PuglView* view, int width, int height) {
		((View*)puglGetHandle(view))->onReshape(width, height);
	}
	static void _onDisplay(PuglView* view) {
		((View*)puglGetHandle(view))->onDisplay();
	}

	PuglView* _view;
};

} // namespace pugl

/**
   @}
*/

#endif  /* PUGL_HPP_INCLUDED */
<commit_msg>Make pugl::View destructor virtual<commit_after>/*
  Copyright 2012-2015 David Robillard <http://drobilla.net>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/**
   @file pugl.hpp C++ API for Pugl, a minimal portable API for OpenGL.
*/

#ifndef PUGL_HPP_INCLUDED
#define PUGL_HPP_INCLUDED

#include "pugl/pugl.h"

/**
   @defgroup puglmm Puglmm
   C++ API wrapper for Pugl.
   @{
*/

namespace pugl {

class View {
public:
	View(int* pargc, char** argv)
		: _view(puglInit(pargc, argv))
	{
		puglSetHandle(_view, this);
		puglSetEventFunc(_view, _onEvent);
		puglSetCloseFunc(_view, _onClose);
		puglSetReshapeFunc(_view, _onReshape);
		puglSetDisplayFunc(_view, _onDisplay);
	}

	virtual ~View() { puglDestroy(_view); }

	virtual void initWindowParent(PuglNativeWindow parent) {
		puglInitWindowParent(_view, parent);
	}

	virtual void initWindowSize(int width, int height) {
		puglInitWindowSize(_view, width, height);
	}

	virtual void initWindowMinSize(int width, int height) {
		puglInitWindowMinSize(_view, width, height);
	}

	virtual void initWindowAspectRatio(int min_x, int min_y, int max_x, int max_y) {
		puglInitWindowAspectRatio(_view, min_x, min_y, max_x, max_y);
	}

	virtual void initResizable(bool resizable) {
		puglInitResizable(_view, resizable);
	}

	virtual void initTransientFor(uintptr_t parent) {
		puglInitTransientFor(_view, parent);
	}

	virtual void initContextType(PuglContextType type) {
		puglInitContextType(_view, type);
	}

	virtual void createWindow(const char* title) {
		puglCreateWindow(_view, title);
	}

	virtual void             showWindow()      { puglShowWindow(_view); }
	virtual void             hideWindow()      { puglHideWindow(_view); }
	virtual PuglNativeWindow getNativeWindow() { return puglGetNativeWindow(_view); }

	virtual void onEvent(const PuglEvent* event) {}
	virtual void onClose() {}
	virtual void onReshape(int width, int height) {}
	virtual void onDisplay() {}

	virtual void*      getContext()                 { return puglGetContext(_view); }
	virtual uint32_t   getEventTimestamp()          { return puglGetEventTimestamp(_view); }
	virtual int        getModifiers()               { return puglGetModifiers(_view); }
	virtual void       ignoreKeyRepeat(bool ignore) { puglIgnoreKeyRepeat(_view, ignore); }
	virtual void       grabFocus()                  { puglGrabFocus(_view); }
	virtual PuglStatus waitForEvent()               { return puglWaitForEvent(_view); }
	virtual PuglStatus processEvents()              { return puglProcessEvents(_view); }
	virtual void       postRedisplay()              { puglPostRedisplay(_view); }

	PuglView* cobj() { return _view; }

private:
	static void _onEvent(PuglView* view, const PuglEvent* event) {
		((View*)puglGetHandle(view))->onEvent(event);
	}
	static void _onClose(PuglView* view) {
		((View*)puglGetHandle(view))->onClose();
	}
	static void _onReshape(PuglView* view, int width, int height) {
		((View*)puglGetHandle(view))->onReshape(width, height);
	}
	static void _onDisplay(PuglView* view) {
		((View*)puglGetHandle(view))->onDisplay();
	}

	PuglView* _view;
};

} // namespace pugl

/**
   @}
*/

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


<commit_before>#include "pel_entry.hpp"

#include <iostream>
#include <xyz/openbmc_project/Common/error.hpp>

namespace openpower
{
namespace pels
{

namespace common_error = sdbusplus::xyz::openbmc_project::Common::Error;

bool PELEntry::managementSystemAck(bool value)
{
    auto current = sdbusplus::org::open_power::Logging::PEL::server::Entry::
        managementSystemAck();
    if (value != current)
    {
        current = sdbusplus::org::open_power::Logging::PEL::server::Entry::
            managementSystemAck(value);

        Repository::LogID id{Repository::LogID::Obmc(getMyId())};
        if (auto logId = _repo->getLogID(id); logId.has_value())
        {
            // Update HMC acknowledge bit in PEL
            _repo->setPELHMCTransState(
                logId->pelID.id,
                (value ? TransmissionState::acked : TransmissionState::newPEL));
        }
        else
        {
            throw common_error::InvalidArgument();
        }
    }
    return current;
}

} // namespace pels
} // namespace openpower
<commit_msg>PEL: Remove unnecessary iostream include<commit_after>#include "pel_entry.hpp"

#include <xyz/openbmc_project/Common/error.hpp>

namespace openpower
{
namespace pels
{

namespace common_error = sdbusplus::xyz::openbmc_project::Common::Error;

bool PELEntry::managementSystemAck(bool value)
{
    auto current = sdbusplus::org::open_power::Logging::PEL::server::Entry::
        managementSystemAck();
    if (value != current)
    {
        current = sdbusplus::org::open_power::Logging::PEL::server::Entry::
            managementSystemAck(value);

        Repository::LogID id{Repository::LogID::Obmc(getMyId())};
        if (auto logId = _repo->getLogID(id); logId.has_value())
        {
            // Update HMC acknowledge bit in PEL
            _repo->setPELHMCTransState(
                logId->pelID.id,
                (value ? TransmissionState::acked : TransmissionState::newPEL));
        }
        else
        {
            throw common_error::InvalidArgument();
        }
    }
    return current;
}

} // namespace pels
} // namespace openpower
<|endoftext|>


<commit_before>/*
 * File:   VirtualJudger.cpp
 * Author: 51isoft
 *
 * Created on 2014年1月31日, 下午9:08
 */

#include "VirtualJudger.h"

const int VirtualJudger::MIN_SOURCE_LENGTH = 15;
const int VirtualJudger::SLEEP_INTERVAL = 10;

const int VirtualJudger::SUBMIT_NORMAL           = 0;
const int VirtualJudger::SUBMIT_SAME_CODE        = 1;
const int VirtualJudger::SUBMIT_INVALID_LANGUAGE = 2;
const int VirtualJudger::SUBMIT_COMPILE_ERROR    = 3;
const int VirtualJudger::SUBMIT_OTHER_ERROR      = 4;

/**
 * Basic constructor for virtual judger
 * @param _info JudgerInfo pointer
 */
VirtualJudger::VirtualJudger(JudgerInfo * _info) {
    info = _info;
    socket = new SocketHandler;
    tmpfilename = CONFIG->GetTmpfile_path() + info->GetId();
    cookiefilename = CONFIG->GetCookies_path() + info->GetId();
    logged_in = false;
}

VirtualJudger::~VirtualJudger() {
    delete socket;
}

/**
 * Generate special results with some default values
 * @param bott          Bott file to store results
 * @param result        Result
 */
void VirtualJudger::generateSpecialResult(Bott * bott, string result) {
    bott->Settype(RESULT_REPORT);
    bott->Settime_used("0");
    bott->Setmemory_used("0");
    bott->Setresult(result);
    bott->Setce_info("");
    bott->Setremote_runid("0");
}

/**
 * Send a submit to remote, and store the judge result
 * @param bott      Submit info
 * @param filename  File store the result
 */
void VirtualJudger::judge(Bott * bott, string filename) {
    // convert language
    if (language_table.find(bott->Getlanguage()) == language_table.end()) {
        throw Exception("Unsupported language.");
    }
    bott->Setlanguage(language_table[bott->Getlanguage()]);

    // login
    if (!logged_in) { // Not logged in, try login
        clearCookies();
        login();
        log("Logged in.");
        logged_in = true;
    }

    // submit
    int submit_status = submit(bott);
    if (submit_status == SUBMIT_OTHER_ERROR) {
        // first time fail, blame login status...
        log((string)"Submit error. Assume not logged in.");
        logged_in = false;
        clearCookies();
        login();
        log("Logged in.");
        logged_in = true;
        submit_status = submit(bott);
        if (submit_status == SUBMIT_OTHER_ERROR) {
            // second time fail, blame frequency
            log("Submit error. Assume should sleep for a while, sleeping " + intToString(VirtualJudger::SLEEP_INTERVAL) + " seconds.");
            sleep(VirtualJudger::SLEEP_INTERVAL);
            submit_status = submit(bott);
        }
    } else if (submit_status == SUBMIT_INVALID_LANGUAGE && info->GetOj() == "SPOJ" && bott->Getlanguage() == "41") {
        // Special HACK for Invalid Language on SPOJ, since it has two C++ type
        // And each of them covers a certain subset of problems
        bott->Setlanguage("1");
        submit_status = submit(bott);
    }
    if (submit_status != SUBMIT_OTHER_ERROR) log("Submitted.");

    // check submit status
    sleep(1); // sleep 1 second, just in case remote status table is not refreshed
    Bott * result;
    if (submit_status == SUBMIT_NORMAL) {
        // get status
        result = getStatus(bott);
        result->Setrunid(bott->Getrunid());
        if (result->Getresult() == "Compile Error") {
            try {
                result->Setce_info(getCEinfo(result));
            } catch (...) {
                log("Failed to get CE info, use empty one instead.");
                result->Setce_info("");
            }
        }
    } else {
        result = new Bott;
        result->Setrunid(bott->Getrunid());
        switch (submit_status) {
            case SUBMIT_SAME_CODE:
                generateSpecialResult(result, "Judge Error (Same Code)");
                break;
            case SUBMIT_INVALID_LANGUAGE:
                generateSpecialResult(result, "Judge Error (Invalid Language)");
                break;
            case SUBMIT_COMPILE_ERROR:
                generateSpecialResult(result, "Compile Error");
                break;
            default:
                log("Submit Error.");
                generateSpecialResult(result, "Judge Error");
        }
    }
    result->Setout_filename(filename);
    result->save();
    log("Done judging. Result: " + result->Getresult() + ", remote runid: " + result->Getremote_runid());
    delete result;
}

/**
 * Start virtual judger
 */
void VirtualJudger::run() {
    log("Judger started");
    while (true) {
        socket->receiveFile(tmpfilename);
        Bott * bott = new Bott(tmpfilename);
        log((string) "Received a new task, problem: " + bott->Getvid() + ".");
        string result_filename = Bott::RESULTS_DIRECTORY + bott->Getrunid();
        if (bott->Gettype() == NEED_JUDGE) {
            // Currently for vjudge, only NEED_JUDGE is supported
            try {
                if (bott->Getsrc().length() < MIN_SOURCE_LENGTH) {
                    // source code too short, may cause problem in remote OJ, such as PKU
                    bott->Setout_filename(result_filename);
                    generateSpecialResult(bott, "Compile Error");
                    bott->Setce_info("Source code too short, minimum length: " + intToString(MIN_SOURCE_LENGTH));
                    bott->save();
                } else {
                    judge(bott, result_filename);
                }
            } catch (Exception & e) {
                // Exception occurs, set to Judge Error
                log((string)"Judge error! Reason: " + e.what());

                // reuse bott file
                bott->Setout_filename(result_filename);
                generateSpecialResult(bott, "Judge Error");
                bott->save();
            } catch (exception & e) {
                // Exception occurs, set to Judge Error
                log((string)"Judge error! Reason: " + e.what());

                // reuse bott file
                bott->Setout_filename(result_filename);
                generateSpecialResult(bott, "Judge Error");
                bott->save();
            }
            delete bott;
        } else {
            delete bott;
            throw Exception("Type not supported.");
        }
        socket->sendFile(result_filename);
    }
}

/**
 * Log with judger identifier
 * @param message       Log message
 */
void VirtualJudger::log(string message) {
    LOG(message, info->GetId());
}

/**
 * Clear current cookies
 */
void VirtualJudger::clearCookies() {
    FILE * fp = fopen(cookiefilename.c_str(), "w");
    fclose(fp);
}

/**
 * Initialize curl pointer with common options
 */
void VirtualJudger::prepareCurl() {

    curl = curl_easy_init();
    if (!curl) {
        throw Exception("Curl init failed.");
    }

    // set basic curl options
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, CONFIG->GetMax_curl_time());
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, CONFIG->GetMax_curl_time());
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "bnuoj, curl");
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookiefilename.c_str());
    curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookiefilename.c_str());
}

/**
 * Execute curl, store the result in tmpfile, then cleanup curl
 */
void VirtualJudger::performCurl() {
    curl_file = fopen(tmpfilename.c_str(), "w");
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl_file);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);

    CURLcode curl_result = curl_easy_perform(curl);
    fclose(curl_file);
    if (curl_result != CURLE_OK) {
        throw Exception("Curl failed");
    }
    int http_code = 0;
    curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
    curl_easy_cleanup(curl);
    if (http_code >= 400) {
        throw Exception("Server failed, code: " + intToString(http_code));
    }
}

/**
 * Check whether the result is final
 * @param result        Current result
 * @return Is final one or not
 */
bool VirtualJudger::isFinalResult(string result) {
    result = trim(result);

    // Minimum length result is "Accept"
    if (result.length() < 6) return false;
    if (result.find("Waiting") != string::npos) return false;
    if (result.find("waiting") != string::npos) return false;
    if (result.find("Running") != string::npos) return false;
    if (result.find("running") != string::npos) return false;
    if (result.find("Judging") != string::npos) return false;
    if (result.find("judging") != string::npos) return false;
    if (result.find("Sent") != string::npos) return false;
    if (result.find("Queuing") != string::npos) return false;
    if (result.find("queue") != string::npos) return false;
    if (result.find("Compiling") != string::npos) return false;
    if (result.find("compiling") != string::npos) return false;
    if (result.find("Linking") != string::npos) return false;
    if (result.find("linking") != string::npos) return false;
    if (result.find("Received") != string::npos) return false;
    if (result.find("Pending") != string::npos) return false;
    if (result.find("pending") != string::npos) return false;

    return true;
}<commit_msg>add error details<commit_after>/*
 * File:   VirtualJudger.cpp
 * Author: 51isoft
 *
 * Created on 2014年1月31日, 下午9:08
 */

#include "VirtualJudger.h"

const int VirtualJudger::MIN_SOURCE_LENGTH = 15;
const int VirtualJudger::SLEEP_INTERVAL = 10;

const int VirtualJudger::SUBMIT_NORMAL           = 0;
const int VirtualJudger::SUBMIT_SAME_CODE        = 1;
const int VirtualJudger::SUBMIT_INVALID_LANGUAGE = 2;
const int VirtualJudger::SUBMIT_COMPILE_ERROR    = 3;
const int VirtualJudger::SUBMIT_OTHER_ERROR      = 4;

/**
 * Basic constructor for virtual judger
 * @param _info JudgerInfo pointer
 */
VirtualJudger::VirtualJudger(JudgerInfo * _info) {
    info = _info;
    socket = new SocketHandler;
    tmpfilename = CONFIG->GetTmpfile_path() + info->GetId();
    cookiefilename = CONFIG->GetCookies_path() + info->GetId();
    logged_in = false;
}

VirtualJudger::~VirtualJudger() {
    delete socket;
}

/**
 * Generate special results with some default values
 * @param bott          Bott file to store results
 * @param result        Result
 */
void VirtualJudger::generateSpecialResult(Bott * bott, string result) {
    bott->Settype(RESULT_REPORT);
    bott->Settime_used("0");
    bott->Setmemory_used("0");
    bott->Setresult(result);
    bott->Setce_info("");
    bott->Setremote_runid("0");
}

/**
 * Send a submit to remote, and store the judge result
 * @param bott      Submit info
 * @param filename  File store the result
 */
void VirtualJudger::judge(Bott * bott, string filename) {
    // convert language
    if (language_table.find(bott->Getlanguage()) == language_table.end()) {
        throw Exception("Unsupported language.");
    }
    bott->Setlanguage(language_table[bott->Getlanguage()]);

    // login
    if (!logged_in) { // Not logged in, try login
        clearCookies();
        login();
        log("Logged in.");
        logged_in = true;
    }

    // submit
    int submit_status = submit(bott);
    if (submit_status == SUBMIT_OTHER_ERROR) {
        // first time fail, blame login status...
        log((string)"Submit error. Assume not logged in.");
        logged_in = false;
        clearCookies();
        login();
        log("Logged in.");
        logged_in = true;
        submit_status = submit(bott);
        if (submit_status == SUBMIT_OTHER_ERROR) {
            // second time fail, blame frequency
            log("Submit error. Assume should sleep for a while, sleeping " + intToString(VirtualJudger::SLEEP_INTERVAL) + " seconds.");
            sleep(VirtualJudger::SLEEP_INTERVAL);
            submit_status = submit(bott);
        }
    } else if (submit_status == SUBMIT_INVALID_LANGUAGE && info->GetOj() == "SPOJ" && bott->Getlanguage() == "41") {
        // Special HACK for Invalid Language on SPOJ, since it has two C++ type
        // And each of them covers a certain subset of problems
        bott->Setlanguage("1");
        submit_status = submit(bott);
    }
    if (submit_status != SUBMIT_OTHER_ERROR) log("Submitted.");

    // check submit status
    sleep(1); // sleep 1 second, just in case remote status table is not refreshed
    Bott * result;
    if (submit_status == SUBMIT_NORMAL) {
        // get status
        result = getStatus(bott);
        result->Setrunid(bott->Getrunid());
        if (result->Getresult() == "Compile Error") {
            try {
                result->Setce_info(getCEinfo(result));
            } catch (...) {
                log("Failed to get CE info, use empty one instead.");
                result->Setce_info("");
            }
        }
    } else {
        result = new Bott;
        result->Setrunid(bott->Getrunid());
        switch (submit_status) {
            case SUBMIT_SAME_CODE:
                generateSpecialResult(result, "Judge Error (Same Code)");
                break;
            case SUBMIT_INVALID_LANGUAGE:
                generateSpecialResult(result, "Judge Error (Invalid Language)");
                break;
            case SUBMIT_COMPILE_ERROR:
                generateSpecialResult(result, "Compile Error");
                break;
            default:
                log("Submit Error.");
                generateSpecialResult(result, "Judge Error");
        }
    }
    result->Setout_filename(filename);
    result->save();
    log("Done judging. Result: " + result->Getresult() + ", remote runid: " + result->Getremote_runid());
    delete result;
}

/**
 * Start virtual judger
 */
void VirtualJudger::run() {
    log("Judger started");
    while (true) {
        socket->receiveFile(tmpfilename);
        Bott * bott = new Bott(tmpfilename);
        log((string) "Received a new task, problem: " + bott->Getvid() + ".");
        string result_filename = Bott::RESULTS_DIRECTORY + bott->Getrunid();
        if (bott->Gettype() == NEED_JUDGE) {
            // Currently for vjudge, only NEED_JUDGE is supported
            try {
                if (bott->Getsrc().length() < MIN_SOURCE_LENGTH) {
                    // source code too short, may cause problem in remote OJ, such as PKU
                    bott->Setout_filename(result_filename);
                    generateSpecialResult(bott, "Compile Error");
                    bott->Setce_info("Source code too short, minimum length: " + intToString(MIN_SOURCE_LENGTH));
                    bott->save();
                } else {
                    judge(bott, result_filename);
                }
            } catch (Exception & e) {
                // Exception occurs, set to Judge Error
                log((string)"Judge error! Reason: " + e.what());

                // reuse bott file
                bott->Setout_filename(result_filename);
                generateSpecialResult(bott, "Judge Error");
                bott->save();
            } catch (exception & e) {
                // Exception occurs, set to Judge Error
                log((string)"Judge error! Reason: " + e.what());

                // reuse bott file
                bott->Setout_filename(result_filename);
                generateSpecialResult(bott, "Judge Error");
                bott->save();
            }
            delete bott;
        } else {
            delete bott;
            throw Exception("Type not supported.");
        }
        socket->sendFile(result_filename);
    }
}

/**
 * Log with judger identifier
 * @param message       Log message
 */
void VirtualJudger::log(string message) {
    LOG(message, info->GetId());
}

/**
 * Clear current cookies
 */
void VirtualJudger::clearCookies() {
    FILE * fp = fopen(cookiefilename.c_str(), "w");
    fclose(fp);
}

/**
 * Initialize curl pointer with common options
 */
void VirtualJudger::prepareCurl() {

    curl = curl_easy_init();
    if (!curl) {
        throw Exception("Curl init failed.");
    }

    // set basic curl options
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, CONFIG->GetMax_curl_time());
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, CONFIG->GetMax_curl_time());
    curl_easy_setopt(curl, CURLOPT_USERAGENT, "bnuoj, curl");
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookiefilename.c_str());
    curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookiefilename.c_str());
}

/**
 * Execute curl, store the result in tmpfile, then cleanup curl
 */
void VirtualJudger::performCurl() {
    curl_file = fopen(tmpfilename.c_str(), "w");
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl_file);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);

    CURLcode curl_result = curl_easy_perform(curl);
    fclose(curl_file);
    if (curl_result != CURLE_OK) {
        throw Exception((string)"Curl failed, reason: " + curl_easy_strerror(curl_result));
    }
    int http_code = 0;
    curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code);
    curl_easy_cleanup(curl);
    if (http_code >= 400) {
        throw Exception("Server failed, code: " + intToString(http_code));
    }
}

/**
 * Check whether the result is final
 * @param result        Current result
 * @return Is final one or not
 */
bool VirtualJudger::isFinalResult(string result) {
    result = trim(result);

    // Minimum length result is "Accept"
    if (result.length() < 6) return false;
    if (result.find("Waiting") != string::npos) return false;
    if (result.find("waiting") != string::npos) return false;
    if (result.find("Running") != string::npos) return false;
    if (result.find("running") != string::npos) return false;
    if (result.find("Judging") != string::npos) return false;
    if (result.find("judging") != string::npos) return false;
    if (result.find("Sent") != string::npos) return false;
    if (result.find("Queuing") != string::npos) return false;
    if (result.find("queue") != string::npos) return false;
    if (result.find("Compiling") != string::npos) return false;
    if (result.find("compiling") != string::npos) return false;
    if (result.find("Linking") != string::npos) return false;
    if (result.find("linking") != string::npos) return false;
    if (result.find("Received") != string::npos) return false;
    if (result.find("Pending") != string::npos) return false;
    if (result.find("pending") != string::npos) return false;

    return true;
}<|endoftext|>