<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <NDK/Entity.hpp>
#include <NDK/BaseComponent.hpp>
#include <NDK/World.hpp>

namespace Ndk
{
	/*!
	* \ingroup NDK
	* \class Ndk::Entity
	* \brief NDK class that represents an entity in a world
	*/

	/*!
	* \brief Constructs a Entity object by move semantic
	*
	* \param entity Entity to move into this
	*/

	Entity::Entity(Entity&& entity) :
	HandledObject(std::move(entity)),
	m_components(std::move(entity.m_components)),
	m_componentBits(std::move(entity.m_componentBits)),
	m_systemBits(std::move(entity.m_systemBits)),
	m_id(entity.m_id),
	m_world(entity.m_world),
	m_enabled(entity.m_enabled),
	m_valid(entity.m_valid)
	{
	}

	/*!
	* \brief Constructs a Entity object linked to a world and with an id
	*
	* \param world World in which the entity interact
	* \param id Identifier of the entity
	*/

	Entity::Entity(World* world, EntityId id) :
	m_id(id),
	m_world(world)
	{
	}

	/*!
	* \brief Destructs the object and calls Destroy
	*
	* \see Destroy
	*/

	Entity::~Entity()
	{
		Destroy();
	}

	/*!
	* \brief Adds a component to the entity
	* \return A reference to the newly added component
	*
	* \param componentPtr Component to add to the entity
	*
	* \remark Produces a NazaraAssert if component is nullptr
	*/

	BaseComponent& Entity::AddComponent(std::unique_ptr<BaseComponent>&& componentPtr)
	{
		NazaraAssert(componentPtr, "Component must be valid");

		ComponentIndex index = componentPtr->GetIndex();

		// We ensure that the vector has enough space
		if (index >= m_components.size())
			m_components.resize(index + 1);

		// Affectation and return of the component
		m_components[index] = std::move(componentPtr);
		m_componentBits.UnboundedSet(index);
		m_removedComponentBits.UnboundedReset(index);

		Invalidate();

		// We get the new component and we alert other existing components of the new one
		BaseComponent& component = *m_components[index].get();
		component.SetEntity(this);

		for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
		{
			if (i != index)
				m_components[i]->OnComponentAttached(component);
		}

		return component;
	}

	/*!
	* \brief Clones the entity
	* \return The clone newly created
	*
	* \remark The close is enable by default, even if the original is disabled
	* \remark Produces a NazaraAssert if the entity is not valid
	*/

	const EntityHandle& Entity::Clone() const
	{
		NazaraAssert(IsValid(), "Invalid entity");

		return m_world->CloneEntity(m_id);
	}

	/*!
	* \brief Kills the entity
	*/

	void Entity::Kill()
	{
		m_world->KillEntity(this);
	}

	/*!
	* \brief Invalidates the entity
	*/

	void Entity::Invalidate()
	{
		// We alert everyone that we have been updated
		m_world->Invalidate(m_id);
	}

	/*!
	* \brief Creates the entity
	*/

	void Entity::Create()
	{
		m_enabled = true;
		m_valid = true;
	}

	/*!
	* \brief Destroys the entity
	*/

	void Entity::Destroy()
	{
		// We alert each system
		for (std::size_t index = m_systemBits.FindFirst(); index != m_systemBits.npos; index = m_systemBits.FindNext(index))
		{
			auto sysIndex = static_cast<Ndk::SystemIndex>(index);

			if (m_world->HasSystem(sysIndex))
			{
				BaseSystem& system = m_world->GetSystem(sysIndex);
				system.RemoveEntity(this);
			}
		}
		m_systemBits.Clear();

		UnregisterAllHandles();

		m_components.clear();
		m_componentBits.Reset();

		m_valid = false;
	}

	/*!
	* \brief Destroys a component by index
	*
	* \param index Index of the component
	*
	* \remark If component is not available, no action is performed
	*/

	void Entity::DestroyComponent(ComponentIndex index)
	{
		if (HasComponent(index))
		{
			// We get the component and we alert existing components of the deleted one
			BaseComponent& component = *m_components[index].get();
			for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
			{
				if (i != index)
					m_components[i]->OnComponentDetached(component);
			}

			component.SetEntity(nullptr);

			m_components[index].reset();
			m_componentBits.Reset(index);
		}
	}

}
<commit_msg>Sdk/Entity: Fix entity destruction not calling Component::OnDetached<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <NDK/Entity.hpp>
#include <NDK/BaseComponent.hpp>
#include <NDK/World.hpp>

namespace Ndk
{
	/*!
	* \ingroup NDK
	* \class Ndk::Entity
	* \brief NDK class that represents an entity in a world
	*/

	/*!
	* \brief Constructs a Entity object by move semantic
	*
	* \param entity Entity to move into this
	*/

	Entity::Entity(Entity&& entity) :
	HandledObject(std::move(entity)),
	m_components(std::move(entity.m_components)),
	m_componentBits(std::move(entity.m_componentBits)),
	m_systemBits(std::move(entity.m_systemBits)),
	m_id(entity.m_id),
	m_world(entity.m_world),
	m_enabled(entity.m_enabled),
	m_valid(entity.m_valid)
	{
	}

	/*!
	* \brief Constructs a Entity object linked to a world and with an id
	*
	* \param world World in which the entity interact
	* \param id Identifier of the entity
	*/

	Entity::Entity(World* world, EntityId id) :
	m_id(id),
	m_world(world)
	{
	}

	/*!
	* \brief Destructs the object and calls Destroy
	*
	* \see Destroy
	*/

	Entity::~Entity()
	{
		Destroy();
	}

	/*!
	* \brief Adds a component to the entity
	* \return A reference to the newly added component
	*
	* \param componentPtr Component to add to the entity
	*
	* \remark Produces a NazaraAssert if component is nullptr
	*/

	BaseComponent& Entity::AddComponent(std::unique_ptr<BaseComponent>&& componentPtr)
	{
		NazaraAssert(componentPtr, "Component must be valid");

		ComponentIndex index = componentPtr->GetIndex();

		// We ensure that the vector has enough space
		if (index >= m_components.size())
			m_components.resize(index + 1);

		// Affectation and return of the component
		m_components[index] = std::move(componentPtr);
		m_componentBits.UnboundedSet(index);
		m_removedComponentBits.UnboundedReset(index);

		Invalidate();

		// We get the new component and we alert other existing components of the new one
		BaseComponent& component = *m_components[index].get();
		component.SetEntity(this);

		for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
		{
			if (i != index)
				m_components[i]->OnComponentAttached(component);
		}

		return component;
	}

	/*!
	* \brief Clones the entity
	* \return The clone newly created
	*
	* \remark The close is enable by default, even if the original is disabled
	* \remark Produces a NazaraAssert if the entity is not valid
	*/

	const EntityHandle& Entity::Clone() const
	{
		NazaraAssert(IsValid(), "Invalid entity");

		return m_world->CloneEntity(m_id);
	}

	/*!
	* \brief Kills the entity
	*/

	void Entity::Kill()
	{
		m_world->KillEntity(this);
	}

	/*!
	* \brief Invalidates the entity
	*/

	void Entity::Invalidate()
	{
		// We alert everyone that we have been updated
		m_world->Invalidate(m_id);
	}

	/*!
	* \brief Creates the entity
	*/

	void Entity::Create()
	{
		m_enabled = true;
		m_valid = true;
	}

	/*!
	* \brief Destroys the entity
	*/

	void Entity::Destroy()
	{
		// We alert each system
		for (std::size_t index = m_systemBits.FindFirst(); index != m_systemBits.npos; index = m_systemBits.FindNext(index))
		{
			auto sysIndex = static_cast<Ndk::SystemIndex>(index);

			if (m_world->HasSystem(sysIndex))
			{
				BaseSystem& system = m_world->GetSystem(sysIndex);
				system.RemoveEntity(this);
			}
		}
		m_systemBits.Clear();

		// We properly destroy each component
		for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
			m_components[i]->SetEntity(nullptr);

		m_components.clear();
		m_componentBits.Reset();

		// And then free every handle
		UnregisterAllHandles();

		m_valid = false;
	}

	/*!
	* \brief Destroys a component by index
	*
	* \param index Index of the component
	*
	* \remark If component is not available, no action is performed
	*/

	void Entity::DestroyComponent(ComponentIndex index)
	{
		if (HasComponent(index))
		{
			// We get the component and we alert existing components of the deleted one
			BaseComponent& component = *m_components[index].get();
			for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
			{
				if (i != index)
					m_components[i]->OnComponentDetached(component);
			}

			component.SetEntity(nullptr);

			m_components[index].reset();
			m_componentBits.Reset(index);
		}
	}

}
<|endoftext|>


<commit_before>#include "3rdparty/GL/OpenGL.h"
#include "texture.h"

#include "augs/graphics/renderer.h"

namespace augs {
	namespace graphics {
		texture::~texture() {
			destroy();
		}

		void texture::create(const augs::image& source) {
			destroy();

			glGenTextures(1, &id); glerr;
			augs::renderer::get_current().bind_texture(*this);

			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glerr;

			glTexImage2D(
				GL_TEXTURE_2D,
				0,
				GL_RGBA,
				source.get_size().x,
				source.get_size().y,
				0,
				GL_BGRA,
				GL_UNSIGNED_BYTE,
				source.get_data()
			); glerr;

			built = true;
		}

		void texture::destroy() {
			if (built) {
				glDeleteTextures(1, &id); glerr;
			}

			built = false;
		}
	}
}

// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glerr;
<commit_msg>fixed texture filtering<commit_after>#include "3rdparty/GL/OpenGL.h"
#include "texture.h"

#include "augs/graphics/renderer.h"

namespace augs {
	namespace graphics {
		texture::~texture() {
			destroy();
		}

		void texture::create(const augs::image& source) {
			destroy();

			glGenTextures(1, &id); glerr;
			augs::renderer::get_current().bind_texture(*this);

			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glerr;
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glerr;

			glTexImage2D(
				GL_TEXTURE_2D,
				0,
				GL_RGBA,
				source.get_size().x,
				source.get_size().y,
				0,
				GL_BGRA,
				GL_UNSIGNED_BYTE,
				source.get_data()
			); glerr;

			built = true;
		}

		void texture::destroy() {
			if (built) {
				glDeleteTextures(1, &id); glerr;
			}

			built = false;
		}
	}
}

// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glerr;
<|endoftext|>


<commit_before>#include "rack.hpp"

using namespace rack;
extern Plugin *plugin;

struct SimpleClockWidget : ModuleWidget {
	SimpleClockWidget();
};

struct RMSWidget : ModuleWidget {
	RMSWidget();
};

struct XYPadWidget : ModuleWidget {
	XYPadWidget();
	Menu *createContextMenu();
};

struct BouncyBallWidget : ModuleWidget {
	BouncyBallWidget();
};

struct QuantizerWidget : ModuleWidget {
	QuantizerWidget();
	enum Notes {
		NOTE_C,
		NOTE_C_SHARP,
		NOTE_D,
		NOTE_D_SHARP,
		NOTE_E,
		NOTE_F,
		NOTE_F_SHARP,
		NOTE_G,
		NOTE_G_SHARP,
		NOTE_A,
		NOTE_A_SHARP,
		NOTE_B,
		NUM_NOTES
	};

	enum ScalesEnum {
		AEOLIAN,
		BLUES,
		CHROMATIC,
		DIATONIC_MINOR,
		DORIAN,
		HARMONIC_MINOR,
		INDIAN,
		LOCRIAN,
		LYDIAN,
		MAJOR,
		MELODIC_MINOR,
		MINOR,
		MIXOLYDIAN,
		NATURAL_MINOR,
		PENTATONIC,
		PHRYGIAN,
		TURKISH,
		NONE,
		NUM_SCALES
	};
};

struct FullScopeWidget : ModuleWidget {
	Panel *panel;
	Widget *rightHandle;
	TransparentWidget *display;
	FullScopeWidget();
	void step();
	json_t *toJson();
	void fromJson(json_t *rootJ);
};

struct GridSeqWidget : ModuleWidget {
	std::vector<ParamWidget*> seqKnobs;
	std::vector<ParamWidget*> gateButtons;
	GridSeqWidget();
	~GridSeqWidget(){
		seqKnobs.clear();
		gateButtons.clear();
	}
	Menu *createContextMenu();
};

struct CenteredLabel : Widget {
	std::string text;
	int fontSize;
	CenteredLabel(int _fontSize = 12) {
		fontSize = _fontSize;
		box.size.y = BND_WIDGET_HEIGHT;
	}
	void draw(NVGcontext *vg) override {
		nvgTextAlign(vg, NVG_ALIGN_CENTER);
		nvgFillColor(vg, nvgRGB(25, 150, 252));
		nvgFontSize(vg, fontSize);
		nvgText(vg, box.pos.x, box.pos.y, text.c_str(), NULL);
	}
};

struct SmallWhiteKnob : RoundKnob {
	SmallWhiteKnob() {
		setSVG(SVG::load(assetPlugin(plugin, "res/SmallWhiteKnob.svg")));
	}
	CenteredLabel* linkedLabel = nullptr;

	void connectLabel(CenteredLabel* label) {
		linkedLabel = label;
		if (linkedLabel) {
			linkedLabel->text = formatCurrentValue();
		}
	}

	void onChange(EventChange &e) override {
		RoundKnob::onChange(e);
		if (linkedLabel) {
			linkedLabel->text = formatCurrentValue();
		}
	}

	virtual std::string formatCurrentValue() {
		return std::to_string(static_cast<unsigned int>(value));
	}
};

struct LEDButtonSmall : SVGSwitch, MomentarySwitch {
	LEDButtonSmall() {
		addFrame(SVG::load(assetPlugin(plugin, "res/LEDButton_small.svg")));
	}
};

struct Screw_J : SVGScrew {
	Screw_J() {
		sw->setSVG(SVG::load(assetPlugin(plugin, "res/Screw_J.svg")));
		box.size = sw->box.size;
	}
};

struct Screw_W : SVGScrew {
	Screw_W() {
		sw->setSVG(SVG::load(assetPlugin(plugin, "res/Screw_W.svg")));
		box.size = sw->box.size;
	}
};

struct TinyBlackKnob : RoundKnob {
	TinyBlackKnob() {
		setSVG(SVG::load(assetGlobal("res/ComponentLibrary/RoundBlack.svg")));
		box.size = Vec(15, 15);
	}
};

struct TinyPJ301MPort : SVGPort {
	TinyPJ301MPort() {
		background->svg = SVG::load(assetPlugin(plugin, "res/TinyPJ301M.svg"));
		background->wrap();
		box.size = background->box.size;
	}
};

struct MyBlueValueLight : ColorLightWidget {
	MyBlueValueLight() {
		addColor(nvgRGB(25, 150, 252));
	}
};

struct NoteKnob : SmallWhiteKnob {
	std::string formatCurrentValue() override {
		switch(int(value)){
			case QuantizerWidget::NOTE_C:       return "C";
			case QuantizerWidget::NOTE_C_SHARP: return "C#";
			case QuantizerWidget::NOTE_D:       return "D";
			case QuantizerWidget::NOTE_D_SHARP: return "D#";
			case QuantizerWidget::NOTE_E:       return "E";
			case QuantizerWidget::NOTE_F:       return "F";
			case QuantizerWidget::NOTE_F_SHARP: return "F#";
			case QuantizerWidget::NOTE_G:       return "G";
			case QuantizerWidget::NOTE_G_SHARP: return "G#";
			case QuantizerWidget::NOTE_A:       return "A";
			case QuantizerWidget::NOTE_A_SHARP: return "A#";
			case QuantizerWidget::NOTE_B:       return "B";
			default: return "";
		}
	}
};

struct ScaleKnob : SmallWhiteKnob {
	std::string formatCurrentValue() override {
		switch(int(value)){
			case QuantizerWidget::AEOLIAN:        return "Aeolian";
			case QuantizerWidget::BLUES:          return "Blues";
			case QuantizerWidget::CHROMATIC:      return "Chromat";
			case QuantizerWidget::DIATONIC_MINOR: return "Diat Min";
			case QuantizerWidget::DORIAN:         return "Dorian";
			case QuantizerWidget::HARMONIC_MINOR: return "Harm Min";
			case QuantizerWidget::INDIAN:         return "Indian";
			case QuantizerWidget::LOCRIAN:        return "Locrian";
			case QuantizerWidget::LYDIAN:         return "Lydian";
			case QuantizerWidget::MAJOR:          return "Major";
			case QuantizerWidget::MELODIC_MINOR:  return "Mel Min";
			case QuantizerWidget::MINOR:          return "Minor";
			case QuantizerWidget::MIXOLYDIAN:     return "Mixolyd";
			case QuantizerWidget::NATURAL_MINOR:  return "Nat Min";
			case QuantizerWidget::PENTATONIC:     return "Penta";
			case QuantizerWidget::PHRYGIAN:       return "Phrygian";
			case QuantizerWidget::TURKISH:        return "Turkish";
			case QuantizerWidget::NONE:           return "None";
			default: return "";
		}
	}
};

struct RightMoveButton : SVGSwitch, MomentarySwitch {
	RightMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/RightButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/RightButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct LeftMoveButton : SVGSwitch, MomentarySwitch {
	LeftMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/LeftButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/LeftButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct DownMoveButton : SVGSwitch, MomentarySwitch {
	DownMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/DownButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/DownButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct UpMoveButton : SVGSwitch, MomentarySwitch {
	UpMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/UpButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/UpButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct RndMoveButton : SVGSwitch, MomentarySwitch {
	RndMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/RndButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/RndButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct RepMoveButton : SVGSwitch, MomentarySwitch {
	RepMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/RepButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/RepButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct SmallButton : SVGSwitch, MomentarySwitch {
	SmallButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/ButtonUp.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/ButtonDown.svg")));
	}
};

struct ModuleResizeHandle : Widget {
	float minWidth;
	bool right = false;
	float dragX;
	Rect originalBox;
	ModuleResizeHandle(float _minWidth) {
		box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT);
		minWidth = _minWidth;
	}
	void onMouseDown(EventMouseDown &e) override {
		if (e.button == 0) {
			e.consumed = true;
			e.target = this;
		}
	}
	void onDragStart(EventDragStart &e) override {
		dragX = gRackWidget->lastMousePos.x;
		ModuleWidget *m = getAncestorOfType<ModuleWidget>();
		originalBox = m->box;
	}
	void onDragMove(EventDragMove &e) override {
		ModuleWidget *m = getAncestorOfType<ModuleWidget>();

		float newDragX = gRackWidget->lastMousePos.x;
		float deltaX = newDragX - dragX;

		Rect newBox = originalBox;
		if (right) {
			newBox.size.x += deltaX;
			newBox.size.x = fmaxf(newBox.size.x, minWidth);
			newBox.size.x = roundf(newBox.size.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
		}
		else {
			newBox.size.x -= deltaX;
			newBox.size.x = fmaxf(newBox.size.x, minWidth);
			newBox.size.x = roundf(newBox.size.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
			newBox.pos.x = originalBox.pos.x + originalBox.size.x - newBox.size.x;
		}
		gRackWidget->requestModuleBox(m, newBox);
	}
};

<commit_msg>fixed lights<commit_after>#include "rack.hpp"

using namespace rack;
extern Plugin *plugin;

struct SimpleClockWidget : ModuleWidget {
	SimpleClockWidget();
};

struct RMSWidget : ModuleWidget {
	RMSWidget();
};

struct XYPadWidget : ModuleWidget {
	XYPadWidget();
	Menu *createContextMenu();
};

struct BouncyBallWidget : ModuleWidget {
	BouncyBallWidget();
};

struct QuantizerWidget : ModuleWidget {
	QuantizerWidget();
	enum Notes {
		NOTE_C,
		NOTE_C_SHARP,
		NOTE_D,
		NOTE_D_SHARP,
		NOTE_E,
		NOTE_F,
		NOTE_F_SHARP,
		NOTE_G,
		NOTE_G_SHARP,
		NOTE_A,
		NOTE_A_SHARP,
		NOTE_B,
		NUM_NOTES
	};

	enum ScalesEnum {
		AEOLIAN,
		BLUES,
		CHROMATIC,
		DIATONIC_MINOR,
		DORIAN,
		HARMONIC_MINOR,
		INDIAN,
		LOCRIAN,
		LYDIAN,
		MAJOR,
		MELODIC_MINOR,
		MINOR,
		MIXOLYDIAN,
		NATURAL_MINOR,
		PENTATONIC,
		PHRYGIAN,
		TURKISH,
		NONE,
		NUM_SCALES
	};
};

struct FullScopeWidget : ModuleWidget {
	Panel *panel;
	Widget *rightHandle;
	TransparentWidget *display;
	FullScopeWidget();
	void step();
	json_t *toJson();
	void fromJson(json_t *rootJ);
};

struct GridSeqWidget : ModuleWidget {
	std::vector<ParamWidget*> seqKnobs;
	std::vector<ParamWidget*> gateButtons;
	GridSeqWidget();
	~GridSeqWidget(){
		seqKnobs.clear();
		gateButtons.clear();
	}
	Menu *createContextMenu();
};

struct CenteredLabel : Widget {
	std::string text;
	int fontSize;
	CenteredLabel(int _fontSize = 12) {
		fontSize = _fontSize;
		box.size.y = BND_WIDGET_HEIGHT;
	}
	void draw(NVGcontext *vg) override {
		nvgTextAlign(vg, NVG_ALIGN_CENTER);
		nvgFillColor(vg, nvgRGB(25, 150, 252));
		nvgFontSize(vg, fontSize);
		nvgText(vg, box.pos.x, box.pos.y, text.c_str(), NULL);
	}
};

struct SmallWhiteKnob : RoundKnob {
	SmallWhiteKnob() {
		setSVG(SVG::load(assetPlugin(plugin, "res/SmallWhiteKnob.svg")));
	}
	CenteredLabel* linkedLabel = nullptr;

	void connectLabel(CenteredLabel* label) {
		linkedLabel = label;
		if (linkedLabel) {
			linkedLabel->text = formatCurrentValue();
		}
	}

	void onChange(EventChange &e) override {
		RoundKnob::onChange(e);
		if (linkedLabel) {
			linkedLabel->text = formatCurrentValue();
		}
	}

	virtual std::string formatCurrentValue() {
		return std::to_string(static_cast<unsigned int>(value));
	}
};

struct LEDButtonSmall : SVGSwitch, MomentarySwitch {
	LEDButtonSmall() {
		addFrame(SVG::load(assetPlugin(plugin, "res/LEDButton_small.svg")));
	}
};

struct Screw_J : SVGScrew {
	Screw_J() {
		sw->setSVG(SVG::load(assetPlugin(plugin, "res/Screw_J.svg")));
		box.size = sw->box.size;
	}
};

struct Screw_W : SVGScrew {
	Screw_W() {
		sw->setSVG(SVG::load(assetPlugin(plugin, "res/Screw_W.svg")));
		box.size = sw->box.size;
	}
};

struct TinyBlackKnob : RoundKnob {
	TinyBlackKnob() {
		setSVG(SVG::load(assetGlobal("res/ComponentLibrary/RoundBlack.svg")));
		box.size = Vec(15, 15);
	}
};

struct TinyPJ301MPort : SVGPort {
	TinyPJ301MPort() {
		background->svg = SVG::load(assetPlugin(plugin, "res/TinyPJ301M.svg"));
		background->wrap();
		box.size = background->box.size;
	}
};

struct MyBlueValueLight : ModuleLightWidget {
	MyBlueValueLight() {
		firstLightId = 1;
		addBaseColor(nvgRGB(25, 150, 252));
	}
};

struct NoteKnob : SmallWhiteKnob {
	std::string formatCurrentValue() override {
		switch(int(value)){
			case QuantizerWidget::NOTE_C:       return "C";
			case QuantizerWidget::NOTE_C_SHARP: return "C#";
			case QuantizerWidget::NOTE_D:       return "D";
			case QuantizerWidget::NOTE_D_SHARP: return "D#";
			case QuantizerWidget::NOTE_E:       return "E";
			case QuantizerWidget::NOTE_F:       return "F";
			case QuantizerWidget::NOTE_F_SHARP: return "F#";
			case QuantizerWidget::NOTE_G:       return "G";
			case QuantizerWidget::NOTE_G_SHARP: return "G#";
			case QuantizerWidget::NOTE_A:       return "A";
			case QuantizerWidget::NOTE_A_SHARP: return "A#";
			case QuantizerWidget::NOTE_B:       return "B";
			default: return "";
		}
	}
};

struct ScaleKnob : SmallWhiteKnob {
	std::string formatCurrentValue() override {
		switch(int(value)){
			case QuantizerWidget::AEOLIAN:        return "Aeolian";
			case QuantizerWidget::BLUES:          return "Blues";
			case QuantizerWidget::CHROMATIC:      return "Chromat";
			case QuantizerWidget::DIATONIC_MINOR: return "Diat Min";
			case QuantizerWidget::DORIAN:         return "Dorian";
			case QuantizerWidget::HARMONIC_MINOR: return "Harm Min";
			case QuantizerWidget::INDIAN:         return "Indian";
			case QuantizerWidget::LOCRIAN:        return "Locrian";
			case QuantizerWidget::LYDIAN:         return "Lydian";
			case QuantizerWidget::MAJOR:          return "Major";
			case QuantizerWidget::MELODIC_MINOR:  return "Mel Min";
			case QuantizerWidget::MINOR:          return "Minor";
			case QuantizerWidget::MIXOLYDIAN:     return "Mixolyd";
			case QuantizerWidget::NATURAL_MINOR:  return "Nat Min";
			case QuantizerWidget::PENTATONIC:     return "Penta";
			case QuantizerWidget::PHRYGIAN:       return "Phrygian";
			case QuantizerWidget::TURKISH:        return "Turkish";
			case QuantizerWidget::NONE:           return "None";
			default: return "";
		}
	}
};

struct RightMoveButton : SVGSwitch, MomentarySwitch {
	RightMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/RightButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/RightButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct LeftMoveButton : SVGSwitch, MomentarySwitch {
	LeftMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/LeftButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/LeftButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct DownMoveButton : SVGSwitch, MomentarySwitch {
	DownMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/DownButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/DownButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct UpMoveButton : SVGSwitch, MomentarySwitch {
	UpMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/UpButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/UpButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct RndMoveButton : SVGSwitch, MomentarySwitch {
	RndMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/RndButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/RndButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct RepMoveButton : SVGSwitch, MomentarySwitch {
	RepMoveButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/RepButton.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/RepButtonDown.svg")));
		sw->wrap();
		box.size = sw->box.size;
	}
};

struct SmallButton : SVGSwitch, MomentarySwitch {
	SmallButton() {
		addFrame(SVG::load(assetPlugin(plugin, "res/ButtonUp.svg")));
		addFrame(SVG::load(assetPlugin(plugin, "res/ButtonDown.svg")));
	}
};

struct ModuleResizeHandle : Widget {
	float minWidth;
	bool right = false;
	float dragX;
	Rect originalBox;
	ModuleResizeHandle(float _minWidth) {
		box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT);
		minWidth = _minWidth;
	}
	void onMouseDown(EventMouseDown &e) override {
		if (e.button == 0) {
			e.consumed = true;
			e.target = this;
		}
	}
	void onDragStart(EventDragStart &e) override {
		dragX = gRackWidget->lastMousePos.x;
		ModuleWidget *m = getAncestorOfType<ModuleWidget>();
		originalBox = m->box;
	}
	void onDragMove(EventDragMove &e) override {
		ModuleWidget *m = getAncestorOfType<ModuleWidget>();

		float newDragX = gRackWidget->lastMousePos.x;
		float deltaX = newDragX - dragX;

		Rect newBox = originalBox;
		if (right) {
			newBox.size.x += deltaX;
			newBox.size.x = fmaxf(newBox.size.x, minWidth);
			newBox.size.x = roundf(newBox.size.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
		}
		else {
			newBox.size.x -= deltaX;
			newBox.size.x = fmaxf(newBox.size.x, minWidth);
			newBox.size.x = roundf(newBox.size.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
			newBox.pos.x = originalBox.pos.x + originalBox.size.x - newBox.size.x;
		}
		gRackWidget->requestModuleBox(m, newBox);
	}
};

<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexEiffel.cxx
 ** Lexer for Eiffel.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

inline bool isEiffelOperator(unsigned int ch) {
	// '.' left out as it is used to make up numbers
	return ch == '*' || ch == '/' || ch == '\\' || ch == '-' || ch == '+' ||
	        ch == '(' || ch == ')' || ch == '=' ||
	        ch == '{' || ch == '}' || ch == '~' ||
	        ch == '[' || ch == ']' || ch == ';' ||
	        ch == '<' || ch == '>' || ch == ',' ||
	        ch == '.' || ch == '^' || ch == '%' || ch == ':' ||
		ch == '!' || ch == '@' || ch == '?';
}

static void getRangeLowered(unsigned int start,
		unsigned int end,
		Accessor &styler,
		char *s,
		unsigned int len) {
	unsigned int i = 0;
	while ((i < end - start + 1) && (i < len-1)) {
		s[i] = static_cast<char>(tolower(styler[start + i]));
		i++;
	}
	s[i] = '\0';
}

inline bool IsASpace(unsigned int ch) {
    return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
}

inline bool IsAWordChar(unsigned int  ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(unsigned int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool IsADigit(unsigned int ch) {
	return (ch >= '0') && (ch <= '9');
}

// All languages handled so far can treat all characters >= 0x80 as one class
// which just continues the current token or starts an identifier if in default.
// DBCS treated specially as the second character can be < 0x80 and hence
// syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80
class ColouriseContext {
	Accessor &styler;
	int lengthDoc;
	int currentPos;
	ColouriseContext& operator=(const ColouriseContext&) {
		return *this;
	}
public:
	int state;
	unsigned int chPrev;
	unsigned int ch;
	unsigned int chNext;

	ColouriseContext(unsigned int startPos, int length,
                        int initStyle, Accessor &styler_) :
		styler(styler_),
		lengthDoc(startPos + length),
		currentPos(startPos),
		state(initStyle),
		chPrev(0),
		ch(0),
		chNext(0) {
		styler.StartAt(startPos);
		styler.StartSegment(startPos);
		int pos = currentPos;
		ch = static_cast<unsigned char>(styler.SafeGetCharAt(pos));
		if (styler.IsLeadByte(static_cast<char>(ch))) {
			pos++;
			ch = ch << 8;
			ch |= static_cast<unsigned char>(styler.SafeGetCharAt(pos));
		}
		chNext = static_cast<unsigned char>(styler.SafeGetCharAt(pos+1));
		if (styler.IsLeadByte(static_cast<char>(chNext))) {
			chNext = chNext << 8;
			chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(pos+2));
		}
	}
	void Complete() {
		styler.ColourTo(currentPos - 1, state);
	}
	bool More() {
		return currentPos <= lengthDoc;
	}
	void Forward() {
		chPrev = ch;
		currentPos++;
		if (ch >= 0x100)
			currentPos++;
		ch = chNext;
		chNext = static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+1));
		if (styler.IsLeadByte(static_cast<char>(chNext))) {
			chNext = chNext << 8;
			chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(currentPos + 2));
		}
	}
	void ChangeState(int state_) {
		state = state_;
	}
	void SetState(int state_) {
		styler.ColourTo(currentPos - 1, state);
		state = state_;
	}
	void GetCurrentLowered(char *s, int len) {
		getRangeLowered(styler.GetStartSegment(), currentPos - 1, styler, s, len);
	}
};

static void ColouriseEiffelDoc(unsigned int startPos,
                            int length,
                            int initStyle,
                            WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	ColouriseContext lc(startPos, length, initStyle, styler);

	for (; lc.More(); lc.Forward()) {

		if (lc.state == SCE_EIFFEL_STRINGEOL) {
			if (lc.ch != '\r' && lc.ch != '\n') {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_OPERATOR) {
			lc.SetState(SCE_EIFFEL_DEFAULT);
		} else if (lc.state == SCE_EIFFEL_WORD) {
			if (!IsAWordChar(lc.ch)) {
				char s[100];
				lc.GetCurrentLowered(s, sizeof(s));
				if (!keywords.InList(s)) {
					lc.ChangeState(SCE_EIFFEL_IDENTIFIER);
				}
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_NUMBER) {
			if (!IsAWordChar(lc.ch)) {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_COMMENTLINE) {
			if (lc.ch == '\r' || lc.ch == '\n') {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_STRING) {
			if (lc.ch == '%') {
				lc.Forward();
			} else if (lc.ch == '\"') {
				lc.Forward();
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_CHARACTER) {
			if (lc.ch == '\r' || lc.ch == '\n') {
				lc.SetState(SCE_EIFFEL_STRINGEOL);
			} else if (lc.ch == '%') {
				lc.Forward();
			} else if (lc.ch == '\'') {
				lc.Forward();
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		}

		if (lc.state == SCE_EIFFEL_DEFAULT) {
			if (lc.ch == '-' && lc.chNext == '-') {
				lc.SetState(SCE_EIFFEL_COMMENTLINE);
			} else if (lc.ch == '\"') {
				lc.SetState(SCE_EIFFEL_STRING);
			} else if (lc.ch == '\'') {
				lc.SetState(SCE_EIFFEL_CHARACTER);
			} else if (IsADigit(lc.ch) || (lc.ch == '.')) {
				lc.SetState(SCE_EIFFEL_NUMBER);
			} else if (IsAWordStart(lc.ch)) {
				lc.SetState(SCE_EIFFEL_WORD);
			} else if (isEiffelOperator(lc.ch)) {
				lc.SetState(SCE_EIFFEL_OPERATOR);
			}
		}
	}
	lc.Complete();
}

static bool IsEiffelComment(Accessor &styler, int pos, int len) {
	return len>1 && styler[pos]=='-' && styler[pos+1]=='-';
}

static void FoldEiffelDocIndent(unsigned int startPos, int length, int,
						   WordList *[], Accessor &styler) {
	int lengthDoc = startPos + length;

	// Backtrack to previous line in case need to fix its fold status
	int lineCurrent = styler.GetLine(startPos);
	if (startPos > 0) {
		if (lineCurrent > 0) {
			lineCurrent--;
			startPos = styler.LineStart(lineCurrent);
		}
	}
	int spaceFlags = 0;
	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsEiffelComment);
	char chNext = styler[startPos];
	for (int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) {
			int lev = indentCurrent;
			int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsEiffelComment);
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
					// Line after is blank so check the next - maybe should continue further?
					int spaceFlags2 = 0;
					int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsEiffelComment);
					if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
						lev |= SC_FOLDLEVELHEADERFLAG;
					}
				}
			}
			indentCurrent = indentNext;
			styler.SetLevel(lineCurrent, lev);
			lineCurrent++;
		}
	}
}

static void FoldEiffelDocKeyWords(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int stylePrev = 0;
	int styleNext = styler.StyleAt(startPos);
	// lastDeferred should be determined by looking back to last keyword in case
	// the "deferred" is on a line before "class"
	bool lastDeferred = false;
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if ((stylePrev != SCE_EIFFEL_WORD) && (style == SCE_EIFFEL_WORD)) {
			char s[20];
			unsigned int j = 0;
			while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) {
				s[j] = styler[i + j];
				j++;
			}
			s[j] = '\0';

			if (
				(strcmp(s, "check") == 0) ||
				(strcmp(s, "debug") == 0) ||
				(strcmp(s, "deferred") == 0) ||
				(strcmp(s, "do") == 0) ||
				(strcmp(s, "from") == 0) ||
				(strcmp(s, "if") == 0) ||
				(strcmp(s, "inspect") == 0) ||
				(strcmp(s, "once") == 0)
			)
				levelCurrent++;
			if (!lastDeferred && (strcmp(s, "class") == 0))
				levelCurrent++;
			if (strcmp(s, "end") == 0)
				levelCurrent--;
			lastDeferred = strcmp(s, "deferred") == 0;
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
		stylePrev = style;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

LexerModule lmEiffel(SCLEX_EIFFEL, ColouriseEiffelDoc, "eiffel", FoldEiffelDocIndent);
LexerModule lmEiffelkw(SCLEX_EIFFELKW, ColouriseEiffelDoc, "eiffelkw", FoldEiffelDocKeyWords);
<commit_msg>Changed name of ColouriseContext to allow debugging.<commit_after>// Scintilla source code edit control
/** @file LexEiffel.cxx
 ** Lexer for Eiffel.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

inline bool isEiffelOperator(unsigned int ch) {
	// '.' left out as it is used to make up numbers
	return ch == '*' || ch == '/' || ch == '\\' || ch == '-' || ch == '+' ||
	        ch == '(' || ch == ')' || ch == '=' ||
	        ch == '{' || ch == '}' || ch == '~' ||
	        ch == '[' || ch == ']' || ch == ';' ||
	        ch == '<' || ch == '>' || ch == ',' ||
	        ch == '.' || ch == '^' || ch == '%' || ch == ':' ||
		ch == '!' || ch == '@' || ch == '?';
}

static void getRangeLowered(unsigned int start,
		unsigned int end,
		Accessor &styler,
		char *s,
		unsigned int len) {
	unsigned int i = 0;
	while ((i < end - start + 1) && (i < len-1)) {
		s[i] = static_cast<char>(tolower(styler[start + i]));
		i++;
	}
	s[i] = '\0';
}

inline bool IsASpace(unsigned int ch) {
    return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
}

inline bool IsAWordChar(unsigned int  ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

inline bool IsAWordStart(unsigned int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

inline bool IsADigit(unsigned int ch) {
	return (ch >= '0') && (ch <= '9');
}

// All languages handled so far can treat all characters >= 0x80 as one class
// which just continues the current token or starts an identifier if in default.
// DBCS treated specially as the second character can be < 0x80 and hence
// syntactically significant. UTF-8 avoids this as all trail bytes are >= 0x80
class xColouriseContext {
	Accessor &styler;
	int lengthDoc;
	int currentPos;
	xColouriseContext& operator=(const xColouriseContext&) {
		return *this;
	}
public:
	int state;
	unsigned int chPrev;
	unsigned int ch;
	unsigned int chNext;

	xColouriseContext(unsigned int startPos, int length,
                        int initStyle, Accessor &styler_) :
		styler(styler_),
		lengthDoc(startPos + length),
		currentPos(startPos),
		state(initStyle),
		chPrev(0),
		ch(0),
		chNext(0) {
		styler.StartAt(startPos);
		styler.StartSegment(startPos);
		int pos = currentPos;
		ch = static_cast<unsigned char>(styler.SafeGetCharAt(pos));
		if (styler.IsLeadByte(static_cast<char>(ch))) {
			pos++;
			ch = ch << 8;
			ch |= static_cast<unsigned char>(styler.SafeGetCharAt(pos));
		}
		chNext = static_cast<unsigned char>(styler.SafeGetCharAt(pos+1));
		if (styler.IsLeadByte(static_cast<char>(chNext))) {
			chNext = chNext << 8;
			chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(pos+2));
		}
	}
	void Complete() {
		styler.ColourTo(currentPos - 1, state);
	}
	bool More() {
		return currentPos <= lengthDoc;
	}
	void Forward() {
		chPrev = ch;
		currentPos++;
		if (ch >= 0x100)
			currentPos++;
		ch = chNext;
		chNext = static_cast<unsigned char>(styler.SafeGetCharAt(currentPos+1));
		if (styler.IsLeadByte(static_cast<char>(chNext))) {
			chNext = chNext << 8;
			chNext |= static_cast<unsigned char>(styler.SafeGetCharAt(currentPos + 2));
		}
	}
	void ChangeState(int state_) {
		state = state_;
	}
	void SetState(int state_) {
		styler.ColourTo(currentPos - 1, state);
		state = state_;
	}
	void GetCurrentLowered(char *s, int len) {
		getRangeLowered(styler.GetStartSegment(), currentPos - 1, styler, s, len);
	}
};

static void ColouriseEiffelDoc(unsigned int startPos,
                            int length,
                            int initStyle,
                            WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	xColouriseContext lc(startPos, length, initStyle, styler);

	for (; lc.More(); lc.Forward()) {

		if (lc.state == SCE_EIFFEL_STRINGEOL) {
			if (lc.ch != '\r' && lc.ch != '\n') {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_OPERATOR) {
			lc.SetState(SCE_EIFFEL_DEFAULT);
		} else if (lc.state == SCE_EIFFEL_WORD) {
			if (!IsAWordChar(lc.ch)) {
				char s[100];
				lc.GetCurrentLowered(s, sizeof(s));
				if (!keywords.InList(s)) {
					lc.ChangeState(SCE_EIFFEL_IDENTIFIER);
				}
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_NUMBER) {
			if (!IsAWordChar(lc.ch)) {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_COMMENTLINE) {
			if (lc.ch == '\r' || lc.ch == '\n') {
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_STRING) {
			if (lc.ch == '%') {
				lc.Forward();
			} else if (lc.ch == '\"') {
				lc.Forward();
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		} else if (lc.state == SCE_EIFFEL_CHARACTER) {
			if (lc.ch == '\r' || lc.ch == '\n') {
				lc.SetState(SCE_EIFFEL_STRINGEOL);
			} else if (lc.ch == '%') {
				lc.Forward();
			} else if (lc.ch == '\'') {
				lc.Forward();
				lc.SetState(SCE_EIFFEL_DEFAULT);
			}
		}

		if (lc.state == SCE_EIFFEL_DEFAULT) {
			if (lc.ch == '-' && lc.chNext == '-') {
				lc.SetState(SCE_EIFFEL_COMMENTLINE);
			} else if (lc.ch == '\"') {
				lc.SetState(SCE_EIFFEL_STRING);
			} else if (lc.ch == '\'') {
				lc.SetState(SCE_EIFFEL_CHARACTER);
			} else if (IsADigit(lc.ch) || (lc.ch == '.')) {
				lc.SetState(SCE_EIFFEL_NUMBER);
			} else if (IsAWordStart(lc.ch)) {
				lc.SetState(SCE_EIFFEL_WORD);
			} else if (isEiffelOperator(lc.ch)) {
				lc.SetState(SCE_EIFFEL_OPERATOR);
			}
		}
	}
	lc.Complete();
}

static bool IsEiffelComment(Accessor &styler, int pos, int len) {
	return len>1 && styler[pos]=='-' && styler[pos+1]=='-';
}

static void FoldEiffelDocIndent(unsigned int startPos, int length, int,
						   WordList *[], Accessor &styler) {
	int lengthDoc = startPos + length;

	// Backtrack to previous line in case need to fix its fold status
	int lineCurrent = styler.GetLine(startPos);
	if (startPos > 0) {
		if (lineCurrent > 0) {
			lineCurrent--;
			startPos = styler.LineStart(lineCurrent);
		}
	}
	int spaceFlags = 0;
	int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsEiffelComment);
	char chNext = styler[startPos];
	for (int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc)) {
			int lev = indentCurrent;
			int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsEiffelComment);
			if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG)) {
				// Only non whitespace lines can be headers
				if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK)) {
					lev |= SC_FOLDLEVELHEADERFLAG;
				} else if (indentNext & SC_FOLDLEVELWHITEFLAG) {
					// Line after is blank so check the next - maybe should continue further?
					int spaceFlags2 = 0;
					int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsEiffelComment);
					if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK)) {
						lev |= SC_FOLDLEVELHEADERFLAG;
					}
				}
			}
			indentCurrent = indentNext;
			styler.SetLevel(lineCurrent, lev);
			lineCurrent++;
		}
	}
}

static void FoldEiffelDocKeyWords(unsigned int startPos, int length, int /* initStyle */, WordList *[],
                       Accessor &styler) {
	unsigned int lengthDoc = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int stylePrev = 0;
	int styleNext = styler.StyleAt(startPos);
	// lastDeferred should be determined by looking back to last keyword in case
	// the "deferred" is on a line before "class"
	bool lastDeferred = false;
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if ((stylePrev != SCE_EIFFEL_WORD) && (style == SCE_EIFFEL_WORD)) {
			char s[20];
			unsigned int j = 0;
			while ((j < (sizeof(s) - 1)) && (iswordchar(styler[i + j]))) {
				s[j] = styler[i + j];
				j++;
			}
			s[j] = '\0';

			if (
				(strcmp(s, "check") == 0) ||
				(strcmp(s, "debug") == 0) ||
				(strcmp(s, "deferred") == 0) ||
				(strcmp(s, "do") == 0) ||
				(strcmp(s, "from") == 0) ||
				(strcmp(s, "if") == 0) ||
				(strcmp(s, "inspect") == 0) ||
				(strcmp(s, "once") == 0)
			)
				levelCurrent++;
			if (!lastDeferred && (strcmp(s, "class") == 0))
				levelCurrent++;
			if (strcmp(s, "end") == 0)
				levelCurrent--;
			lastDeferred = strcmp(s, "deferred") == 0;
		}

		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
		stylePrev = style;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

LexerModule lmEiffel(SCLEX_EIFFEL, ColouriseEiffelDoc, "eiffel", FoldEiffelDocIndent);
LexerModule lmEiffelkw(SCLEX_EIFFELKW, ColouriseEiffelDoc, "eiffelkw", FoldEiffelDocKeyWords);
<|endoftext|>


<commit_before>#include "MenuState.h"
#include "Game.h"
#include "InputHandler.h"
#include "PlayState.h"
#include <iostream>

MenuState::MenuState(const int nbButtons) : m_nbButtons(nbButtons) {}

void MenuState::update() {
	InputHandler* handlerInstance = InputHandler::Instance();
	if (handlerInstance->joysticksInitialised()) {
		int yAxisValue = handlerInstance->stickYValue(0, LEFT_STICK);
		// The stick must be brought back to neutral position to choose another
		// menu element, otherwise, it moves too fast.
		if (m_menuBeingChanged && yAxisValue == 0) {
			m_menuBeingChanged = false;
		}
		else if (!m_menuBeingChanged && yAxisValue != 0) {
			// deactivate the current menu element, change the current active
			// index, activate the new current menu element
			m_buttons[m_activeButtonIndex]->setActive(false);
			if (yAxisValue < 0) {
				m_activeButtonIndex = (m_nbButtons + m_activeButtonIndex - 1) % m_nbButtons;
			}
			else if (yAxisValue > 0) {
				m_activeButtonIndex = (m_activeButtonIndex + 1) % m_nbButtons;
			}
			m_buttons[m_activeButtonIndex]->setActive(true);
			m_menuBeingChanged = true;
		}

		if (InputHandler::Instance()->getButtonState(0, 0)) {
			m_buttons[m_activeButtonIndex]->executeAction();
		}
	}
}

void MenuState::render() {
	for (std::vector<GameObject*>::size_type i = 0; i != m_renderableObjects.size(); i++) {
		m_renderableObjects[i]->render(Game::Instance()->getRenderer());
	}
}

bool MenuState::onEnter() {
	std::cout << "entering MenuState\n";
	m_menuBeingChanged = false;
	m_nbButtons = 2;
	m_activeButtonIndex = 0;
	for (int i = 0; i < m_nbButtons; ++i) {
		m_buttons.push_back(createButton(i));
		m_gameObjects.push_back(m_buttons[i]);
		m_renderableObjects.push_back(m_buttons[i]);
	}
	return true;
}

bool MenuState::onExit() {
	std::cout << "exiting MenuState\n";
	return true;
}
<commit_msg>this is not needed here, already initialised in the construct<commit_after>#include "MenuState.h"
#include "Game.h"
#include "InputHandler.h"
#include "PlayState.h"
#include <iostream>

MenuState::MenuState(const int nbButtons) : m_nbButtons(nbButtons) {}

void MenuState::update() {
	InputHandler* handlerInstance = InputHandler::Instance();
	if (handlerInstance->joysticksInitialised()) {
		int yAxisValue = handlerInstance->stickYValue(0, LEFT_STICK);
		// The stick must be brought back to neutral position to choose another
		// menu element, otherwise, it moves too fast.
		if (m_menuBeingChanged && yAxisValue == 0) {
			m_menuBeingChanged = false;
		}
		else if (!m_menuBeingChanged && yAxisValue != 0) {
			// deactivate the current menu element, change the current active
			// index, activate the new current menu element
			m_buttons[m_activeButtonIndex]->setActive(false);
			if (yAxisValue < 0) {
				m_activeButtonIndex = (m_nbButtons + m_activeButtonIndex - 1) % m_nbButtons;
			}
			else if (yAxisValue > 0) {
				m_activeButtonIndex = (m_activeButtonIndex + 1) % m_nbButtons;
			}
			m_buttons[m_activeButtonIndex]->setActive(true);
			m_menuBeingChanged = true;
		}

		if (InputHandler::Instance()->getButtonState(0, 0)) {
			m_buttons[m_activeButtonIndex]->executeAction();
		}
	}
}

void MenuState::render() {
	for (std::vector<GameObject*>::size_type i = 0; i != m_renderableObjects.size(); i++) {
		m_renderableObjects[i]->render(Game::Instance()->getRenderer());
	}
}

bool MenuState::onEnter() {
	for (int i = 0; i < m_nbButtons; ++i) {
		m_buttons.push_back(createButton(i));
		m_gameObjects.push_back(m_buttons[i]);
		m_renderableObjects.push_back(m_buttons[i]);
	}
	return true;
}

bool MenuState::onExit() {
	std::cout << "exiting MenuState\n";
	return true;
}
<|endoftext|>


<commit_before>#include "MenuState.h"
#include "Game.h"
#include "InputHandler.h"
#include "PlayState.h"
#include <iostream>

MenuState::MenuState(const int nbButtons) : m_nbButtons(nbButtons) {}

void MenuState::update() {
	InputHandler* handlerInstance = InputHandler::Instance();
	if (handlerInstance->joysticksInitialised()) {
		int yAxisValue = handlerInstance->stickYValue(0, LEFT_STICK);
		// The stick must be brought back to neutral position to choose another
		// menu element, otherwise, it moves too fast.
		if (m_menuBeingChanged && yAxisValue == 0) {
			m_menuBeingChanged = false;
		}
		else if (!m_menuBeingChanged && yAxisValue != 0) {
			// deactivate the current menu element, change the current active
			// index, activate the new current menu element
			m_buttons[m_activeButtonIndex]->setActive(false);
			if (yAxisValue > 0) {
				m_activeButtonIndex = (m_nbButtons + m_activeButtonIndex - 1) % m_nbButtons;
			}
			else if (yAxisValue < 0) {
				m_activeButtonIndex = (m_activeButtonIndex + 1) % m_nbButtons;
			}
			m_buttons[m_activeButtonIndex]->setActive(true);
			m_menuBeingChanged = true;
		}

		if (InputHandler::Instance()->getButtonState(0, 0)) {
			m_buttons[m_activeButtonIndex]->executeAction();
		}
	}
}

void MenuState::render() {
	for (std::vector<GameObject*>::size_type i = 0; i != m_renderableObjects.size(); i++) {
		m_renderableObjects[i]->render(Game::Instance()->getRenderer());
	}
}

bool MenuState::onEnter() {
	std::cout << "entering MenuState\n";
	m_menuBeingChanged = false;
	m_nbButtons = 2;
	m_activeButtonIndex = 0;
	for (int i = 0; i < m_nbButtons; ++i) {
		m_buttons.push_back(createButton(i));
		m_gameObjects.push_back(m_buttons[i]);
		m_renderableObjects.push_back(m_buttons[i]);
	}
	return true;
}

bool MenuState::onExit() {
	std::cout << "exiting MenuState\n";
	return true;
}
<commit_msg>the directions where inverted<commit_after>#include "MenuState.h"
#include "Game.h"
#include "InputHandler.h"
#include "PlayState.h"
#include <iostream>

MenuState::MenuState(const int nbButtons) : m_nbButtons(nbButtons) {}

void MenuState::update() {
	InputHandler* handlerInstance = InputHandler::Instance();
	if (handlerInstance->joysticksInitialised()) {
		int yAxisValue = handlerInstance->stickYValue(0, LEFT_STICK);
		// The stick must be brought back to neutral position to choose another
		// menu element, otherwise, it moves too fast.
		if (m_menuBeingChanged && yAxisValue == 0) {
			m_menuBeingChanged = false;
		}
		else if (!m_menuBeingChanged && yAxisValue != 0) {
			// deactivate the current menu element, change the current active
			// index, activate the new current menu element
			m_buttons[m_activeButtonIndex]->setActive(false);
			if (yAxisValue < 0) {
				m_activeButtonIndex = (m_nbButtons + m_activeButtonIndex - 1) % m_nbButtons;
			}
			else if (yAxisValue > 0) {
				m_activeButtonIndex = (m_activeButtonIndex + 1) % m_nbButtons;
			}
			m_buttons[m_activeButtonIndex]->setActive(true);
			m_menuBeingChanged = true;
		}

		if (InputHandler::Instance()->getButtonState(0, 0)) {
			m_buttons[m_activeButtonIndex]->executeAction();
		}
	}
}

void MenuState::render() {
	for (std::vector<GameObject*>::size_type i = 0; i != m_renderableObjects.size(); i++) {
		m_renderableObjects[i]->render(Game::Instance()->getRenderer());
	}
}

bool MenuState::onEnter() {
	std::cout << "entering MenuState\n";
	m_menuBeingChanged = false;
	m_nbButtons = 2;
	m_activeButtonIndex = 0;
	for (int i = 0; i < m_nbButtons; ++i) {
		m_buttons.push_back(createButton(i));
		m_gameObjects.push_back(m_buttons[i]);
		m_renderableObjects.push_back(m_buttons[i]);
	}
	return true;
}

bool MenuState::onExit() {
	std::cout << "exiting MenuState\n";
	return true;
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2012 Kolibre

This file is part of kolibre-narrator.

Kolibre-narrator is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.

Kolibre-narrator 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with kolibre-narrator. If not, see <http://www.gnu.org/licenses/>.
*/

#include "Message.h"
#include "Mp3Stream.h"

#include <cstdio>
#include <sstream>
#include <math.h>
#include <log4cxx/logger.h>

// create logger which will become a child to logger kolibre.narrator
log4cxx::LoggerPtr narratorMsLog(log4cxx::Logger::getLogger("kolibre.narrator.mp3stream"));

Mp3Stream::Mp3Stream()
{
    LOG4CXX_INFO(narratorMsLog, "Initializing mp3stream");

    mError = 0;
    mEncoding = 0;
    mChannels = 0;
    mRate = 0;
    isOpen = false;
    openTmpFile = false;
    mTmpFile = "";
    scaleNegative = powf(2, 16);
    scalePositive = scaleNegative - 1;

    mpg123_init();
    mh = mpg123_new(NULL, &mError);
    mFrameSize = mpg123_outblock(mh);
}

Mp3Stream::~Mp3Stream()
{
    close();
    if (mh) mpg123_delete(mh);
    mpg123_exit();
}

bool Mp3Stream::open(const MessageAudio &ma)
{
    // opening mp3 audio from database could possibly be done by libmpg123 feed API calls
    // but since this fearture will bu used very seldom it's sufficient to create temporary files
    // and let libmpg123 open a file on the filesystem

    size_t bytesToRead = ma.getSize();

    // read audio data from database to buffer
    LOG4CXX_DEBUG(narratorMsLog, "reading " << bytesToRead << " bytes from database");
    currentAudio = ma;
    char *buffer;
    buffer = (char *) malloc (bytesToRead * sizeof(char));
    size_t bytesRead = currentAudio.read(buffer, sizeof(char), bytesToRead);
    currentAudio.close();

    // write buffer data to tmp file
    mTmpFile = std::tmpnam(NULL);
    LOG4CXX_DEBUG(narratorMsLog, "creating temporary file " << mTmpFile);
    FILE *pFile = fopen(mTmpFile.c_str(), "wb");
    if (pFile == NULL)
    {
        LOG4CXX_ERROR(narratorMsLog, "failed to open temporary file");
        free(buffer);
        return false;
    }
    LOG4CXX_DEBUG(narratorMsLog, "writing " << bytesRead << " bytes to file");
    fwrite(buffer, sizeof(char), bytesRead, pFile);
    fclose(pFile);
    free(buffer);

    openTmpFile = true;
    return open(mTmpFile);
}

bool Mp3Stream::open(string path)
{
    // open file
    int result = mpg123_open(mh, path.c_str());
    if (result != MPG123_OK)
    {
        LOG4CXX_ERROR(narratorMsLog, "File " << path << " could not be opened");
        return false;
    }

    // get rate, channels and encoding
    mpg123_getformat(mh, &mRate, &mChannels, &mEncoding);
    isOpen = true;

    return true;
}

// Returns samples (1 sample contains data from all channels)
long Mp3Stream::read(float* buffer, int bytes)
{
    LOG4CXX_TRACE(narratorMsLog, "read " << bytes << " bytes from mp3 file");

    // mpg123 uses enconding MPG123_ENC_SIGNED_16 which results in decoded short samples
    short *shortBuffer;
    shortBuffer = new short[bytes*mChannels];

    size_t done = 0;
    int result = mpg123_read(mh, (unsigned char*)shortBuffer, bytes*mChannels*sizeof(short), &done);

    switch (result)
    {
        case MPG123_DONE:
            LOG4CXX_DEBUG(narratorMsLog, "End of stream");
            break;
        case MPG123_OK:
            break;
    }

    LOG4CXX_TRACE(narratorMsLog, done << " bytes decoded");

    // convert short buffer to scaled float buffer
    float *bufptr = buffer;
    for (int i = 0; i < done/sizeof(short); i++)
    {
        int value = (int)shortBuffer[i];
        if (value == 0)
        {
            *buffer++ = 0.f;
        }
        else if (value < 0)
        {
            // multiple with 2.0f to increase volume by a factor of 2 (+6dB)
            *buffer++ = (float)(value/scaleNegative) * 2.0f;
        }
        else
        {
            // multiple with 2.0f to increase volume by a factor of 2 (+6dB)
            *buffer++ = (float)(value/scalePositive) * 2.0f;
        }
    }
    delete shortBuffer;

    return done/sizeof(short);
}

bool Mp3Stream::close()
{
    if (openTmpFile)
    {
        LOG4CXX_DEBUG(narratorMsLog, "deleting temporary file " << mTmpFile);
        if (remove(mTmpFile.c_str()) != 0) LOG4CXX_WARN(narratorMsLog, "file could not be deleted");
        openTmpFile = false;
        mTmpFile = "";
    }
    if (isOpen)
    {
        mpg123_close(mh);
        isOpen = false;
    }
    return true;
}

long Mp3Stream::getRate()
{
    return mRate;
}

long Mp3Stream::getChannels()
{
    return mChannels;
}
<commit_msg>Fix double free crash when decoding mp3 audio with two channels<commit_after>/*
Copyright (C) 2012 Kolibre

This file is part of kolibre-narrator.

Kolibre-narrator is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.

Kolibre-narrator 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with kolibre-narrator. If not, see <http://www.gnu.org/licenses/>.
*/

#include "Message.h"
#include "Mp3Stream.h"

#include <cstdio>
#include <sstream>
#include <math.h>
#include <log4cxx/logger.h>

// create logger which will become a child to logger kolibre.narrator
log4cxx::LoggerPtr narratorMsLog(log4cxx::Logger::getLogger("kolibre.narrator.mp3stream"));

Mp3Stream::Mp3Stream()
{
    LOG4CXX_INFO(narratorMsLog, "Initializing mp3stream");

    mError = 0;
    mEncoding = 0;
    mChannels = 0;
    mRate = 0;
    isOpen = false;
    openTmpFile = false;
    mTmpFile = "";
    scaleNegative = powf(2, 16);
    scalePositive = scaleNegative - 1;

    mpg123_init();
    mh = mpg123_new(NULL, &mError);
    mFrameSize = mpg123_outblock(mh);
}

Mp3Stream::~Mp3Stream()
{
    close();
    if (mh) mpg123_delete(mh);
    mpg123_exit();
}

bool Mp3Stream::open(const MessageAudio &ma)
{
    // opening mp3 audio from database could possibly be done by libmpg123 feed API calls
    // but since this fearture will bu used very seldom it's sufficient to create temporary files
    // and let libmpg123 open a file on the filesystem

    size_t bytesToRead = ma.getSize();

    // read audio data from database to buffer
    LOG4CXX_DEBUG(narratorMsLog, "reading " << bytesToRead << " bytes from database");
    currentAudio = ma;
    char *buffer;
    buffer = (char *) malloc (bytesToRead * sizeof(char));
    size_t bytesRead = currentAudio.read(buffer, sizeof(char), bytesToRead);
    currentAudio.close();

    // write buffer data to tmp file
    mTmpFile = std::tmpnam(NULL);
    LOG4CXX_DEBUG(narratorMsLog, "creating temporary file " << mTmpFile);
    FILE *pFile = fopen(mTmpFile.c_str(), "wb");
    if (pFile == NULL)
    {
        LOG4CXX_ERROR(narratorMsLog, "failed to open temporary file");
        free(buffer);
        return false;
    }
    LOG4CXX_DEBUG(narratorMsLog, "writing " << bytesRead << " bytes to file");
    fwrite(buffer, sizeof(char), bytesRead, pFile);
    fclose(pFile);
    free(buffer);

    openTmpFile = true;
    return open(mTmpFile);
}

bool Mp3Stream::open(string path)
{
    // open file
    int result = mpg123_open(mh, path.c_str());
    if (result != MPG123_OK)
    {
        LOG4CXX_ERROR(narratorMsLog, "File " << path << " could not be opened");
        return false;
    }

    // get rate, channels and encoding
    mpg123_getformat(mh, &mRate, &mChannels, &mEncoding);
    isOpen = true;

    return true;
}

// Returns samples (1 sample contains data from all channels)
long Mp3Stream::read(float* buffer, int bytes)
{
    LOG4CXX_TRACE(narratorMsLog, "read " << bytes << " bytes from mp3 file");

    // mpg123 uses enconding MPG123_ENC_SIGNED_16 which results in decoded short samples
    short *shortBuffer;
    shortBuffer = new short[bytes*mChannels];

    size_t done = 0;
    int result = mpg123_read(mh, (unsigned char*)shortBuffer, bytes*sizeof(short), &done);

    switch (result)
    {
        case MPG123_DONE:
            LOG4CXX_DEBUG(narratorMsLog, "End of stream");
            break;
        case MPG123_OK:
            break;
    }

    LOG4CXX_TRACE(narratorMsLog, done << " bytes decoded");

    // convert short buffer to scaled float buffer
    float *bufptr = buffer;
    for (int i = 0; i < done/sizeof(short); i++)
    {
        int value = (int)shortBuffer[i];
        if (value == 0)
        {
            *buffer++ = 0.f;
        }
        else if (value < 0)
        {
            // multiple with 2.0f to increase volume by a factor of 2 (+6dB)
            *buffer++ = (float)(value/scaleNegative) * 2.0f;
        }
        else
        {
            // multiple with 2.0f to increase volume by a factor of 2 (+6dB)
            *buffer++ = (float)(value/scalePositive) * 2.0f;
        }
    }
    delete shortBuffer;

    return done/sizeof(short);
}

bool Mp3Stream::close()
{
    if (openTmpFile)
    {
        LOG4CXX_DEBUG(narratorMsLog, "deleting temporary file " << mTmpFile);
        if (remove(mTmpFile.c_str()) != 0) LOG4CXX_WARN(narratorMsLog, "file could not be deleted");
        openTmpFile = false;
        mTmpFile = "";
    }
    if (isOpen)
    {
        mpg123_close(mh);
        isOpen = false;
    }
    return true;
}

long Mp3Stream::getRate()
{
    return mRate;
}

long Mp3Stream::getChannels()
{
    return mChannels;
}
<|endoftext|>


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

#include <iostream>
#include <teetime/stages/RandomIntProducer.h>
#include <teetime/stages/AbstractConsumerStage.h>
#include <teetime/stages/FunctionStage.h>
#include <teetime/stages/CollectorSink.h>
#include <teetime/stages/DistributorStage.h>
#include <teetime/stages/MergerStage.h>
#include <teetime/Configuration.h>
#include <teetime/Md5Hash.h>
#include <teetime/ports/Port.h>
#include <teetime/logging.h>
#include <teetime/platform.h>
#include <climits>
#include <string>
#include <random>
#include "Benchmark.h"

using namespace teetime;

namespace {

class Producer : public AbstractProducerStage<Md5Hash>
{
public:
  Producer(int min, int max, int num)
    : m_min(min)
    , m_max(max)
    , m_num(num)
  {}

private:
  virtual void execute() override
  {
    if (m_min == m_max)
    {
      auto hash = Md5Hash::generate(&m_min, sizeof(m_min));
      for (int i = 0; i < m_num; ++i)
      {
        AbstractProducerStage<Md5Hash>::getOutputPort().send(Md5Hash(hash));
      }
    }
    else
    {
      //std::random_device                  rand_dev;
      std::mt19937                        generator(0); //TODO(johl): currently using 0 as seed (instead of rand_dev) for reproducable results. This should be adjustable.
      std::uniform_int_distribution<int>  distr(m_min, m_max);

      for (int i = 0; i < m_num; ++i)
      {
        int value = distr(generator);
        AbstractProducerStage<Md5Hash>::getOutputPort().send(Md5Hash::generate(&value, sizeof(value)));
      }
    }

    AbstractProducerStage<Md5Hash>::terminate();
  }

  int m_min;
  int m_max;
  int m_num;
};

int reverseHash(Md5Hash hash) {
  for(int i=0; i<INT_MAX; ++i) {
    if( Md5Hash::generate(&i, sizeof(i)) == hash ) {
      return i;
    }
  }

  return -1;
}

class Config2 : public Configuration
{
public:
  Config2(const Params& params, int threads, const std::vector<int>& affinity)
  {
    CpuDispenser cpus(affinity);

    int min = params.getInt32("minvalue");
    int max = params.getInt32("maxvalue");
    int num = params.getInt32("num");

    auto producer = createStage<Producer>(min, max, num);
    auto distributor = createStage<DistributorStage<Md5Hash>>();
    auto merger = createStage<MergerStage<int>>();
    auto sink = createStage<CollectorSink<int>>();

    declareStageActive(producer, cpus.next());
    declareStageActive(merger, cpus.next());

    for(int i=0; i<threads; ++i)
    {
      auto revhash = createStageFromFunction<Md5Hash, int, reverseHash>();
      declareStageActive(revhash, cpus.next());

      connectPorts(distributor->getNewOutputPort(), revhash->getInputPort());
      connectPorts(revhash->getOutputPort(), merger->getNewInputPort());
    }

    connectPorts(producer->getOutputPort(), distributor->getInputPort());
    connectPorts(merger->getOutputPort(), sink->getInputPort());
  }
};

}

void benchmark_teetime(const Params& params, int threads)
{
  Config2 config(params, threads, affinity_none);
  config.executeBlocking();
}

void benchmark_teetime_prefer_same_cpu(const Params& params, int threads)
{
  Config2 config(params, threads, affinity_preferSameCpu);
  config.executeBlocking();
}

void benchmark_teetime_avoid_same_core(const Params& params, int threads)
{
  Config2 config(params, threads, affinity_avoidSameCore);
  config.executeBlocking();
}<commit_msg>fixed queue capacity<commit_after>/**
 * Copyright (C) 2016 Johannes Ohlemacher (https://github.com/eXistence/TeeTime-Cpp)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>
#include <teetime/stages/RandomIntProducer.h>
#include <teetime/stages/AbstractConsumerStage.h>
#include <teetime/stages/FunctionStage.h>
#include <teetime/stages/CollectorSink.h>
#include <teetime/stages/DistributorStage.h>
#include <teetime/stages/MergerStage.h>
#include <teetime/Configuration.h>
#include <teetime/Md5Hash.h>
#include <teetime/ports/Port.h>
#include <teetime/logging.h>
#include <teetime/platform.h>
#include <climits>
#include <string>
#include <random>
#include "Benchmark.h"

using namespace teetime;

namespace {

class Producer : public AbstractProducerStage<Md5Hash>
{
public:
  Producer(int min, int max, int num)
    : m_min(min)
    , m_max(max)
    , m_num(num)
  {}

private:
  virtual void execute() override
  {
    if (m_min == m_max)
    {
      auto hash = Md5Hash::generate(&m_min, sizeof(m_min));
      for (int i = 0; i < m_num; ++i)
      {
        AbstractProducerStage<Md5Hash>::getOutputPort().send(Md5Hash(hash));
      }
    }
    else
    {
      //std::random_device                  rand_dev;
      std::mt19937                        generator(0); //TODO(johl): currently using 0 as seed (instead of rand_dev) for reproducable results. This should be adjustable.
      std::uniform_int_distribution<int>  distr(m_min, m_max);

      for (int i = 0; i < m_num; ++i)
      {
        int value = distr(generator);
        AbstractProducerStage<Md5Hash>::getOutputPort().send(Md5Hash::generate(&value, sizeof(value)));
      }
    }

    AbstractProducerStage<Md5Hash>::terminate();
  }

  int m_min;
  int m_max;
  int m_num;
};

int reverseHash(Md5Hash hash) {
  for(int i=0; i<INT_MAX; ++i) {
    if( Md5Hash::generate(&i, sizeof(i)) == hash ) {
      return i;
    }
  }

  return -1;
}

class Config2 : public Configuration
{
public:
  Config2(const Params& params, int threads, const std::vector<int>& affinity)
  {
    CpuDispenser cpus(affinity);

    int min = params.getInt32("minvalue");
    int max = params.getInt32("maxvalue");
    int num = params.getInt32("num");

    auto producer = createStage<Producer>(min, max, num);
    auto distributor = createStage<DistributorStage<Md5Hash>>();
    auto merger = createStage<MergerStage<int>>();
    auto sink = createStage<CollectorSink<int>>();

    declareStageActive(producer, cpus.next());
    declareStageActive(merger, cpus.next());

    for(int i=0; i<threads; ++i)
    {
      auto revhash = createStageFromFunction<Md5Hash, int, reverseHash>();
      declareStageActive(revhash, cpus.next());

      connectPorts(distributor->getNewOutputPort(), revhash->getInputPort(), 4096);
      connectPorts(revhash->getOutputPort(), merger->getNewInputPort(), 4096);
    }

    connectPorts(producer->getOutputPort(), distributor->getInputPort(), 4096);
    connectPorts(merger->getOutputPort(), sink->getInputPort(), 4096);
  }
};

}

void benchmark_teetime(const Params& params, int threads)
{
  Config2 config(params, threads, affinity_none);
  config.executeBlocking();
}

void benchmark_teetime_prefer_same_cpu(const Params& params, int threads)
{
  Config2 config(params, threads, affinity_preferSameCpu);
  config.executeBlocking();
}

void benchmark_teetime_avoid_same_core(const Params& params, int threads)
{
  Config2 config(params, threads, affinity_avoidSameCore);
  config.executeBlocking();
}<|endoftext|>


<commit_before>#include <vector>
#include <iostream>
#include <iomanip>
#include <thread>

#include "Processor.hpp"

using namespace std;

const uint32_t Processor::interruptHandlerAddress = 0x00010000;

void Processor::handleInterruption() {
    if (cp0->interruptable() && cp0->interrupting()) {
        // save current PC to EPC
        cp0->regs[14] = pc;
        // set PC to interrupt handler address
        pc = interruptHandlerAddress;
        // disable interrupt from the same device
        cp0->disableInterruptForCode(cp0->interruptingBusCode());
    }
}

void Processor::tick() {
    d.deAsm(bus->at(pc >> 2)->get());
    pc += 4;
    handleInterruption();

    switch(d.opcode) {
        case 0b000000:
            // R-type instruction
            switch(d.func) {
                case 0b100000: regs[d.rd] = regs[d.rs] + regs[d.rt]; break;       // add
                case 0b100001: regs[d.rd] = regs[d.rs] + regs[d.rt]; break;       // addu
                case 0b100010: regs[d.rd] = regs[d.rs] - regs[d.rt]; break;       // sub
                case 0b100011: regs[d.rd] = regs[d.rs] - regs[d.rt]; break;       // subu
                case 0b100100: regs[d.rd] = regs[d.rs] & regs[d.rt]; break;       // and
                case 0b100101: regs[d.rd] = regs[d.rs] | regs[d.rt]; break;       // or
                case 0b100110: regs[d.rd] = regs[d.rs] ^ regs[d.rt]; break;       // xor
                case 0b100111: regs[d.rd] = ~(regs[d.rs] | regs[d.rt]); break;    // nor
                case 0b101010:
                    regs[d.rd] = (int32_t)(regs[d.rs] - regs[d.rt]) < 0 ? 1 : 0; break;    // slt
                case 0b101011:
                    regs[d.rd] = (int32_t)(regs[d.rs] - regs[d.rt]) < 0 ? 1 : 0; break;    // sltu
                case 0b000000: regs[d.rd] = regs[d.rt] << regs[d.shamt]; break;   // sll
                case 0b000010: regs[d.rd] = regs[d.rt] >> regs[d.shamt]; break;   // srl
                case 0b000011:
                    regs[d.rd] = (uint32_t)((int32_t)regs[d.rs] >> regs[d.rt]);   // sra
                    break;
                case 0b000100: regs[d.rd] = regs[d.rt] << regs[d.rs]; break;      // sllv
                case 0b000110: regs[d.rd] = regs[d.rt] >> regs[d.rs]; break;      // srlv
                case 0b000111:
                    regs[d.rd] = (uint32_t)((int32_t)regs[d.rt] >> regs[d.rs]);   // srav
                    break;
                case 0b001000: pc = regs[d.rs]; break;                            // jr
            }
            break;
        // I-type instruction
        case 0b001000: regs[d.rt] = regs[d.rs] + d.signedExtImm; break;               // addi
        case 0b001001: regs[d.rt] = regs[d.rs] + d.signedExtImm; break;               // addiu
        case 0b001100: regs[d.rt] = regs[d.rs] & d.signedExtImm; break;               // andi
        case 0b001101: regs[d.rt] = regs[d.rs] | d.signedExtImm; break;               // ori
        case 0b001110: regs[d.rt] = regs[d.rs] ^ d.signedExtImm; break;               // xori
        case 0b001111: regs[d.rt] = d.signedExtImm << 16; break;                      // lui
        case 0b100011: regs[d.rt] = bus->at(regs[d.rs] + d.signedExtImm)->get(); break;     // lw
        case 0b101011: bus->at(regs[d.rs] + d.signedExtImm)->set(regs[d.rt]); break;        // sw
        case 0b000100: if (regs[d.rs] == regs[d.rt]) pc += d.signedExtImm; break;     // beq
        case 0b000101: if (regs[d.rt] != regs[d.rs]) pc += d.signedExtImm; break;     // bne
        case 0b001010: regs[d.rt] = regs[d.rs] < d.signedExtImm ? 1 : 0; break;       // slti
        case 0b001011: regs[d.rt] = regs[d.rs] < d.signedExtImm ? 1 : 0; break;       // sltiu
        // J-type instruction
        case 0b000010: pc = d.address; break;                                         // j
        case 0b000011: regs[31] = pc; pc = d.address; break;                          // jal
    }

    //dump();
    //cout << "0x" << setfill('0') << setw(8) << hex << ((pc >> 2) - 1) << endl << endl;
}

void Processor::dump() const {
    const static string regNames[] = {
        "zero", "at",
        "v0", "v1", "a0", "a1", "a2", "a3",
        "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
        "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
        "t8", "t9",
        "k0", "k1",
        "gp", "sp", "fp", "ra"
    };

    for (int i = 0; i < 32; ++i) {
        cout << regNames[i] << ": " << "0x" << setfill('0') << setw(8) << hex << regs[i] << "\t";
        if (((i + 1) % 8) == 0)
            cout << endl;
    }
}
<commit_msg>fix: shift shamt instead of regs[shamt]<commit_after>#include <vector>
#include <iostream>
#include <iomanip>
#include <thread>

#include "Processor.hpp"

using namespace std;

const uint32_t Processor::interruptHandlerAddress = 0x00010000;

void Processor::handleInterruption() {
    if (cp0->interruptable() && cp0->interrupting()) {
        // save current PC to EPC
        cp0->regs[14] = pc;
        // set PC to interrupt handler address
        pc = interruptHandlerAddress;
        // disable interrupt from the same device
        cp0->disableInterruptForCode(cp0->interruptingBusCode());
    }
}

void Processor::tick() {
    d.deAsm(bus->at(pc >> 2)->get());
    pc += 4;
    handleInterruption();

    switch(d.opcode) {
        case 0b000000:
            // R-type instruction
            switch(d.func) {
                case 0b100000: regs[d.rd] = regs[d.rs] + regs[d.rt]; break;       // add
                case 0b100001: regs[d.rd] = regs[d.rs] + regs[d.rt]; break;       // addu
                case 0b100010: regs[d.rd] = regs[d.rs] - regs[d.rt]; break;       // sub
                case 0b100011: regs[d.rd] = regs[d.rs] - regs[d.rt]; break;       // subu
                case 0b100100: regs[d.rd] = regs[d.rs] & regs[d.rt]; break;       // and
                case 0b100101: regs[d.rd] = regs[d.rs] | regs[d.rt]; break;       // or
                case 0b100110: regs[d.rd] = regs[d.rs] ^ regs[d.rt]; break;       // xor
                case 0b100111: regs[d.rd] = ~(regs[d.rs] | regs[d.rt]); break;    // nor
                case 0b101010:
                    regs[d.rd] = (int32_t)(regs[d.rs] - regs[d.rt]) < 0 ? 1 : 0; break;    // slt
                case 0b101011:
                    regs[d.rd] = (int32_t)(regs[d.rs] - regs[d.rt]) < 0 ? 1 : 0; break;    // sltu
                case 0b000000: regs[d.rd] = regs[d.rt] << d.shamt; break;   // sll
                case 0b000010: regs[d.rd] = regs[d.rt] >> d.shamt; break;   // srl
                case 0b000011:
                    regs[d.rd] = (uint32_t)((int32_t)regs[d.rs] >> regs[d.rt]);   // sra
                    break;
                case 0b000100: regs[d.rd] = regs[d.rt] << regs[d.rs]; break;      // sllv
                case 0b000110: regs[d.rd] = regs[d.rt] >> regs[d.rs]; break;      // srlv
                case 0b000111:
                    regs[d.rd] = (uint32_t)((int32_t)regs[d.rt] >> regs[d.rs]);   // srav
                    break;
                case 0b001000: pc = regs[d.rs]; break;                            // jr
            }
            break;
        // I-type instruction
        case 0b001000: regs[d.rt] = regs[d.rs] + d.signedExtImm; break;               // addi
        case 0b001001: regs[d.rt] = regs[d.rs] + d.signedExtImm; break;               // addiu
        case 0b001100: regs[d.rt] = regs[d.rs] & d.signedExtImm; break;               // andi
        case 0b001101: regs[d.rt] = regs[d.rs] | d.signedExtImm; break;               // ori
        case 0b001110: regs[d.rt] = regs[d.rs] ^ d.signedExtImm; break;               // xori
        case 0b001111: regs[d.rt] = d.signedExtImm << 16; break;                      // lui
        case 0b100011: regs[d.rt] = bus->at(regs[d.rs] + d.signedExtImm)->get(); break;     // lw
        case 0b101011: bus->at(regs[d.rs] + d.signedExtImm)->set(regs[d.rt]); break;        // sw
        case 0b000100: if (regs[d.rs] == regs[d.rt]) pc += d.signedExtImm; break;     // beq
        case 0b000101: if (regs[d.rt] != regs[d.rs]) pc += d.signedExtImm; break;     // bne
        case 0b001010: regs[d.rt] = regs[d.rs] < d.signedExtImm ? 1 : 0; break;       // slti
        case 0b001011: regs[d.rt] = regs[d.rs] < d.signedExtImm ? 1 : 0; break;       // sltiu
        // J-type instruction
        case 0b000010: pc = d.address; break;                                         // j
        case 0b000011: regs[31] = pc; pc = d.address; break;                          // jal
    }

    if (debug) {
        dump();
        cout << "PC: 0x" << setfill('0') << setw(8) << hex << ((pc >> 2) - 1) << endl << endl;
    }
}

void Processor::dump() const {
    const static string regNames[] = {
        "zero", "at",
        "v0", "v1", "a0", "a1", "a2", "a3",
        "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
        "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
        "t8", "t9",
        "k0", "k1",
        "gp", "sp", "fp", "ra"
    };

    for (int i = 0; i < 32; ++i) {
        cout << regNames[i] << ": " << "0x" << setfill('0') << setw(8) << hex << regs[i] << "\t";
        if (((i + 1) % 8) == 0)
            cout << endl;
    }
}
<|endoftext|>


<commit_before>/** @file RunStyles.cxx
 ** Data structure used to store sparse styles.
 **/
// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

#include <stdexcept>

#include "Platform.h"

#include "Scintilla.h"
#include "SplitVector.h"
#include "Partitioning.h"
#include "RunStyles.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

// Find the first run at a position
int RunStyles::RunFromPosition(int position) const {
	int run = starts->PartitionFromPosition(position);
	// Go to first element with this position
	while ((run > 0) && (position == starts->PositionFromPartition(run-1))) {
		run--;
	}
	return run;
}

// If there is no run boundary at position, insert one continuing style.
int RunStyles::SplitRun(int position) {
	int run = RunFromPosition(position);
	int posRun = starts->PositionFromPartition(run);
	if (posRun < position) {
		int runStyle = ValueAt(position);
		run++;
		starts->InsertPartition(run, position);
		styles->InsertValue(run, 1, runStyle);
	}
	return run;
}

void RunStyles::RemoveRun(int run) {
	starts->RemovePartition(run);
	styles->DeleteRange(run, 1);
}

void RunStyles::RemoveRunIfEmpty(int run) {
	if ((run < starts->Partitions()) && (starts->Partitions() > 1)) {
		if (starts->PositionFromPartition(run) == starts->PositionFromPartition(run+1)) {
			RemoveRun(run);
		}
	}
}

void RunStyles::RemoveRunIfSameAsPrevious(int run) {
	if ((run > 0) && (run < starts->Partitions())) {
		if (styles->ValueAt(run-1) == styles->ValueAt(run)) {
			RemoveRun(run);
		}
	}
}

RunStyles::RunStyles() {
	starts = new Partitioning(8);
	styles = new SplitVector<int>();
	styles->InsertValue(0, 2, 0);
}

RunStyles::~RunStyles() {
	delete starts;
	starts = NULL;
	delete styles;
	styles = NULL;
}

int RunStyles::Length() const {
	return starts->PositionFromPartition(starts->Partitions());
}

int RunStyles::ValueAt(int position) const {
	return styles->ValueAt(starts->PartitionFromPosition(position));
}

int RunStyles::FindNextChange(int position, int end) {
	int run = starts->PartitionFromPosition(position);
	if (run < starts->Partitions()) {
		int runChange = starts->PositionFromPartition(run);
		if (runChange > position)
			return runChange;
		int nextChange = starts->PositionFromPartition(run + 1);
		if (nextChange > position) {
			return nextChange;
		} else if (position < end) {
			return end;
		} else {
			return end + 1;
		}
	} else {
		return end + 1;
	}
}

int RunStyles::StartRun(int position) {
	return starts->PositionFromPartition(starts->PartitionFromPosition(position));
}

int RunStyles::EndRun(int position) {
	return starts->PositionFromPartition(starts->PartitionFromPosition(position) + 1);
}

bool RunStyles::FillRange(int &position, int value, int &fillLength) {
	if (fillLength <= 0) {
		throw std::invalid_argument("RunStyles::FillRange <= 0 length.");
	}
	int end = position + fillLength;
	if (end > Length()) {
		throw std::invalid_argument("RunStyles::FillRange length goes past end.");
	}
	int runEnd = RunFromPosition(end);
	if (styles->ValueAt(runEnd) == value) {
		// End already has value so trim range.
		end = starts->PositionFromPartition(runEnd);
		if (position >= end) {
			// Whole range is already same as value so no action
			return false;
		}
		fillLength = end - position;
	} else {
		runEnd = SplitRun(end);
	}
	int runStart = RunFromPosition(position);
	if (styles->ValueAt(runStart) == value) {
		// Start is in expected value so trim range.
		runStart++;
		position = starts->PositionFromPartition(runStart);
		fillLength = end - position;
	} else {
		if (starts->PositionFromPartition(runStart) < position) {
			runStart = SplitRun(position);
			runEnd++;
		}
	}
	if (runStart < runEnd) {
		styles->SetValueAt(runStart, value);
		// Remove each old run over the range
		for (int run=runStart+1; run<runEnd; run++) {
			RemoveRun(runStart+1);
		}
		runEnd = RunFromPosition(end);
		RemoveRunIfSameAsPrevious(runEnd);
		RemoveRunIfSameAsPrevious(runStart);
		runEnd = RunFromPosition(end);
		RemoveRunIfEmpty(runEnd);
		return true;
	} else {
		return false;
	}
}

void RunStyles::SetValueAt(int position, int value) {
	int len = 1;
	FillRange(position, value, len);
}

void RunStyles::InsertSpace(int position, int insertLength) {
	int runStart = RunFromPosition(position);
	if (starts->PositionFromPartition(runStart) == position) {
		int runStyle = ValueAt(position);
		// Inserting at start of run so make previous longer
		if (runStart == 0) {
			// Inserting at start of document so ensure 0
			if (runStyle) {
				styles->SetValueAt(0, 0);
				starts->InsertPartition(1, 0);
				styles->InsertValue(1, 1, runStyle);
				starts->InsertText(0, insertLength);
			} else {
				starts->InsertText(runStart, insertLength);
			}
		} else {
			if (runStyle) {
				starts->InsertText(runStart-1, insertLength);
			} else {
				// Insert at end of run so do not extend style
				starts->InsertText(runStart, insertLength);
			}
		}
	} else {
		starts->InsertText(runStart, insertLength);
	}
}

void RunStyles::DeleteAll() {
	delete starts;
	starts = NULL;
	delete styles;
	styles = NULL;
	starts = new Partitioning(8);
	styles = new SplitVector<int>();
	styles->InsertValue(0, 2, 0);
}

void RunStyles::DeleteRange(int position, int deleteLength) {
	int end = position + deleteLength;
	int runStart = RunFromPosition(position);
	int runEnd = RunFromPosition(end);
	if (runStart == runEnd) {
		// Deleting from inside one run
		starts->InsertText(runStart, -deleteLength);
		RemoveRunIfEmpty(runStart);
	} else {
		runStart = SplitRun(position);
		runEnd = SplitRun(end);
		starts->InsertText(runStart, -deleteLength);
		// Remove each old run over the range
		for (int run=runStart; run<runEnd; run++) {
			RemoveRun(runStart);
		}
		RemoveRunIfEmpty(runStart);
		RemoveRunIfSameAsPrevious(runStart);
	}
}

int RunStyles::Runs() const {
	return starts->Partitions();
}

bool RunStyles::AllSame() const {
	for (int run = 1; run < starts->Partitions(); run++) {
		if (styles->ValueAt(run) != styles->ValueAt(run - 1))
			return false;
	}
	return true;
}

bool RunStyles::AllSameAs(int value) const {
	return AllSame() && (styles->ValueAt(0) == value);
}

int RunStyles::Find(int value, int start) const {
	if (start < Length()) {
		int run = start ? RunFromPosition(start) : 0;
		if (styles->ValueAt(run) == value)
			return start;
		run++;
		while (run < starts->Partitions()) {
			if (styles->ValueAt(run) == value)
				return starts->PositionFromPartition(run);
			run++;
		}
	}
	return -1;
}

void RunStyles::Check() {
	if (Length() < 0) {
		throw std::runtime_error("RunStyles: Length can not be negative.");
	}
	if (starts->Partitions() < 1) {
		throw std::runtime_error("RunStyles: Must always have 1 or more partitions.");
	}
	if (starts->Partitions() != styles->Length()-1) {
		throw std::runtime_error("RunStyles: Partitions and styles different lengths.");
	}
	int start=0;
	while (start < Length()) {
		int end = EndRun(start);
		if (start >= end) {
			throw std::runtime_error("RunStyles: Partition is 0 length.");
		}
		start = end;
	}
	if (styles->ValueAt(styles->Length()-1) != 0) {
		throw std::runtime_error("RunStyles: Unused style at end changed.");
	}
	for (int j=1; j<styles->Length()-1; j++) {
		if (styles->ValueAt(j) == styles->ValueAt(j-1)) {
			throw std::runtime_error("RunStyles: Style of a partition same as previous.");
		}
	}
}
<commit_msg>Existing code fills 0 length ranges and ranges after document end so simply return instead of throwing exceptions.<commit_after>/** @file RunStyles.cxx
 ** Data structure used to store sparse styles.
 **/
// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

#include <stdexcept>

#include "Platform.h"

#include "Scintilla.h"
#include "SplitVector.h"
#include "Partitioning.h"
#include "RunStyles.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

// Find the first run at a position
int RunStyles::RunFromPosition(int position) const {
	int run = starts->PartitionFromPosition(position);
	// Go to first element with this position
	while ((run > 0) && (position == starts->PositionFromPartition(run-1))) {
		run--;
	}
	return run;
}

// If there is no run boundary at position, insert one continuing style.
int RunStyles::SplitRun(int position) {
	int run = RunFromPosition(position);
	int posRun = starts->PositionFromPartition(run);
	if (posRun < position) {
		int runStyle = ValueAt(position);
		run++;
		starts->InsertPartition(run, position);
		styles->InsertValue(run, 1, runStyle);
	}
	return run;
}

void RunStyles::RemoveRun(int run) {
	starts->RemovePartition(run);
	styles->DeleteRange(run, 1);
}

void RunStyles::RemoveRunIfEmpty(int run) {
	if ((run < starts->Partitions()) && (starts->Partitions() > 1)) {
		if (starts->PositionFromPartition(run) == starts->PositionFromPartition(run+1)) {
			RemoveRun(run);
		}
	}
}

void RunStyles::RemoveRunIfSameAsPrevious(int run) {
	if ((run > 0) && (run < starts->Partitions())) {
		if (styles->ValueAt(run-1) == styles->ValueAt(run)) {
			RemoveRun(run);
		}
	}
}

RunStyles::RunStyles() {
	starts = new Partitioning(8);
	styles = new SplitVector<int>();
	styles->InsertValue(0, 2, 0);
}

RunStyles::~RunStyles() {
	delete starts;
	starts = NULL;
	delete styles;
	styles = NULL;
}

int RunStyles::Length() const {
	return starts->PositionFromPartition(starts->Partitions());
}

int RunStyles::ValueAt(int position) const {
	return styles->ValueAt(starts->PartitionFromPosition(position));
}

int RunStyles::FindNextChange(int position, int end) {
	int run = starts->PartitionFromPosition(position);
	if (run < starts->Partitions()) {
		int runChange = starts->PositionFromPartition(run);
		if (runChange > position)
			return runChange;
		int nextChange = starts->PositionFromPartition(run + 1);
		if (nextChange > position) {
			return nextChange;
		} else if (position < end) {
			return end;
		} else {
			return end + 1;
		}
	} else {
		return end + 1;
	}
}

int RunStyles::StartRun(int position) {
	return starts->PositionFromPartition(starts->PartitionFromPosition(position));
}

int RunStyles::EndRun(int position) {
	return starts->PositionFromPartition(starts->PartitionFromPosition(position) + 1);
}

bool RunStyles::FillRange(int &position, int value, int &fillLength) {
	if (fillLength <= 0) {
		return false;
	}
	int end = position + fillLength;
	if (end > Length()) {
		return false;
	}
	int runEnd = RunFromPosition(end);
	if (styles->ValueAt(runEnd) == value) {
		// End already has value so trim range.
		end = starts->PositionFromPartition(runEnd);
		if (position >= end) {
			// Whole range is already same as value so no action
			return false;
		}
		fillLength = end - position;
	} else {
		runEnd = SplitRun(end);
	}
	int runStart = RunFromPosition(position);
	if (styles->ValueAt(runStart) == value) {
		// Start is in expected value so trim range.
		runStart++;
		position = starts->PositionFromPartition(runStart);
		fillLength = end - position;
	} else {
		if (starts->PositionFromPartition(runStart) < position) {
			runStart = SplitRun(position);
			runEnd++;
		}
	}
	if (runStart < runEnd) {
		styles->SetValueAt(runStart, value);
		// Remove each old run over the range
		for (int run=runStart+1; run<runEnd; run++) {
			RemoveRun(runStart+1);
		}
		runEnd = RunFromPosition(end);
		RemoveRunIfSameAsPrevious(runEnd);
		RemoveRunIfSameAsPrevious(runStart);
		runEnd = RunFromPosition(end);
		RemoveRunIfEmpty(runEnd);
		return true;
	} else {
		return false;
	}
}

void RunStyles::SetValueAt(int position, int value) {
	int len = 1;
	FillRange(position, value, len);
}

void RunStyles::InsertSpace(int position, int insertLength) {
	int runStart = RunFromPosition(position);
	if (starts->PositionFromPartition(runStart) == position) {
		int runStyle = ValueAt(position);
		// Inserting at start of run so make previous longer
		if (runStart == 0) {
			// Inserting at start of document so ensure 0
			if (runStyle) {
				styles->SetValueAt(0, 0);
				starts->InsertPartition(1, 0);
				styles->InsertValue(1, 1, runStyle);
				starts->InsertText(0, insertLength);
			} else {
				starts->InsertText(runStart, insertLength);
			}
		} else {
			if (runStyle) {
				starts->InsertText(runStart-1, insertLength);
			} else {
				// Insert at end of run so do not extend style
				starts->InsertText(runStart, insertLength);
			}
		}
	} else {
		starts->InsertText(runStart, insertLength);
	}
}

void RunStyles::DeleteAll() {
	delete starts;
	starts = NULL;
	delete styles;
	styles = NULL;
	starts = new Partitioning(8);
	styles = new SplitVector<int>();
	styles->InsertValue(0, 2, 0);
}

void RunStyles::DeleteRange(int position, int deleteLength) {
	int end = position + deleteLength;
	int runStart = RunFromPosition(position);
	int runEnd = RunFromPosition(end);
	if (runStart == runEnd) {
		// Deleting from inside one run
		starts->InsertText(runStart, -deleteLength);
		RemoveRunIfEmpty(runStart);
	} else {
		runStart = SplitRun(position);
		runEnd = SplitRun(end);
		starts->InsertText(runStart, -deleteLength);
		// Remove each old run over the range
		for (int run=runStart; run<runEnd; run++) {
			RemoveRun(runStart);
		}
		RemoveRunIfEmpty(runStart);
		RemoveRunIfSameAsPrevious(runStart);
	}
}

int RunStyles::Runs() const {
	return starts->Partitions();
}

bool RunStyles::AllSame() const {
	for (int run = 1; run < starts->Partitions(); run++) {
		if (styles->ValueAt(run) != styles->ValueAt(run - 1))
			return false;
	}
	return true;
}

bool RunStyles::AllSameAs(int value) const {
	return AllSame() && (styles->ValueAt(0) == value);
}

int RunStyles::Find(int value, int start) const {
	if (start < Length()) {
		int run = start ? RunFromPosition(start) : 0;
		if (styles->ValueAt(run) == value)
			return start;
		run++;
		while (run < starts->Partitions()) {
			if (styles->ValueAt(run) == value)
				return starts->PositionFromPartition(run);
			run++;
		}
	}
	return -1;
}

void RunStyles::Check() {
	if (Length() < 0) {
		throw std::runtime_error("RunStyles: Length can not be negative.");
	}
	if (starts->Partitions() < 1) {
		throw std::runtime_error("RunStyles: Must always have 1 or more partitions.");
	}
	if (starts->Partitions() != styles->Length()-1) {
		throw std::runtime_error("RunStyles: Partitions and styles different lengths.");
	}
	int start=0;
	while (start < Length()) {
		int end = EndRun(start);
		if (start >= end) {
			throw std::runtime_error("RunStyles: Partition is 0 length.");
		}
		start = end;
	}
	if (styles->ValueAt(styles->Length()-1) != 0) {
		throw std::runtime_error("RunStyles: Unused style at end changed.");
	}
	for (int j=1; j<styles->Length()-1; j++) {
		if (styles->ValueAt(j) == styles->ValueAt(j-1)) {
			throw std::runtime_error("RunStyles: Style of a partition same as previous.");
		}
	}
}
<|endoftext|>