<commit_before>#include "AutomationEditor.h"
#include "SDL.h"
#include "ISynth.h"
#include "IPlayer.h"
#include "Renderer.h"
#include "ModularSynth.h"
#include "SynthModule.h"
#include "EditorState.h"
#include "ModuleSelector.h"
#include "Color.h"
#include "Synth.h"
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>

AutomationEditor::AutomationEditor(EditorState& editorState, ISynth& synth, IPlayer& player)
	:Editor(editorState, true), mSynth(synth), mSelectedNode(-1), mSelectedTrack(0)
{
	mEditorState.patternEditor.currentRow.addListener(this);
	mEditorState.sequenceEditor.currentRow.addListener(this);
}

AutomationEditor::~AutomationEditor()
{
}

SDL_Rect AutomationEditor::getNodeArea(const SDL_Rect& parent, int index) const
{
	const Synth& synth = static_cast<const Synth&>(mSynth);
	const Synth::AutomationNode& node = getAutomationTrack().getNode(index);

	return getNodeArea(parent, node);
}

SDL_Rect AutomationEditor::getNodeArea(const SDL_Rect& parent, const Synth::AutomationNode& node) const
{
	const int nodeWidth = 5;
	const int nodeHeight = 5;

	SDL_Rect area = {
		node.time + parent.x - nodeWidth / 2 - getScrollPosition(),
		static_cast<int>((1.0f - node.value) * parent.h) + parent.y - nodeHeight / 2,
		nodeWidth, nodeHeight
	};

	return area;
}

void AutomationEditor::onDraw(Renderer& renderer, const SDL_Rect& area)
{
	setDirty(false);

	if (mModal != NULL)
	{
		return;
	}

	renderer.setClip(area);
	renderer.renderBackground(area);

	const Synth& synth = getSynth();
	int patternLength = synth.getPatternLength();

	for (int x = area.x - getScrollPosition() ; x < area.w + area.x ; x += patternLength)
	{
		renderer.renderLine(x, area.y, x, area.y + area.h, Color(64,64,64));
	}

	float time = synth.getSongPosition();
	int editPos = mEditorState.patternEditor.currentRow + mEditorState.sequenceEditor.currentRow * patternLength;

	renderer.renderLine(time - getScrollPosition() + area.x, area.y, time - getScrollPosition() + area.x, area.y + area.h, Color(0,0,128));
	renderer.renderLine(editPos - getScrollPosition() + area.x, area.y, editPos - getScrollPosition() + area.x, area.y + area.h, Color(255,255,255));

	for (int track = 0 ; track < Synth::maxAutomationTracks ; ++track)
	{
		if (track == mSelectedTrack)
		{
			continue;
		}

		if (synth.getAutomationTrack(track).numNodes > 0)
		{
			SDL_Rect nodeArea = getNodeArea(area, synth.getAutomationTrack(track).nodes[0]);
			int px = nodeArea.x + nodeArea.w / 2;
			int py = nodeArea.y + nodeArea.h / 2;

			for (int i = 1 ; i < synth.getAutomationTrack(track).numNodes ; ++i)
			{
				SDL_Rect nodeArea = getNodeArea(area, synth.getAutomationTrack(track).nodes[i]);
				int x = nodeArea.x + nodeArea.w / 2;
				int y = nodeArea.y + nodeArea.h / 2;

				renderer.renderLine(px, py, x, y, track == mSelectedTrack ? Color(255, 255, 255) : Color(64, 64, 64));

				px = x;
				py = y;
			}
		}
	}

	if (getAutomationTrack().numNodes > 0)
	{
		SDL_Rect nodeArea = getNodeArea(area, 0);
		int px = nodeArea.x + nodeArea.w / 2;
		int py = nodeArea.y + nodeArea.h / 2;

		for (int i = 1 ; i < getAutomationTrack().numNodes ; ++i)
		{
			SDL_Rect nodeArea = getNodeArea(area, i);
			int x = nodeArea.x + nodeArea.w / 2;
			int y = nodeArea.y + nodeArea.h / 2;

			renderer.renderLine(px, py, x, y, Color(255, 255, 255));

			px = x;
			py = y;
		}

		for (int i = 0 ; i < getAutomationTrack().numNodes ; ++i)
		{
			SDL_Rect nodeArea = getNodeArea(area, i);
			renderer.clearRect(nodeArea, mSelectedNode == i ? Color(255, 255, 255) : Color(255, 0, 0));
		}
	}

	const SDL_Rect textArea = { area.x + area.w - renderer.getFontWidth() * 2 - 1, area.y + 1, 16, 16 };
	renderer.renderTextV(textArea, Color(192, 140, 32), "%02d", mSelectedTrack);
}

bool AutomationEditor::pickNode(int x, int y, const SDL_Rect& area, int& nodeOut) const
{
	SDL_Point point = {x,y};

	for (int i = 0 ; i < getAutomationTrack().numNodes ; ++i)
	{
		if (pointInRect(point, getNodeArea(area, i)))
		{
			nodeOut = i;
			return true;
		}
	}

	return false;
}

bool AutomationEditor::onEvent(SDL_Event& event)
{
	if (event.type == SDL_MOUSEBUTTONDOWN)
	{
		// Editor base class should probably do this when clicked
		setFocus(this);

		mMouseX = event.button.x / SCALE;
		mMouseY = event.button.y / SCALE;

		switch (event.button.button)
		{
			case SDL_BUTTON_LEFT:
				if (event.button.clicks == 1)
				{
					int nodeIdx;
					if (pickNode(mMouseX, mMouseY, mThisArea, nodeIdx))
					{
						Synth::AutomationNode& node = getAutomationTrack().getNode(nodeIdx);
						mSelectedNode = nodeIdx;
					}
					else
					{
						mSelectedNode = -1;
					}
					setDirty(true);
				}
				else if (event.button.clicks == 2)
				{
					Synth& synth = static_cast<Synth&>(mSynth);
					SDL_Keymod modState = SDL_GetModState();
					int xGranularity = 1, yGranularity = 1;

					if (modState & KMOD_CTRL)
					{
						xGranularity = synth.getPatternLength();
						yGranularity = mThisArea.h / 2;
					}

					mSelectedNode = getAutomationTrack().addNode(
						granularize(mMouseX - mThisArea.x + getScrollPosition(), xGranularity),
						1.0f - static_cast<float>(granularize(mMouseY - mThisArea.y, yGranularity)) / mThisArea.h
					);
					setDirty(true);
				}
				break;
		}

		return false;
	}
	else if (event.type == SDL_MOUSEMOTION)
	{
		mMouseX = event.motion.x / SCALE;
		mMouseY = event.motion.y / SCALE;

		if ((event.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT)) && mSelectedNode != -1)
		{
			Synth& synth = static_cast<Synth&>(mSynth);
			SDL_Keymod modState = SDL_GetModState();
			int xGranularity = 1, yGranularity = 1;
			Synth::AutomationTrack& track = getAutomationTrack();
			Synth::AutomationNode& firstNode = track.getNode(mSelectedNode);
			int origTime = firstNode.time;
			float origValue = firstNode.value;

			if (modState & KMOD_CTRL)
			{
				xGranularity = synth.getPatternLength() / 2;
				yGranularity = mThisArea.h / 2;
			}

			track.editNode(mSelectedNode,
				granularize(mMouseX - mThisArea.x + getScrollPosition(), xGranularity),
				1.0f - static_cast<float>(granularize(mMouseY - mThisArea.y, yGranularity)) / mThisArea.h
			);

			if (modState & KMOD_ALT)
			{

				int deltaTime = firstNode.time - origTime;
				float deltaValue = firstNode.value - origValue;

				for (int nodeIdx = mSelectedNode + 1 ; nodeIdx < track.numNodes ; ++nodeIdx)
				{
					Synth::AutomationNode node = track.getNode(nodeIdx);
					track.editNode(nodeIdx,
						node.time + deltaTime,
						node.value + deltaValue
					);
				}
			}
			else
			{

			}
		}
	}
	else if (event.type == SDL_MOUSEWHEEL)
	{
		mSelectedTrack = (mSelectedTrack + (event.wheel.y < 0 ? -1 : 1) + Synth::maxAutomationTracks) % Synth::maxAutomationTracks;
		mSelectedNode = -1;
		setDirty(true);
	}
	else if (event.type == SDL_KEYDOWN)
	{
		switch (event.key.keysym.sym)
		{
			case SDLK_DELETE:
				if (mSelectedNode != -1)
				{
					getAutomationTrack().removeNode(mSelectedNode);
					setDirty(true);
					mSelectedNode = -1;
				}
				break;
		}
	}

	return false;
}

void AutomationEditor::onListenableChange(Listenable *listenable)
{

}

void AutomationEditor::onLoaded()
{

}

int AutomationEditor::granularize(int value, int steps)
{
	int newValue = value + steps / 2;
	newValue = newValue - (newValue % steps);
	return abs(newValue - value) < 4 ? newValue : value;
}

Synth& AutomationEditor::getSynth()
{
	return static_cast<Synth&>(mSynth);
}

Synth::AutomationTrack& AutomationEditor::getAutomationTrack()
{
	return getSynth().getAutomationTrack(mSelectedTrack);
}

const Synth& AutomationEditor::getSynth() const
{
	return static_cast<const Synth&>(mSynth);
}

const Synth::AutomationTrack& AutomationEditor::getAutomationTrack() const
{
	return getSynth().getAutomationTrack(mSelectedTrack);
}

int AutomationEditor::getScrollPosition() const
{
	return std::max(0, mEditorState.patternEditor.currentRow + mEditorState.sequenceEditor.currentRow * getSynth().getPatternLength() - mThisArea.w / 2);
}
<commit_msg>Code cleanup<commit_after>#include "AutomationEditor.h"
#include "SDL.h"
#include "ISynth.h"
#include "IPlayer.h"
#include "Renderer.h"
#include "ModularSynth.h"
#include "SynthModule.h"
#include "EditorState.h"
#include "ModuleSelector.h"
#include "Color.h"
#include "Synth.h"
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>

AutomationEditor::AutomationEditor(EditorState& editorState, ISynth& synth, IPlayer& player)
	:Editor(editorState, true), mSynth(synth), mSelectedNode(-1), mSelectedTrack(0)
{
	mEditorState.patternEditor.currentRow.addListener(this);
	mEditorState.sequenceEditor.currentRow.addListener(this);
}

AutomationEditor::~AutomationEditor()
{
}

SDL_Rect AutomationEditor::getNodeArea(const SDL_Rect& parent, int index) const
{
	const Synth& synth = static_cast<const Synth&>(mSynth);
	const Synth::AutomationNode& node = getAutomationTrack().getNode(index);

	return getNodeArea(parent, node);
}

SDL_Rect AutomationEditor::getNodeArea(const SDL_Rect& parent, const Synth::AutomationNode& node) const
{
	const int nodeWidth = 5;
	const int nodeHeight = 5;

	SDL_Rect area = {
		node.time + parent.x - nodeWidth / 2 - getScrollPosition(),
		static_cast<int>((1.0f - node.value) * parent.h) + parent.y - nodeHeight / 2,
		nodeWidth, nodeHeight
	};

	return area;
}

void AutomationEditor::onDraw(Renderer& renderer, const SDL_Rect& area)
{
	setDirty(false);

	if (mModal != NULL)
	{
		return;
	}

	renderer.setClip(area);
	renderer.renderBackground(area);

	const Synth& synth = getSynth();
	int patternLength = synth.getPatternLength();

	for (int x = area.x - getScrollPosition() ; x < area.w + area.x ; x += patternLength)
	{
		renderer.renderLine(x, area.y, x, area.y + area.h, Color(64,64,64));
	}

	float time = synth.getSongPosition();
	int editPos = mEditorState.patternEditor.currentRow + mEditorState.sequenceEditor.currentRow * patternLength;

	renderer.renderLine(time - getScrollPosition() + area.x, area.y, time - getScrollPosition() + area.x, area.y + area.h, Color(0,0,128));
	renderer.renderLine(editPos - getScrollPosition() + area.x, area.y, editPos - getScrollPosition() + area.x, area.y + area.h, Color(255,255,255));

	for (int track = 0 ; track < Synth::maxAutomationTracks ; ++track)
	{
		if (track == mSelectedTrack)
		{
			continue;
		}

		if (synth.getAutomationTrack(track).numNodes > 0)
		{
			SDL_Rect nodeArea = getNodeArea(area, synth.getAutomationTrack(track).nodes[0]);
			int px = nodeArea.x + nodeArea.w / 2;
			int py = nodeArea.y + nodeArea.h / 2;

			for (int i = 1 ; i < synth.getAutomationTrack(track).numNodes ; ++i)
			{
				SDL_Rect nodeArea = getNodeArea(area, synth.getAutomationTrack(track).nodes[i]);
				int x = nodeArea.x + nodeArea.w / 2;
				int y = nodeArea.y + nodeArea.h / 2;

				renderer.renderLine(px, py, x, y, track == mSelectedTrack ? Color(255, 255, 255) : Color(64, 64, 64));

				px = x;
				py = y;
			}
		}
	}

	if (getAutomationTrack().numNodes > 0)
	{
		SDL_Rect nodeArea = getNodeArea(area, 0);
		int px = nodeArea.x + nodeArea.w / 2;
		int py = nodeArea.y + nodeArea.h / 2;

		for (int i = 1 ; i < getAutomationTrack().numNodes ; ++i)
		{
			SDL_Rect nodeArea = getNodeArea(area, i);
			int x = nodeArea.x + nodeArea.w / 2;
			int y = nodeArea.y + nodeArea.h / 2;

			renderer.renderLine(px, py, x, y, Color(255, 255, 255));

			px = x;
			py = y;
		}

		for (int i = 0 ; i < getAutomationTrack().numNodes ; ++i)
		{
			SDL_Rect nodeArea = getNodeArea(area, i);
			renderer.clearRect(nodeArea, mSelectedNode == i ? Color(255, 255, 255) : Color(255, 0, 0));
		}
	}

	const SDL_Rect textArea = { area.x + area.w - renderer.getFontWidth() * 2 - 1, area.y + 1, 16, 16 };
	renderer.renderTextV(textArea, Color(192, 140, 32), "%02d", mSelectedTrack);
}

bool AutomationEditor::pickNode(int x, int y, const SDL_Rect& area, int& nodeOut) const
{
	SDL_Point point = {x,y};

	for (int i = 0 ; i < getAutomationTrack().numNodes ; ++i)
	{
		if (pointInRect(point, getNodeArea(area, i)))
		{
			nodeOut = i;
			return true;
		}
	}

	return false;
}

bool AutomationEditor::onEvent(SDL_Event& event)
{
	if (event.type == SDL_MOUSEBUTTONDOWN)
	{
		// Editor base class should probably do this when clicked
		setFocus(this);

		mMouseX = event.button.x / SCALE;
		mMouseY = event.button.y / SCALE;

		switch (event.button.button)
		{
			case SDL_BUTTON_LEFT:
				if (event.button.clicks == 1)
				{
					int nodeIdx;
					if (pickNode(mMouseX, mMouseY, mThisArea, nodeIdx))
					{
						Synth::AutomationNode& node = getAutomationTrack().getNode(nodeIdx);
						mSelectedNode = nodeIdx;
					}
					else
					{
						mSelectedNode = -1;
					}
					setDirty(true);
				}
				else if (event.button.clicks == 2)
				{
					Synth& synth = static_cast<Synth&>(mSynth);
					SDL_Keymod modState = SDL_GetModState();
					int xGranularity = 1, yGranularity = 1;

					if (modState & KMOD_CTRL)
					{
						xGranularity = synth.getPatternLength();
						yGranularity = mThisArea.h / 2;
					}

					mSelectedNode = getAutomationTrack().addNode(
						granularize(mMouseX - mThisArea.x + getScrollPosition(), xGranularity),
						1.0f - static_cast<float>(granularize(mMouseY - mThisArea.y, yGranularity)) / mThisArea.h
					);
					setDirty(true);
				}
				break;
		}

		return false;
	}
	else if (event.type == SDL_MOUSEMOTION)
	{
		mMouseX = event.motion.x / SCALE;
		mMouseY = event.motion.y / SCALE;

		if ((event.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT)) && mSelectedNode != -1)
		{
			Synth& synth = static_cast<Synth&>(mSynth);
			SDL_Keymod modState = SDL_GetModState();
			int xGranularity = 1, yGranularity = 1;
			Synth::AutomationTrack& track = getAutomationTrack();
			Synth::AutomationNode& firstNode = track.getNode(mSelectedNode);
			int origTime = firstNode.time;
			float origValue = firstNode.value;

			if (modState & KMOD_CTRL)
			{
				xGranularity = synth.getPatternLength() / 2;
				yGranularity = mThisArea.h / 2;
			}

			track.editNode(mSelectedNode,
				granularize(mMouseX - mThisArea.x + getScrollPosition(), xGranularity),
				1.0f - static_cast<float>(granularize(mMouseY - mThisArea.y, yGranularity)) / mThisArea.h
			);

			if (modState & KMOD_ALT)
			{

				int deltaTime = firstNode.time - origTime;
				float deltaValue = firstNode.value - origValue;

				for (int nodeIdx = mSelectedNode + 1 ; nodeIdx < track.numNodes ; ++nodeIdx)
				{
					Synth::AutomationNode node = track.getNode(nodeIdx);
					track.editNode(nodeIdx,
						node.time + deltaTime,
						node.value + deltaValue
					);
				}
			}
		}
	}
	else if (event.type == SDL_MOUSEWHEEL)
	{
		mSelectedTrack = (mSelectedTrack + (event.wheel.y < 0 ? -1 : 1) + Synth::maxAutomationTracks) % Synth::maxAutomationTracks;
		mSelectedNode = -1;
		setDirty(true);
	}
	else if (event.type == SDL_KEYDOWN)
	{
		switch (event.key.keysym.sym)
		{
			case SDLK_DELETE:
				if (mSelectedNode != -1)
				{
					getAutomationTrack().removeNode(mSelectedNode);
					setDirty(true);
					mSelectedNode = -1;
				}
				break;
		}
	}

	return false;
}

void AutomationEditor::onListenableChange(Listenable *listenable)
{

}

void AutomationEditor::onLoaded()
{

}

int AutomationEditor::granularize(int value, int steps)
{
	int newValue = value + steps / 2;
	newValue = newValue - (newValue % steps);
	return abs(newValue - value) < 4 ? newValue : value;
}

Synth& AutomationEditor::getSynth()
{
	return static_cast<Synth&>(mSynth);
}

Synth::AutomationTrack& AutomationEditor::getAutomationTrack()
{
	return getSynth().getAutomationTrack(mSelectedTrack);
}

const Synth& AutomationEditor::getSynth() const
{
	return static_cast<const Synth&>(mSynth);
}

const Synth::AutomationTrack& AutomationEditor::getAutomationTrack() const
{
	return getSynth().getAutomationTrack(mSelectedTrack);
}

int AutomationEditor::getScrollPosition() const
{
	return std::max(0, mEditorState.patternEditor.currentRow + mEditorState.sequenceEditor.currentRow * getSynth().getPatternLength() - mThisArea.w / 2);
}
<|endoftext|>


<commit_before>/* Copyright 2014 Gagarine Yaikhom (MIT License) */

#include <iostream>
#include "BinarySearchTree.hh"

using namespace std;

BinarySearchTree::BinarySearchTree() {
    root = 0;
}

void BinarySearchTree::preorderRecursive(BinarySearchTreeNode* root) {
    if (root) {
        root->print();
        preorderRecursive(root->left);
        preorderRecursive(root->right);
    }
}

void BinarySearchTree::preorderNonRecursive(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    while (current) {
        if (!current->visited) {
            current->print();
            current->visited = true;
        }

        if (current->left && !current->left->visited) {
            current = current->left;
            continue;
        } else if (current->right && !current->right->visited) {
            current = current->right;
            continue;
        }

        if (current->left)
            current->left->visited = false;
        if (current->right)
            current->right->visited = false;

        current = current->parent;
    };
    if (root)
        root->visited = false;
}

void BinarySearchTree::preorder() {
    cout << "\nPreorder traversal\n";
    preorderNonRecursive(root);
}

void BinarySearchTree::inorderRecursive(BinarySearchTreeNode* root) {
    if (root) {
        inorderRecursive(root->left);
        root->print();
        inorderRecursive(root->right);
    }
}

void BinarySearchTree::inorderNonRecursive(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    while (current) {
        if (current->left && !current->left->visited) {
            current = current->left;
            continue;
        }

        if (!current->visited) {
            current->print();
            current->visited = true;
        }

        if (current->right && !current->right->visited) {
            current = current->right;
            continue;
        }

        if (current->left)
            current->left->visited = false;
        if (current->right)
            current->right->visited = false;

        current = current->parent;
    };
    if (root)
        root->visited = false;
}

void BinarySearchTree::inorder() {
    cout << "\nInorder traversal\n";
    inorderNonRecursive(root);
}

void BinarySearchTree::postorderRecursive(BinarySearchTreeNode* root) {
    if (root) {
        postorderRecursive(root->left);
        postorderRecursive(root->right);
        root->print();
    }
}

void BinarySearchTree::postorderNonRecursive(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    while (current) {
        if (current->left && !current->left->visited) {
            current = current->left;
            continue;
        } else if (current->right && !current->right->visited) {
            current = current->right;
            continue;
        }

        if (!current->visited) {
            current->print();
            current->visited = true;
        }

        if (current->left)
            current->left->visited = false;
        if (current->right)
            current->right->visited = false;

        current = current->parent;
    };
    if (root)
        root->visited = false;
}

void BinarySearchTree::postorder() {
    cout << "\nPostorder traversal\n";
    postorderNonRecursive(root);
}

int BinarySearchTree::add(int key) {
    if (root == 0) {
        root = new BinarySearchTreeNode(key);
    } else {
        BinarySearchTreeNode* current = root;
        BinarySearchTreeNode* newNode = new BinarySearchTreeNode(key);
        while (current) {
            if (*current == *newNode) {
                delete newNode;
                return 1; /* duplicate key */
            } else {
                if (*newNode < *current) {
                    if (current->left)
                        current = current->left;
                    else {
                        current->left = newNode;
                        newNode->parent = current;
                        return 0;
                    }
                } else {
                    if (current->right)
                        current = current->right;
                    else {
                        current->right = newNode;
                        newNode->parent = current;
                        return 0;
                    }
                }
            }
        }
    }
    return 0;
}

BinarySearchTreeNode* BinarySearchTree::find(int key) {
    BinarySearchTreeNode* current = root;
    while (current) {
        if (key == current->key)
            return current;
        else {
            if (key < current->key)
                current = current->left;
            else
                current = current->right;
        }
    }
    return 0;
}

BinarySearchTreeNode* BinarySearchTree::findSubtreeMax(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    if (current)
        while (current->right)
            current = current->right;
    return current;
}

BinarySearchTreeNode* BinarySearchTree::findSubtreeMin(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    if (current)
        while (current->left)
            current = current->left;
    return current;
}

int BinarySearchTree::remove(int key) {
    BinarySearchTreeNode* node = find(key);
    if (node) {

    }
}

void BinarySearchTree::destroyRecursive(BinarySearchTreeNode* root) {
    if (root) {
        destroyRecursive(root->left);
        destroyRecursive(root->right);
        cout << "\nDeleting node " << root->key;
        delete root;
    }
}

void BinarySearchTree::destroyNonRecursive(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* temp;
    while (root) {
        if (root->left) {
            root = root->left;
            continue;
        } else if (root->right) {
            root = root->right;
            continue;
        }

        temp = root->parent;
        if (temp) {
            if (temp->left == root)
                temp->left = 0;
            else
                temp->right = 0;
        }

        cout << "\nDeleting node " << root->key;
        delete root;
        root = temp;
    };
}

BinarySearchTree::~BinarySearchTree() {
    destroyNonRecursive(root);
}
<commit_msg>Complete implementation of removal.<commit_after>/* Copyright 2014 Gagarine Yaikhom (MIT License) */

#include <iostream>
#include "BinarySearchTree.hh"

using namespace std;

BinarySearchTree::BinarySearchTree() {
    root = 0;
}

void BinarySearchTree::preorderRecursive(BinarySearchTreeNode* root) {
    if (root) {
        root->print();
        preorderRecursive(root->left);
        preorderRecursive(root->right);
    }
}

void BinarySearchTree::preorderNonRecursive(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    while (current) {
        if (!current->visited) {
            current->print();
            current->visited = true;
        }

        if (current->left && !current->left->visited) {
            current = current->left;
            continue;
        } else if (current->right && !current->right->visited) {
            current = current->right;
            continue;
        }

        if (current->left)
            current->left->visited = false;
        if (current->right)
            current->right->visited = false;

        current = current->parent;
    };
    if (root)
        root->visited = false;
}

void BinarySearchTree::preorder() {
    cout << "\nPreorder traversal\n";
    preorderNonRecursive(root);
}

void BinarySearchTree::inorderRecursive(BinarySearchTreeNode* root) {
    if (root) {
        inorderRecursive(root->left);
        root->print();
        inorderRecursive(root->right);
    }
}

void BinarySearchTree::inorderNonRecursive(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    while (current) {
        if (current->left && !current->left->visited) {
            current = current->left;
            continue;
        }

        if (!current->visited) {
            current->print();
            current->visited = true;
        }

        if (current->right && !current->right->visited) {
            current = current->right;
            continue;
        }

        if (current->left)
            current->left->visited = false;
        if (current->right)
            current->right->visited = false;

        current = current->parent;
    };
    if (root)
        root->visited = false;
}

void BinarySearchTree::inorder() {
    cout << "\nInorder traversal\n";
    inorderNonRecursive(root);
}

void BinarySearchTree::postorderRecursive(BinarySearchTreeNode* root) {
    if (root) {
        postorderRecursive(root->left);
        postorderRecursive(root->right);
        root->print();
    }
}

void BinarySearchTree::postorderNonRecursive(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    while (current) {
        if (current->left && !current->left->visited) {
            current = current->left;
            continue;
        } else if (current->right && !current->right->visited) {
            current = current->right;
            continue;
        }

        if (!current->visited) {
            current->print();
            current->visited = true;
        }

        if (current->left)
            current->left->visited = false;
        if (current->right)
            current->right->visited = false;

        current = current->parent;
    };
    if (root)
        root->visited = false;
}

void BinarySearchTree::postorder() {
    cout << "\nPostorder traversal\n";
    postorderNonRecursive(root);
}

int BinarySearchTree::add(int key) {
    if (root == 0) {
        root = new BinarySearchTreeNode(key);
    } else {
        BinarySearchTreeNode* current = root;
        BinarySearchTreeNode* newNode = new BinarySearchTreeNode(key);
        while (current) {
            if (*current == *newNode) {
                delete newNode;
                return 1; /* duplicate key */
            } else {
                if (*newNode < *current) {
                    if (current->left)
                        current = current->left;
                    else {
                        current->left = newNode;
                        newNode->parent = current;
                        return 0;
                    }
                } else {
                    if (current->right)
                        current = current->right;
                    else {
                        current->right = newNode;
                        newNode->parent = current;
                        return 0;
                    }
                }
            }
        }
    }
    return 0;
}

BinarySearchTreeNode* BinarySearchTree::find(int key) {
    BinarySearchTreeNode* current = root;
    while (current) {
        if (key == current->key)
            return current;
        else {
            if (key < current->key)
                current = current->left;
            else
                current = current->right;
        }
    }
    return 0;
}

BinarySearchTreeNode* BinarySearchTree::findSubtreeMax(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    if (current)
        while (current->right)
            current = current->right;
    return current;
}

BinarySearchTreeNode* BinarySearchTree::findSubtreeMin(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* current = root;
    if (current)
        while (current->left)
            current = current->left;
    return current;
}

int BinarySearchTree::remove(int key) {
    BinarySearchTreeNode* node = find(key), *newRoot, *temp;
    if (node) {
        if (node->right) {
            newRoot = node->right;
            newRoot->parent = node->parent;
            if (node->parent) {
                if (node->parent->right == node)
                    node->parent->right = newRoot;
                else
                    node->parent->left = newRoot;
            } else
                root = newRoot;
            temp = findSubtreeMin(newRoot);
            temp->left = node->left;
            if (node->left)
                node->left->parent = temp;
        } else if (node->left) {
            newRoot = node->left;
            newRoot->parent = node->parent;
            if (node->parent) {
                if (node->parent->right == node)
                    node->parent->right = newRoot;
                else
                    node->parent->left = newRoot;
            } else
                root = newRoot;
            temp = findSubtreeMax(newRoot);
            temp->right = node->right;
            if (node->right)
                node->right->parent = temp;
        } else {
            if (node->parent) {
                if (node->parent->right == node)
                    node->parent->right = 0;
                else
                    node->parent->left = 0;
            } else
                root = 0;
        }
        delete node;
        return 1;
    } else
        return 0;
}

void BinarySearchTree::destroyRecursive(BinarySearchTreeNode* root) {
    if (root) {
        destroyRecursive(root->left);
        destroyRecursive(root->right);
        cout << "\nDeleting node " << root->key;
        delete root;
    }
}

void BinarySearchTree::destroyNonRecursive(BinarySearchTreeNode* root) {
    BinarySearchTreeNode* temp;
    while (root) {
        if (root->left) {
            root = root->left;
            continue;
        } else if (root->right) {
            root = root->right;
            continue;
        }

        temp = root->parent;
        if (temp) {
            if (temp->left == root)
                temp->left = 0;
            else
                temp->right = 0;
        }

        cout << "\nDeleting node " << root->key;
        delete root;
        root = temp;
    };
}

BinarySearchTree::~BinarySearchTree() {
    destroyNonRecursive(root);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013-2014 Morwenn
 *
 * static_math 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 3 of
 * the License, or (at your option) any later version.
 *
 * static_math 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 this program. If not,
 * see <http://www.gnu.org/licenses/>.
 */
#include <static_math/rational.h>

using namespace smath;

int main()
{
    // Constructor tests
    constexpr auto ratio = rational<int>(4, 3);
    static_assert(ratio.numerator() == 4, "");
    static_assert(ratio.denominator() == 3, "");

    constexpr auto ratio2 = rational<int>(5);
    static_assert(ratio2.numerator() == 5, "");
    static_assert(ratio2.denominator() == 1, "");

    constexpr auto r1 = rational<int>(1, 2);
    constexpr auto r2 = rational<int>(2, 4);
    constexpr auto r3 = rational<int>(1, 3);
    constexpr auto r4 = rational<int>(5, 1);
    constexpr auto r5 = rational<int>(-1, 2);
    constexpr auto r6 = rational<int>(1, -2);

    // rational-rational comparison
    static_assert(r1 == r2, "");
    static_assert(r1 != r3, "");
    static_assert(r1 > r3, "");
    static_assert(r3 < r2, "");
    static_assert(r1 >= r2, "");
    static_assert(r3 <= r2, "");
    static_assert(r5 == r6, "");

    // rational-integral comparison
    static_assert(r4 == 5, "");
    static_assert(5 == r4, "");
    static_assert(r1 != 3, "");
    static_assert(8 != r2, "");
    static_assert(0 < r1, "");
    static_assert(r2 < 1, "");
    static_assert(8 > r4, "");
    static_assert(r2 > -1, "");
    static_assert(5 <= r4, "");
    static_assert(r3 <= 1, "");
    static_assert(1 >= r3, "");
    static_assert(r1 >= -8, "");
    static_assert(r5 <= 0, "");
    static_assert(r6 <= 0, "");

    // rational-rational arithmetic operations
    static_assert(r1 + r2 == 1, "");
    static_assert(r4 - r1 == rational<int>(9, 2), "");
    static_assert(r2 * r3 == rational<int>(1, 6), "");
    static_assert(r1 / r3 == rational<int>(3, 2), "");

    // rational-integral arithmetic operations
    static_assert(r1 + 1 == rational<int>(3, 2), "");
    static_assert(2 + r2 == rational<int>(5, 2), "");
    static_assert(r3 - 3 == rational<int>(-8, 3), "");
    static_assert(2 - r1 == rational<int>(3, 2), "");
    static_assert(r4 * 2 == 10, "");
    static_assert(6 * r2 == r1 * 6, "");
    static_assert(1 / r2 == 2, "");
    static_assert(r3 / 3 == rational<int>(1, 9), "");

    // cast
    static_assert(rational<int>(1, 2) == rational<long int>(1, 2), "");
    static_assert(rational<unsigned long long>(3, 2) == rational<short>(3, 2), "");

    // _smath_r literal
    static_assert(2 / 3_r == rational<unsigned long long>(2, 3), "");
    static_assert(1_r / 8 == rational<unsigned long long>(1, 8), "");
    static_assert(3 / 5_r == 3_r / 5, "");

    constexpr auto a0 = rational<int>(0, 1);
    constexpr auto a1 = rational<int>(1, 2);
    constexpr auto a2 = rational<int>(-3, 8);
    constexpr auto a3 = rational<int>(6, -7);

    // Math functions
    static_assert(sign(a0) == 0, "");
    static_assert(sign(a1) == 1, "");
    static_assert(sign(a2) == -1, "");
    static_assert(sign(a3) == -1, "");

    static_assert(abs(a1) == 1 / 2_r, "");
    static_assert(abs(a2) == 3 / 8_r, "");
    static_assert(abs(a3) == 6 / 7_r, "");

    static_assert(round(a1) == 1.0, "");
    /* No more tests for ceil, floor, trunc
     * and round since they are based on
     * the floating point functions after
     * a simple cast.
     */

    static_assert(reciprocal(a1) == 2, "");
    static_assert(reciprocal(a2) == rational<int>(8, -3), "");

    static_assert(pow(a1, 2) == 1 / 4_r, "");
    static_assert(pow(a2, 3) == -27 / 512_r, "");
    static_assert(pow(a3, -2) == 49 / 36_r, "");
}
<commit_msg>More tests.<commit_after>/*
 * Copyright (C) 2013-2014 Morwenn
 *
 * static_math 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 3 of
 * the License, or (at your option) any later version.
 *
 * static_math 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 this program. If not,
 * see <http://www.gnu.org/licenses/>.
 */
#include <static_math/rational.h>

using namespace smath;

int main()
{
    // Constructor tests
    constexpr auto ratio = rational<int>(4, 3);
    static_assert(ratio.numerator() == 4, "");
    static_assert(ratio.denominator() == 3, "");

    constexpr auto ratio2 = rational<int>(5);
    static_assert(ratio2.numerator() == 5, "");
    static_assert(ratio2.denominator() == 1, "");

    constexpr auto r1 = rational<int>(1, 2);
    constexpr auto r2 = rational<int>(2, 4);
    constexpr auto r3 = rational<int>(1, 3);
    constexpr auto r4 = rational<int>(5, 1);
    constexpr auto r5 = rational<int>(-1, 2);
    constexpr auto r6 = rational<int>(1, -2);
    constexpr auto r7 = rational<int>(4, 5);

    // Rational-rational comparison
    static_assert(r1 == r2, "");
    static_assert(r1 != r3, "");
    static_assert(r1 > r3, "");
    static_assert(r3 < r2, "");
    static_assert(r1 >= r2, "");
    static_assert(r3 <= r2, "");
    static_assert(r5 == r6, "");

    // Rational-integral comparison
    static_assert(r4 == 5, "");
    static_assert(5 == r4, "");
    static_assert(r1 != 3, "");
    static_assert(8 != r2, "");
    static_assert(0 < r1, "");
    static_assert(r2 < 1, "");
    static_assert(8 > r4, "");
    static_assert(r2 > -1, "");
    static_assert(5 <= r4, "");
    static_assert(r3 <= 1, "");
    static_assert(1 >= r3, "");
    static_assert(r1 >= -8, "");
    static_assert(r5 <= 0, "");
    static_assert(r6 <= 0, "");

    // Rational-rational arithmetic operations
    static_assert(r1 + r2 == 1, "");
    static_assert(r4 - r1 == rational<int>(9, 2), "");
    static_assert(r2 * r3 == rational<int>(1, 6), "");
    static_assert(r1 / r3 == rational<int>(3, 2), "");

    // Rational-integral arithmetic operations
    static_assert(r1 + 1 == rational<int>(3, 2), "");
    static_assert(2 + r2 == rational<int>(5, 2), "");
    static_assert(r3 - 3 == rational<int>(-8, 3), "");
    static_assert(2 - r1 == rational<int>(3, 2), "");
    static_assert(r4 * 2 == 10, "");
    static_assert(6 * r2 == r1 * 6, "");
    static_assert(1 / r2 == 2, "");
    static_assert(r3 / 3 == rational<int>(1, 9), "");

    // Cast
    static_assert(rational<int>(1, 2) == rational<long int>(1, 2), "");
    static_assert(rational<unsigned long long>(3, 2) == rational<short>(3, 2), "");

    // User-defined literal
    static_assert(2 / 3_r == rational<unsigned long long>(2, 3), "");
    static_assert(1_r / 8 == rational<unsigned long long>(1, 8), "");
    static_assert(3 / 5_r == 3_r / 5, "");

    constexpr auto a0 = rational<int>(0, 1);
    constexpr auto a1 = rational<int>(1, 2);
    constexpr auto a2 = rational<int>(-3, 8);
    constexpr auto a3 = rational<int>(6, -7);

    // Math functions
    static_assert(sign(a0) == 0, "");
    static_assert(sign(a1) == 1, "");
    static_assert(sign(a2) == -1, "");
    static_assert(sign(a3) == -1, "");

    static_assert(abs(a1) == 1 / 2_r, "");
    static_assert(abs(a2) == 3 / 8_r, "");
    static_assert(abs(a3) == 6 / 7_r, "");

    static_assert(round(a1) == 1.0, "");
    /* No more tests for ceil, floor, trunc
     * and round since they are based on
     * the floating point functions after
     * a simple cast.
     */

    static_assert(reciprocal(a1) == 2, "");
    static_assert(reciprocal(a2) == rational<int>(8, -3), "");

    static_assert(pow(a1, 2) == 1 / 4_r, "");
    static_assert(pow(a2, 3) == -27 / 512_r, "");
    static_assert(pow(a3, -2) == 49 / 36_r, "");
    static_assert(pow(r1, 0) == 1_r, "");
    static_assert(pow(r2, 1) == r2, "");
    static_assert(pow(r7, 3) == 64 / 125_r, "");
}
<|endoftext|>


<commit_before>#ifndef __GLOBALS_HPP_INCLUDED
#define __GLOBALS_HPP_INCLUDED

#include <string>
#include <vector>
#include <stdint.h> // uint32_t etc.

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h>
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp>
#endif

#ifndef WINDOW_WIDTH
#define WINDOW_WIDTH (1600.0f)
#endif

#ifndef WINDOW_HEIGHT
#define WINDOW_HEIGHT (900.0f)
#endif

#ifndef ASPECT_RATIO
#define ASPECT_RATIO (WINDOW_WIDTH / WINDOW_HEIGHT)
#endif

#ifndef PI
#define PI 3.14159265359f
#endif

#ifndef EARTH_RADIUS
#define EARTH_RADIUS 6371000.0f
#endif

#ifndef TEXT_SIZE
#define TEXT_SIZE 40
#endif

#ifndef FONT_SIZE
#define FONT_SIZE 16
#endif

#ifndef MAX_FPS
#define MAX_FPS 60
#endif

extern glm::vec3 position;
extern double horizontalAngle;
extern double verticalAngle;
extern GLfloat initialFoV;
extern double earth_radius;
extern bool hasMouseEverMoved;
extern bool is_invert_mouse_in_use;
extern bool is_key_I_released;
extern bool is_world_loaded; // no more than one world object can be loaded. TODO: check that no more than one world is loaded!
extern bool is_world_spherical;

typedef struct
{
    std::string texture_file_format;
    std::string image_path;
} TextureStruct;

typedef struct
{
    void *world_pointer;                     // pointer to the world (draw list).
    std::string vertex_shader;               // filename of vertex shader.
    std::string fragment_shader;             // filename of fragment shader.
} ShaderStruct;

typedef struct
{
    GLuint nodeID;
    void* graph_pointer;
    glm::vec3 coordinate_vector;
    std::vector<uint32_t> neighbor_nodeIDs;
} NodeStruct;

typedef struct
{
    glm::vec3 coordinate_vector;     // coordinate vector.
    GLfloat rotate_angle;            // rotate angle.
    glm::vec3 rotate_vector;         // rotate vector.
    glm::vec3 translate_vector;      // translate vector.
    glm::mat4 model_matrix;          // model matrix.
    glm::mat4 MVP_matrix;            // model view projection matrix.
    void *species_pointer;           // pointer to the species.
} ObjectStruct;

typedef struct
{
    // used for all files (for all species).
    void *shader_pointer;                    // pointer to the shader object.
    std::string model_file_format;           // type of the model file. supported file formats so far: `"bmp"`/`"BMP"`, `"obj"`/`"OBJ"`.
                                             // TODO: add support for `"SRTM"`.
    std::string texture_file_format;         // type of the texture file. supported file formats so far: `"bmp"`/`"BMP"`, `"dds"`/`"DDS"`.
    std::string texture_filename;            // filename of the model file.
    std::string vertex_shader;               // filename of vertex shader.
    std::string fragment_shader;             // filename of fragment shader.
    glm::vec3 lightPos;                      // light position.
    std::vector<ObjectStruct> object_vector; // vector of individual objects of this species.
    bool is_world;                           // worlds currently do not rotate nor translate.
    std::string coordinate_system;           // used only for worlds (`is_world` == `true`). valid values: `"cartesian"`.
                                             // TODO: add support for `"spherical"`. `"spherical"` is used eg. in SRTM heightmaps.
    double world_radius;                    // radius of sea level in meters. used only for worlds.

    // for `"bmp"` model files.
    std::string model_filename;              // filename of the model file.
    std::string color_channel;               // color channel to use for altitude data.
} SpeciesStruct;

typedef struct
{
    GLuint screen_width;
    GLuint screen_height;
    GLuint x;
    GLuint y;
    GLuint text_size;
    GLuint font_size;
    const char *text;
    const char *char_font_texture_file_format;
    const char *horizontal_alignment;
    const char *vertical_alignment;
} PrintingStruct;

typedef struct
{
    double rho;
    double theta;
    double phi;
} SphericalCoordinatesStruct;

typedef struct
{
    double southern_latitude;
    double northern_latitude;
    double western_longitude;
    double eastern_longitude;
} SphericalWorldStruct;

extern SphericalCoordinatesStruct spherical_position;

#endif
<commit_msg>Muokattu `typedef struct {` ... `} TextureStruct;`.<commit_after>#ifndef __GLOBALS_HPP_INCLUDED
#define __GLOBALS_HPP_INCLUDED

#include <string>
#include <vector>
#include <stdint.h> // uint32_t etc.

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h>
#endif

// Include GLFW
#ifndef __GLFW3_H_INCLUDED
#define __GLFW3_H_INCLUDED
#include <glfw3.h>
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp>
#endif

#ifndef WINDOW_WIDTH
#define WINDOW_WIDTH (1600.0f)
#endif

#ifndef WINDOW_HEIGHT
#define WINDOW_HEIGHT (900.0f)
#endif

#ifndef ASPECT_RATIO
#define ASPECT_RATIO (WINDOW_WIDTH / WINDOW_HEIGHT)
#endif

#ifndef PI
#define PI 3.14159265359f
#endif

#ifndef EARTH_RADIUS
#define EARTH_RADIUS 6371000.0f
#endif

#ifndef TEXT_SIZE
#define TEXT_SIZE 40
#endif

#ifndef FONT_SIZE
#define FONT_SIZE 16
#endif

#ifndef MAX_FPS
#define MAX_FPS 60
#endif

extern glm::vec3 position;
extern double horizontalAngle;
extern double verticalAngle;
extern GLfloat initialFoV;
extern double earth_radius;
extern bool hasMouseEverMoved;
extern bool is_invert_mouse_in_use;
extern bool is_key_I_released;
extern bool is_world_loaded; // no more than one world object can be loaded. TODO: check that no more than one world is loaded!
extern bool is_world_spherical;

typedef struct
{
    void *world_pointer;                     // pointer to the world (draw list).
    std::string vertex_shader;               // filename of vertex shader.
    std::string fragment_shader;             // filename of fragment shader.
} ShaderStruct;

typedef struct
{
    void *world_pointer;                     // pointer to the world.
    std::string texture_file_format;
    std::string image_path;
} TextureStruct;

typedef struct
{
    GLuint nodeID;
    void* graph_pointer;
    glm::vec3 coordinate_vector;
    std::vector<uint32_t> neighbor_nodeIDs;
} NodeStruct;

typedef struct
{
    glm::vec3 coordinate_vector;     // coordinate vector.
    GLfloat rotate_angle;            // rotate angle.
    glm::vec3 rotate_vector;         // rotate vector.
    glm::vec3 translate_vector;      // translate vector.
    glm::mat4 model_matrix;          // model matrix.
    glm::mat4 MVP_matrix;            // model view projection matrix.
    void *species_pointer;           // pointer to the species.
} ObjectStruct;

typedef struct
{
    // used for all files (for all species).
    void *shader_pointer;                    // pointer to the shader object.
    std::string model_file_format;           // type of the model file. supported file formats so far: `"bmp"`/`"BMP"`, `"obj"`/`"OBJ"`.
                                             // TODO: add support for `"SRTM"`.
    std::string texture_file_format;         // type of the texture file. supported file formats so far: `"bmp"`/`"BMP"`, `"dds"`/`"DDS"`.
    std::string texture_filename;            // filename of the model file.
    std::string vertex_shader;               // filename of vertex shader.
    std::string fragment_shader;             // filename of fragment shader.
    glm::vec3 lightPos;                      // light position.
    std::vector<ObjectStruct> object_vector; // vector of individual objects of this species.
    bool is_world;                           // worlds currently do not rotate nor translate.
    std::string coordinate_system;           // used only for worlds (`is_world` == `true`). valid values: `"cartesian"`.
                                             // TODO: add support for `"spherical"`. `"spherical"` is used eg. in SRTM heightmaps.
    double world_radius;                    // radius of sea level in meters. used only for worlds.

    // for `"bmp"` model files.
    std::string model_filename;              // filename of the model file.
    std::string color_channel;               // color channel to use for altitude data.
} SpeciesStruct;

typedef struct
{
    GLuint screen_width;
    GLuint screen_height;
    GLuint x;
    GLuint y;
    GLuint text_size;
    GLuint font_size;
    const char *text;
    const char *char_font_texture_file_format;
    const char *horizontal_alignment;
    const char *vertical_alignment;
} PrintingStruct;

typedef struct
{
    double rho;
    double theta;
    double phi;
} SphericalCoordinatesStruct;

typedef struct
{
    double southern_latitude;
    double northern_latitude;
    double western_longitude;
    double eastern_longitude;
} SphericalWorldStruct;

extern SphericalCoordinatesStruct spherical_position;

#endif
<|endoftext|>


<commit_before>// -*- mode: c++, coding: utf-8 -*-
/**
 * tbrpg – Text based roll playing game
 *
 * Copyright © 2012  Mattias Andrée (maandree@kth.se)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef __GUARD_CHARACTERCREATOR_HPP__
#define __GUARD_CHARACTERCREATOR_HPP__

#include <iostream>
#include <stdlib.h>
#include <vector>
#include <unistd.h>
#include <unordered_map>

#include "CharacterSheet.hpp"
#include "RuleSet.hpp"
#include "Dice.hpp"
#include "prompter.hpp"

/**
 * Text based roll playing game
 *
 * DD2387 Program construction with C++
 * Laboration 3
 *
 * @author  Mattias Andrée <maandree@kth.se>
 */
namespace tbrpg
{
  /**
   * Character creator class
   */
  class CharacterCreator
  {
  protected:
    /**
     * The game's rules
     */
    RuleSet ruleset;

    /**
     * The start values, these are updated by the assign function
     */
    int* start;

    /**
     * The lower bounds
     */
    int* lower;

    /**
     * The upper bounds
     */
    int* upper;

  public:
    /**
     * Constructor
     *
     * @param  rules  The game's rules
     */
    CharacterCreator(const RuleSet& rules);

    /**
     * Destructor
     */
    virtual ~CharacterCreator();

    /**
     * Create a character sheet
     *
     * @return  A character sheet, nullptr if aborted
     */
    virtual CharacterSheet* create() const;

  protected:

    /**
     * Assign scores
     *
     * @param   n           Number of printers
     * @param   unassigned  Unassigned scores
     * @param   extra       Extra data to add as argument to the value printer
     * @param   printer     Value printer, takes arguments: index, value, extra data
     * @param   reroll      Pointer to a reroll function pointer, nullptr if not allowed
     * @return              Whether the assignment was completed
     */
    virtual bool assign(int n, int unassigned, void* data, void (*printer)(int, int, void*), void (**reroll)() == nullptr);

    /**
     * Ability score printer
     *
     * @param  index  The index of the ability
     * @param  value  The value of the ability
     * @param  data   Pointer to the 100-part of the strenght
     */
    virtual void abilityPrinter(int index, int value, void* data);

    /**
     * Ability score reroll
     */
    virtual void abilityReroll();

  };

}

#endif//__GUARD_CHARACTERCREATOR_HPP__

<commit_msg>forgot to stage<commit_after>// -*- mode: c++, coding: utf-8 -*-
/**
 * tbrpg – Text based roll playing game
 *
 * Copyright © 2012  Mattias Andrée (maandree@kth.se)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef __GUARD_CHARACTERCREATOR_HPP__
#define __GUARD_CHARACTERCREATOR_HPP__

#include <iostream>
#include <stdlib.h>
#include <vector>
#include <unistd.h>
#include <unordered_map>

#include "CharacterSheet.hpp"
#include "RuleSet.hpp"
#include "Dice.hpp"
#include "prompter.hpp"

/**
 * Text based roll playing game
 *
 * DD2387 Program construction with C++
 * Laboration 3
 *
 * @author  Mattias Andrée <maandree@kth.se>
 */
namespace tbrpg
{
  /**
   * Character creator class
   */
  class CharacterCreator
  {
  protected:
    /**
     * The game's rules
     */
    RuleSet ruleset;

    /**
     * The start values, these are updated by the assign function
     */
    int* start;

    /**
     * The lower bounds
     */
    int* lower;

    /**
     * The upper bounds
     */
    int* upper;

  public:
    /**
     * Constructor
     *
     * @param  rules  The game's rules
     */
    CharacterCreator(const RuleSet& rules);

    /**
     * Destructor
     */
    virtual ~CharacterCreator();

    /**
     * Create a character sheet
     *
     * @return  A character sheet, nullptr if aborted
     */
    virtual CharacterSheet* create() const;

  protected:

    /**
     * Assign scores
     *
     * @param   n           Number of printers
     * @param   unassigned  Unassigned scores
     * @param   extra       Extra data to add as argument to the value printer
     * @param   printer     Value printer, takes arguments: index, value, extra data
     * @param   reroll      Pointer to a reroll function pointer, nullptr if not allowed
     * @return              Whether the assignment was completed
     */
    virtual bool assign(int n, int unassigned, void* data, void (*printer)(int, int, void*), void (**reroll)() == nullptr);

    /**
     * Ability score printer
     *
     * @param  index  The index of the ability
     * @param  value  The value of the ability
     * @param  data   Pointer to the 100-part of the strenght
     */
    virtual void abilityPrinter(int index, int value, void* data) const;

    /**
     * Generic attribute score printer
     *
     * @param  index  The index of the attribute
     * @param  value  The value of the attribute
     * @param  data   The labels of the attributes
     */
    virtual void genericPrinter(int index, int value, void* data) const;

    /**
     * Ability score reroll
     */
    virtual void abilityReroll();

  };

}

#endif//__GUARD_CHARACTERCREATOR_HPP__

<|endoftext|>


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

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#include <iostream>
#include <fstream>

#include "os_string.hpp"
#include "os_process.hpp"
#include "os_version.hpp"

#include "cli.hpp"
#include "cli_resources.hpp"

#if defined(__APPLE__)
#define TRACE_VARIABLE "DYLD_FRAMEWORK_PATH"
#define GL_TRACE_WRAPPER  "OpenGL.framework/OpenGL"
#elif defined(_WIN32)
#define GL_TRACE_WRAPPER  "opengl32.dll"
#else
#define TRACE_VARIABLE "LD_PRELOAD"
#define GL_TRACE_WRAPPER  "glxtrace.so"
#define EGL_TRACE_WRAPPER  "egltrace.so"
#endif

static inline bool
copyWrapper(const os::String & wrapperPath,
            const char *programPath,
            bool verbose)
{
    os::String wrapperFilename(wrapperPath);
    wrapperFilename.trimDirectory();

    os::String tmpWrapper(programPath);
    tmpWrapper.trimFilename();
    tmpWrapper.join(wrapperFilename);

    if (verbose) {
        std::cerr << wrapperPath << " -> " << tmpWrapper << "\n";
    }

    if (tmpWrapper.exists()) {
        std::cerr << "error: not overwriting " << tmpWrapper << "\n";
        return false;
    }

    if (!os::copyFile(wrapperPath, tmpWrapper, false)) {
        std::cerr << "error: failed to copy " << wrapperPath << " into " << tmpWrapper << "\n";
        return false;
    }

    return true;
}

static int
traceProgram(trace::API api,
             char * const *argv,
             const char *output,
             bool verbose,
             bool debug)
{
    const char *wrapperFilename;
    std::vector<const char *> args;
    int status = 1;

    /*
     * TODO: simplify code
     */

    bool useInject = false;
    switch (api) {
    case trace::API_GL:
        wrapperFilename = GL_TRACE_WRAPPER;
        break;
#ifdef EGL_TRACE_WRAPPER
    case trace::API_EGL:
        wrapperFilename = EGL_TRACE_WRAPPER;
        break;
#endif
#ifdef _WIN32
    case trace::API_D3D7:
        wrapperFilename = "ddraw.dll";
        break;
    case trace::API_D3D8:
        wrapperFilename = "d3d8.dll";
        break;
    case trace::API_D3D9:
        wrapperFilename = "d3d9.dll";
        break;
    case trace::API_DXGI:
        wrapperFilename = "dxgitrace.dll";
        useInject = true;
        break;
    case trace::API_D2D1:
        wrapperFilename = "d2d1trace.dll";
        useInject = true;
        break;
#endif
    default:
        std::cerr << "error: unsupported API\n";
        return 1;
    }

    os::String wrapperPath = findWrapper(wrapperFilename, verbose);
    if (!wrapperPath.length()) {
        std::cerr << "error: failed to find " << wrapperFilename << " wrapper (rerun with -v option for more details)\n";
        goto exit;
    }

#if defined(_WIN32)
    /*
     * Use DLL injection method on Windows, even for APIs that don't stricly
     * need it.
     */
    useInject = true;

    if (useInject) {
        args.push_back("inject");
        args.push_back(wrapperPath);
    } else {
        /* On Windows copy the wrapper to the program directory.
         */
        if (!copyWrapper(wrapperPath, argv[0], verbose)) {
            goto exit;
        }
    }
#else  /* !_WIN32 */
    (void)useInject;
#endif /* !_WIN32 */

#if defined(__APPLE__)
    /* On Mac OS X, using DYLD_LIBRARY_PATH, we actually set the
     * parent directory, not the file. */
    wrapperPath.trimFilename();
    wrapperPath.trimFilename();
#endif

    /*
     * Spawn child process.
     */

    {
#if defined(TRACE_VARIABLE)
        const char *oldEnvVarValue = getenv(TRACE_VARIABLE);
        if (oldEnvVarValue) {
            wrapperPath.append(OS_PATH_SEP);
            wrapperPath.append(oldEnvVarValue);
        }

        std::string ex;
        if (debug) {
#if defined(__APPLE__)
            bool lldb = true;
#else
            bool lldb = false;
#endif

            if (lldb) {
                /*
                 * Debug with LLDB.
                 *
                 * See also http://lldb.llvm.org/lldb-gdb.html
                 */

                char scriptFileName[] = "/tmp/apitrace.XXXXXX";
                int scriptFD = mkstemp(scriptFileName);
                if (scriptFD < 0) {
                    std::cerr << "error: failed to create temporary lldb script file\n";
                    exit(1);
                }

                FILE *scriptStream = fdopen(scriptFD, "w");
                fprintf(scriptStream, "env " TRACE_VARIABLE "='%s'\n", wrapperPath.str());
                fclose(scriptStream);

                args.push_back("lldb");
                args.push_back("-s");
                args.push_back(scriptFileName);
                args.push_back("--");
            } else {
                /*
                 * Debug with GDB.
                 */

                ex = "set exec-wrapper env " TRACE_VARIABLE "='";
                ex.append(wrapperPath.str());
                ex.append("'");

                args.push_back("gdb");
                args.push_back("--ex");
                args.push_back(ex.c_str());
                args.push_back("--args");
            }

            os::unsetEnvironment(TRACE_VARIABLE);
        } else {
            /* FIXME: Don't modify our (ie parent) environment */
            os::setEnvironment(TRACE_VARIABLE, wrapperPath.str());
        }

        if (verbose) {
            std::cerr << TRACE_VARIABLE << "=" << wrapperPath.str() << "\n";
        }
#endif /* TRACE_VARIABLE */

        if (output) {
            os::setEnvironment("TRACE_FILE", output);
        }

        for (char * const * arg = argv; *arg; ++arg) {
            args.push_back(*arg);
        }

        if (verbose) {
            const char *sep = "";
            for (unsigned i = 0; i < args.size(); ++i) {
                const char *quote;
                if (strchr(args[i], ' ') != NULL) {
                    quote = "\"";
                } else {
                    quote = "";
                }
                std::cerr << sep << quote << args[i] << quote;
                sep = " ";
            }
            std::cerr << "\n";
        }

        args.push_back(NULL);

        status = os::execute((char * const *)&args[0]);

#if defined(TRACE_VARIABLE)
        if (oldEnvVarValue) {
            os::setEnvironment(TRACE_VARIABLE, oldEnvVarValue);
        } else {
            os::unsetEnvironment(TRACE_VARIABLE);
        }
#endif
    }

exit:
#if defined(_WIN32)
    if (!useInject) {
        os::String tmpWrapper(argv[0]);
        tmpWrapper.trimFilename();
        tmpWrapper.join(wrapperFilename);
        os::removeFile(tmpWrapper);
    }
#endif

    if (output) {
        os::unsetEnvironment("TRACE_FILE");
    }

    return status;

}

static const char *synopsis = "Generate a new trace by executing the given program.";

static void
usage(void)
{
    std::cout << "usage: apitrace trace [OPTIONS] PROGRAM [ARGS ...]\n"
        << synopsis << "\n"
        "\n"
        "    The given program will be executed with the given arguments.\n"
        "    During execution, all OpenGL calls will be captured to a trace\n"
        "    file. That trace file can then be used\n"
        "    with other apitrace utilities for replay or analysis.\n"
        "\n"
        "    -v, --verbose       verbose output\n"
        "    -a, --api=API       specify API to trace ("
#ifdef _WIN32
                                                      "gl, d3d7, d3d8, d3d9, or dxgi (for d3d10 and higher) "
#else
                                                      "gl or egl"
#endif
                                                      ");\n"
        "                        default is `gl`\n"
        "    -o, --output=TRACE  specify output trace file;\n"
        "                        default is `PROGRAM.trace`\n"
#ifdef TRACE_VARIABLE
        "    -d,  --debug        run inside debugger (gdb/lldb)\n"
#endif
    ;
}

const static char *
shortOptions = "+hva:o:d";

const static struct option
longOptions[] = {
    {"help", no_argument, 0, 'h'},
    {"verbose", no_argument, 0, 'v'},
    {"api", required_argument, 0, 'a'},
    {"output", required_argument, 0, 'o'},
    {"debug", no_argument, 0, 'd'},
    {0, 0, 0, 0}
};

static int
command(int argc, char *argv[])
{
    bool verbose = false;
    trace::API api = trace::API_GL;
    const char *output = NULL;
    bool debug = false;

    int opt;
    while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
        switch (opt) {
        case 'h':
            usage();
            return 0;
        case 'v':
            verbose = true;
            break;
        case 'a':
            if (strcmp(optarg, "gl") == 0) {
                api = trace::API_GL;
            } else if (strcmp(optarg, "egl") == 0) {
                api = trace::API_EGL;
            } else if (strcmp(optarg, "d3d7") == 0) {
                api = trace::API_D3D7;
            } else if (strcmp(optarg, "d3d8") == 0) {
                api = trace::API_D3D8;
            } else if (strcmp(optarg, "d3d9") == 0) {
                api = trace::API_D3D9;
            } else if (strcmp(optarg, "dxgi") == 0 ||
                       strcmp(optarg, "d3d10") == 0 ||
                       strcmp(optarg, "d3d10_1") == 0 ||
                       strcmp(optarg, "d3d11") == 0 ||
                       strcmp(optarg, "d3d11_1") == 0) {
                api = trace::API_DXGI;
            } else if (strcmp(optarg, "d2d") == 0 ||
                       strcmp(optarg, "d2d1") == 0) {
                api = trace::API_D2D1;
            } else {
                std::cerr << "error: unknown API `" << optarg << "`\n";
                usage();
                return 1;
            }
            break;
        case 'o':
            output = optarg;
            break;
        case 'd':
            debug = true;
            break;
        default:
            std::cerr << "error: unexpected option `" << (char)opt << "`\n";
            usage();
            return 1;
        }
    }

    if (optind == argc) {
        std::cerr << "error: no command specified\n";
        usage();
        return 1;
    }

    assert(argv[argc] == 0);
    return traceProgram(api, argv + optind, output, verbose, debug);
}

const Command trace_command = {
    "trace",
    synopsis,
    usage,
    command
};
<commit_msg>cli: Silence unused copyWrapper function warning.<commit_after>/*********************************************************************
 *
 * Copyright 2011 Intel Corporation
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *********************************************************************/

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#include <iostream>
#include <fstream>

#include "os_string.hpp"
#include "os_process.hpp"
#include "os_version.hpp"

#include "cli.hpp"
#include "cli_resources.hpp"

#if defined(__APPLE__)
#define TRACE_VARIABLE "DYLD_FRAMEWORK_PATH"
#define GL_TRACE_WRAPPER  "OpenGL.framework/OpenGL"
#elif defined(_WIN32)
#define GL_TRACE_WRAPPER  "opengl32.dll"
#else
#define TRACE_VARIABLE "LD_PRELOAD"
#define GL_TRACE_WRAPPER  "glxtrace.so"
#define EGL_TRACE_WRAPPER  "egltrace.so"
#endif

#ifdef _WIN32

static inline bool
copyWrapper(const os::String & wrapperPath,
            const char *programPath,
            bool verbose)
{
    os::String wrapperFilename(wrapperPath);
    wrapperFilename.trimDirectory();

    os::String tmpWrapper(programPath);
    tmpWrapper.trimFilename();
    tmpWrapper.join(wrapperFilename);

    if (verbose) {
        std::cerr << wrapperPath << " -> " << tmpWrapper << "\n";
    }

    if (tmpWrapper.exists()) {
        std::cerr << "error: not overwriting " << tmpWrapper << "\n";
        return false;
    }

    if (!os::copyFile(wrapperPath, tmpWrapper, false)) {
        std::cerr << "error: failed to copy " << wrapperPath << " into " << tmpWrapper << "\n";
        return false;
    }

    return true;
}

#endif /* _WIN32 */

static int
traceProgram(trace::API api,
             char * const *argv,
             const char *output,
             bool verbose,
             bool debug)
{
    const char *wrapperFilename;
    std::vector<const char *> args;
    int status = 1;

    /*
     * TODO: simplify code
     */

    bool useInject = false;
    switch (api) {
    case trace::API_GL:
        wrapperFilename = GL_TRACE_WRAPPER;
        break;
#ifdef EGL_TRACE_WRAPPER
    case trace::API_EGL:
        wrapperFilename = EGL_TRACE_WRAPPER;
        break;
#endif
#ifdef _WIN32
    case trace::API_D3D7:
        wrapperFilename = "ddraw.dll";
        break;
    case trace::API_D3D8:
        wrapperFilename = "d3d8.dll";
        break;
    case trace::API_D3D9:
        wrapperFilename = "d3d9.dll";
        break;
    case trace::API_DXGI:
        wrapperFilename = "dxgitrace.dll";
        useInject = true;
        break;
    case trace::API_D2D1:
        wrapperFilename = "d2d1trace.dll";
        useInject = true;
        break;
#endif
    default:
        std::cerr << "error: unsupported API\n";
        return 1;
    }

    os::String wrapperPath = findWrapper(wrapperFilename, verbose);
    if (!wrapperPath.length()) {
        std::cerr << "error: failed to find " << wrapperFilename << " wrapper (rerun with -v option for more details)\n";
        goto exit;
    }

#if defined(_WIN32)
    /*
     * Use DLL injection method on Windows, even for APIs that don't stricly
     * need it.
     */
    useInject = true;

    if (useInject) {
        args.push_back("inject");
        args.push_back(wrapperPath);
    } else {
        /* On Windows copy the wrapper to the program directory.
         */
        if (!copyWrapper(wrapperPath, argv[0], verbose)) {
            goto exit;
        }
    }
#else  /* !_WIN32 */
    (void)useInject;
#endif /* !_WIN32 */

#if defined(__APPLE__)
    /* On Mac OS X, using DYLD_LIBRARY_PATH, we actually set the
     * parent directory, not the file. */
    wrapperPath.trimFilename();
    wrapperPath.trimFilename();
#endif

    /*
     * Spawn child process.
     */

    {
#if defined(TRACE_VARIABLE)
        const char *oldEnvVarValue = getenv(TRACE_VARIABLE);
        if (oldEnvVarValue) {
            wrapperPath.append(OS_PATH_SEP);
            wrapperPath.append(oldEnvVarValue);
        }

        std::string ex;
        if (debug) {
#if defined(__APPLE__)
            bool lldb = true;
#else
            bool lldb = false;
#endif

            if (lldb) {
                /*
                 * Debug with LLDB.
                 *
                 * See also http://lldb.llvm.org/lldb-gdb.html
                 */

                char scriptFileName[] = "/tmp/apitrace.XXXXXX";
                int scriptFD = mkstemp(scriptFileName);
                if (scriptFD < 0) {
                    std::cerr << "error: failed to create temporary lldb script file\n";
                    exit(1);
                }

                FILE *scriptStream = fdopen(scriptFD, "w");
                fprintf(scriptStream, "env " TRACE_VARIABLE "='%s'\n", wrapperPath.str());
                fclose(scriptStream);

                args.push_back("lldb");
                args.push_back("-s");
                args.push_back(scriptFileName);
                args.push_back("--");
            } else {
                /*
                 * Debug with GDB.
                 */

                ex = "set exec-wrapper env " TRACE_VARIABLE "='";
                ex.append(wrapperPath.str());
                ex.append("'");

                args.push_back("gdb");
                args.push_back("--ex");
                args.push_back(ex.c_str());
                args.push_back("--args");
            }

            os::unsetEnvironment(TRACE_VARIABLE);
        } else {
            /* FIXME: Don't modify our (ie parent) environment */
            os::setEnvironment(TRACE_VARIABLE, wrapperPath.str());
        }

        if (verbose) {
            std::cerr << TRACE_VARIABLE << "=" << wrapperPath.str() << "\n";
        }
#endif /* TRACE_VARIABLE */

        if (output) {
            os::setEnvironment("TRACE_FILE", output);
        }

        for (char * const * arg = argv; *arg; ++arg) {
            args.push_back(*arg);
        }

        if (verbose) {
            const char *sep = "";
            for (unsigned i = 0; i < args.size(); ++i) {
                const char *quote;
                if (strchr(args[i], ' ') != NULL) {
                    quote = "\"";
                } else {
                    quote = "";
                }
                std::cerr << sep << quote << args[i] << quote;
                sep = " ";
            }
            std::cerr << "\n";
        }

        args.push_back(NULL);

        status = os::execute((char * const *)&args[0]);

#if defined(TRACE_VARIABLE)
        if (oldEnvVarValue) {
            os::setEnvironment(TRACE_VARIABLE, oldEnvVarValue);
        } else {
            os::unsetEnvironment(TRACE_VARIABLE);
        }
#endif
    }

exit:
#if defined(_WIN32)
    if (!useInject) {
        os::String tmpWrapper(argv[0]);
        tmpWrapper.trimFilename();
        tmpWrapper.join(wrapperFilename);
        os::removeFile(tmpWrapper);
    }
#endif

    if (output) {
        os::unsetEnvironment("TRACE_FILE");
    }

    return status;

}

static const char *synopsis = "Generate a new trace by executing the given program.";

static void
usage(void)
{
    std::cout << "usage: apitrace trace [OPTIONS] PROGRAM [ARGS ...]\n"
        << synopsis << "\n"
        "\n"
        "    The given program will be executed with the given arguments.\n"
        "    During execution, all OpenGL calls will be captured to a trace\n"
        "    file. That trace file can then be used\n"
        "    with other apitrace utilities for replay or analysis.\n"
        "\n"
        "    -v, --verbose       verbose output\n"
        "    -a, --api=API       specify API to trace ("
#ifdef _WIN32
                                                      "gl, d3d7, d3d8, d3d9, or dxgi (for d3d10 and higher) "
#else
                                                      "gl or egl"
#endif
                                                      ");\n"
        "                        default is `gl`\n"
        "    -o, --output=TRACE  specify output trace file;\n"
        "                        default is `PROGRAM.trace`\n"
#ifdef TRACE_VARIABLE
        "    -d,  --debug        run inside debugger (gdb/lldb)\n"
#endif
    ;
}

const static char *
shortOptions = "+hva:o:d";

const static struct option
longOptions[] = {
    {"help", no_argument, 0, 'h'},
    {"verbose", no_argument, 0, 'v'},
    {"api", required_argument, 0, 'a'},
    {"output", required_argument, 0, 'o'},
    {"debug", no_argument, 0, 'd'},
    {0, 0, 0, 0}
};

static int
command(int argc, char *argv[])
{
    bool verbose = false;
    trace::API api = trace::API_GL;
    const char *output = NULL;
    bool debug = false;

    int opt;
    while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
        switch (opt) {
        case 'h':
            usage();
            return 0;
        case 'v':
            verbose = true;
            break;
        case 'a':
            if (strcmp(optarg, "gl") == 0) {
                api = trace::API_GL;
            } else if (strcmp(optarg, "egl") == 0) {
                api = trace::API_EGL;
            } else if (strcmp(optarg, "d3d7") == 0) {
                api = trace::API_D3D7;
            } else if (strcmp(optarg, "d3d8") == 0) {
                api = trace::API_D3D8;
            } else if (strcmp(optarg, "d3d9") == 0) {
                api = trace::API_D3D9;
            } else if (strcmp(optarg, "dxgi") == 0 ||
                       strcmp(optarg, "d3d10") == 0 ||
                       strcmp(optarg, "d3d10_1") == 0 ||
                       strcmp(optarg, "d3d11") == 0 ||
                       strcmp(optarg, "d3d11_1") == 0) {
                api = trace::API_DXGI;
            } else if (strcmp(optarg, "d2d") == 0 ||
                       strcmp(optarg, "d2d1") == 0) {
                api = trace::API_D2D1;
            } else {
                std::cerr << "error: unknown API `" << optarg << "`\n";
                usage();
                return 1;
            }
            break;
        case 'o':
            output = optarg;
            break;
        case 'd':
            debug = true;
            break;
        default:
            std::cerr << "error: unexpected option `" << (char)opt << "`\n";
            usage();
            return 1;
        }
    }

    if (optind == argc) {
        std::cerr << "error: no command specified\n";
        usage();
        return 1;
    }

    assert(argv[argc] == 0);
    return traceProgram(api, argv + optind, output, verbose, debug);
}

const Command trace_command = {
    "trace",
    synopsis,
    usage,
    command
};
<|endoftext|>


<commit_before><commit_msg>WaE: class has virtual functions, but destructor is not virtual<commit_after><|endoftext|>


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

#include "MQ/MQException.h"
#include "MQ/Web/MessageConsumerTask.h"
#include "MQ/Web/JSONMessage.h"

namespace MQ {
namespace Web {

MessageConsumerTask::MessageConsumerTask(Poco::SharedPtr<Poco::Net::WebSocket> ws, QueueManagerPoolGuard::Ptr queueManagerPoolGuard, const std::string& queueName)
	: Poco::Task("MessageConsumer"), _ws(ws), _qmgrPoolGuard(queueManagerPoolGuard), _count(0)
{
	poco_assert_dbg(!queueManagerPoolGuard.isNull());

	Poco::Timespan ts(10, 0);
	_ws->setReceiveTimeout(ts);
	_ws->setSendTimeout(ts);

	QueueManager::Ptr qmgr = queueManagerPoolGuard->getObject();
	_consumer = new MessageConsumer(qmgr, queueName, MessageConsumer::BROWSE);
	_consumer->messageEvent += Poco::delegate(this, &MessageConsumerTask::onMessage);
	_consumer->errorEvent += Poco::delegate(this, &MessageConsumerTask::onError);
}

MessageConsumerTask::~MessageConsumerTask()
{
	_consumer->messageEvent -= Poco::delegate(this, &MessageConsumerTask::onMessage);
	_consumer->errorEvent -= Poco::delegate(this, &MessageConsumerTask::onError);
}

void MessageConsumerTask::cancel()
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");
	logger.trace("MessageConsumerTask cancelling ...");

	try
	{
		_consumer->stop();
	}
	catch (MQException&)
	{
		//Ignore to make sure the socket is closed and the task is cancelled.
	}

	_ws->close();

	Poco::Task::cancel();

	logger.trace("MessageConsumerTask cancelled.");
}

void MessageConsumerTask::runTask()
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");
	logger.trace("MessageConsumerTask started ...");

	_consumer->start();

	char buffer[1024];
	int n;
	int flags;
	do
	{
		try
		{
			n = _ws->receiveFrame(buffer, sizeof(buffer), flags);
			logger.trace("Number of messages: so far %d", _count);
		}
		catch (Poco::TimeoutException&)
		{
			logger.trace("Timeout");
			break;
		}
		catch (Poco::Net::NetException&)
		{
			logger.trace("NetException received. WebSocket closed by the client?");
			break;
		}
	} while (n > 0 || (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE);

	logger.trace("MessageConsumerTask ended.");
}

void MessageConsumerTask::onMessage(const void* pSender, Message::Ptr& msg)
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");
	logger.trace("A message is received %s", msg->messageId()->toHex());

	_count++;

	JSONMessage jsonMessage(msg);
	Poco::JSON::Object::Ptr json = new Poco::JSON::Object();
	jsonMessage.toJSON(json);

	std::stringstream ss;
	json->stringify(ss);
	std::string content = ss.str();
	try
	{
		_ws->sendFrame(content.c_str(), content.length(), Poco::Net::WebSocket::FRAME_TEXT);
	}
	catch (Poco::Exception&)
	{
		cancel();
	}
}

void MessageConsumerTask::onError(const void* pSender, MQLONG& rc)
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");
	logger.trace("An MQ error is received %ld. Task will be cancelled.", rc);
	cancel();
}

}} // Namespace MQ::Web
<commit_msg>Add mqmd to JSON<commit_after>/*
* Copyright 2017 - KBC Group NV - Franky Braem - The MIT license
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
*  copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "Poco/Delegate.h"
#include "Poco/Logger.h"
#include "Poco/Net/NetException.h"

#include "MQ/MQException.h"
#include "MQ/Web/MessageConsumerTask.h"
#include "MQ/Web/JSONMessage.h"

namespace MQ {
namespace Web {

MessageConsumerTask::MessageConsumerTask(Poco::SharedPtr<Poco::Net::WebSocket> ws, QueueManagerPoolGuard::Ptr queueManagerPoolGuard, const std::string& queueName)
	: Poco::Task("MessageConsumer"), _ws(ws), _qmgrPoolGuard(queueManagerPoolGuard), _count(0)
{
	poco_assert_dbg(!queueManagerPoolGuard.isNull());

	Poco::Timespan ts(10, 0);
	_ws->setReceiveTimeout(ts);
	_ws->setSendTimeout(ts);

	QueueManager::Ptr qmgr = queueManagerPoolGuard->getObject();
	_consumer = new MessageConsumer(qmgr, queueName, MessageConsumer::BROWSE);
	_consumer->messageEvent += Poco::delegate(this, &MessageConsumerTask::onMessage);
	_consumer->errorEvent += Poco::delegate(this, &MessageConsumerTask::onError);
}

MessageConsumerTask::~MessageConsumerTask()
{
	_consumer->messageEvent -= Poco::delegate(this, &MessageConsumerTask::onMessage);
	_consumer->errorEvent -= Poco::delegate(this, &MessageConsumerTask::onError);
}

void MessageConsumerTask::cancel()
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");
	logger.trace("MessageConsumerTask cancelling ...");

	try
	{
		_consumer->stop();
	}
	catch (MQException&)
	{
		//Ignore to make sure the socket is closed and the task is cancelled.
	}

	_ws->close();

	Poco::Task::cancel();

	logger.trace("MessageConsumerTask cancelled.");
}

void MessageConsumerTask::runTask()
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");
	logger.trace("MessageConsumerTask started ...");

	_consumer->start();

	char buffer[1024];
	int n;
	int flags;
	do
	{
		try
		{
			n = _ws->receiveFrame(buffer, sizeof(buffer), flags);
			logger.trace("Number of messages: so far %d", _count);
		}
		catch (Poco::TimeoutException&)
		{
			logger.trace("Timeout");
			break;
		}
		catch (Poco::Net::NetException&)
		{
			logger.trace("NetException received. WebSocket closed by the client?");
			break;
		}
	} while (n > 0 || (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE);

	logger.trace("MessageConsumerTask ended.");
}

void MessageConsumerTask::onMessage(const void* pSender, Message::Ptr& msg)
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");
	logger.trace("A message is received %s", msg->messageId()->toHex());

	_count++;

	JSONMessage jsonMessage(msg);
	Poco::JSON::Object::Ptr json = new Poco::JSON::Object();
	json->set("mqmd", jsonMessage.toJSONMQMD());
	jsonMessage.toJSON(json);

	std::stringstream ss;
	json->stringify(ss);
	std::string content = ss.str();
	try
	{
		_ws->sendFrame(content.c_str(), content.length(), Poco::Net::WebSocket::FRAME_TEXT);
	}
	catch (Poco::Exception&)
	{
		cancel();
	}
}

void MessageConsumerTask::onError(const void* pSender, MQLONG& rc)
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");
	logger.trace("An MQ error is received %ld. Task will be cancelled.", rc);
	cancel();
}

}} // Namespace MQ::Web
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/magnet_uri.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/escape_string.hpp"

#include <string>
#include <sstream>

namespace libtorrent
{
	std::string make_magnet_uri(torrent_handle const& handle)
	{
		std::stringstream ret;
		if (!handle.is_valid()) return ret.str();

		std::string name = handle.name();

		ret << "magnet:?xt=urn:btih:" << base32encode((char*)handle.info_hash().begin());
		if (!name.empty())
			ret << "&dn=" << escape_string(name.c_str(), name.length());
		torrent_status st = handle.status();
		if (!st.current_tracker.empty())
		{
			ret << "&tr=" << escape_string(st.current_tracker.c_str()
				, st.current_tracker.length());
		}
		else
		{
			std::vector<announce_entry> const& tr = handle.trackers();
			if (!tr.empty())
			{
				ret << "&tr=" << escape_string(tr[0].url.c_str()
					, tr[0].url.length());
			}
		}
		return ret.str();
	}

	torrent_handle add_magnet_uri(session& ses, std::string const& uri
		, fs::path const& save_path
		, storage_mode_t storage_mode
		, bool paused
		, storage_constructor_type sc
		, void* userdata)
	{
		std::string name;
		std::string tracker;

		boost::optional<std::string> display_name = url_has_argument(uri, "dn");
		if (display_name) name = unescape_string(display_name->c_str());
		boost::optional<std::string> tracker_string = url_has_argument(uri, "tr");
		if (tracker_string) tracker = unescape_string(tracker_string->c_str());

		boost::optional<std::string> btih = url_has_argument(uri, "xt");
		if (!btih) return torrent_handle();

		if (btih->compare(0, 9, "urn:btih:") != 0) return torrent_handle();

		sha1_hash info_hash(base32decode(btih->substr(9)));

		return ses.add_torrent(tracker.empty() ? 0 : tracker.c_str(), info_hash
			, name.empty() ? 0 : name.c_str(), save_path, entry()
			, storage_mode, paused, sc, userdata);
	}
}

<commit_msg>fixed bug in make_magnet_uri<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/magnet_uri.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/escape_string.hpp"

#include <string>
#include <sstream>

namespace libtorrent
{
	std::string make_magnet_uri(torrent_handle const& handle)
	{
		std::stringstream ret;
		if (!handle.is_valid()) return ret.str();

		std::string name = handle.name();

		ret << "magnet:?xt=urn:btih:" << base32encode(
			std::string((char*)handle.info_hash().begin(), 20));
		if (!name.empty())
			ret << "&dn=" << escape_string(name.c_str(), name.length());
		torrent_status st = handle.status();
		if (!st.current_tracker.empty())
		{
			ret << "&tr=" << escape_string(st.current_tracker.c_str()
				, st.current_tracker.length());
		}
		else
		{
			std::vector<announce_entry> const& tr = handle.trackers();
			if (!tr.empty())
			{
				ret << "&tr=" << escape_string(tr[0].url.c_str()
					, tr[0].url.length());
			}
		}
		return ret.str();
	}

	torrent_handle add_magnet_uri(session& ses, std::string const& uri
		, fs::path const& save_path
		, storage_mode_t storage_mode
		, bool paused
		, storage_constructor_type sc
		, void* userdata)
	{
		std::string name;
		std::string tracker;

		boost::optional<std::string> display_name = url_has_argument(uri, "dn");
		if (display_name) name = unescape_string(display_name->c_str());
		boost::optional<std::string> tracker_string = url_has_argument(uri, "tr");
		if (tracker_string) tracker = unescape_string(tracker_string->c_str());

		boost::optional<std::string> btih = url_has_argument(uri, "xt");
		if (!btih) return torrent_handle();

		if (btih->compare(0, 9, "urn:btih:") != 0) return torrent_handle();

		sha1_hash info_hash(base32decode(btih->substr(9)));

		return ses.add_torrent(tracker.empty() ? 0 : tracker.c_str(), info_hash
			, name.empty() ? 0 : name.c_str(), save_path, entry()
			, storage_mode, paused, sc, userdata);
	}
}

<|endoftext|>