<commit_before>/*
 * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
 * All rights reserved. Distributed under the terms of the MIT License.
 */

#include "TextEditor.h"

#include <algorithm>
#include <stdio.h>

TextEditor::TextEditor()
	:
	fDocument(),
	fLayout(),
	fSelection(),
	fCaretAnchorX(0.0f),
	fStyleAtCaret(),
	fEditingEnabled(true)
{
}

TextEditor::TextEditor(const TextEditor& other)
	:
	fDocument(other.fDocument),
	fLayout(other.fLayout),
	fSelection(other.fSelection),
	fCaretAnchorX(other.fCaretAnchorX),
	fStyleAtCaret(other.fStyleAtCaret),
	fEditingEnabled(other.fEditingEnabled)
{
}

TextEditor::~TextEditor()
{
}

TextEditor&
TextEditor::operator=(const TextEditor& other)
{
	if (this == &other)
		return *this;

	fDocument = other.fDocument;
	fLayout = other.fLayout;
	fSelection = other.fSelection;
	fCaretAnchorX = other.fCaretAnchorX;
	fStyleAtCaret = other.fStyleAtCaret;
	fEditingEnabled = other.fEditingEnabled;
	return *this;
}

bool
TextEditor::operator==(const TextEditor& other) const
{
	if (this == &other)
		return true;

	return fDocument == other.fDocument
		&& fLayout == other.fLayout
		&& fSelection == other.fSelection
		&& fCaretAnchorX == other.fCaretAnchorX
		&& fStyleAtCaret == other.fStyleAtCaret
		&& fEditingEnabled == other.fEditingEnabled;
}

bool
TextEditor::operator!=(const TextEditor& other) const
{
	return !(*this == other);
}

// #pragma mark -

void
TextEditor::SetDocument(const TextDocumentRef& ref)
{
	fDocument = ref;
	SetSelection(TextSelection());
}

void
TextEditor::SetLayout(const TextDocumentLayoutRef& ref)
{
	fLayout = ref;
	SetSelection(TextSelection());
}

void
TextEditor::SetEditingEnabled(bool enabled)
{
	fEditingEnabled = enabled;
}

void
TextEditor::SetCaret(BPoint location, bool extendSelection)
{
	if (fDocument.Get() == NULL || fLayout.Get() == NULL)
		return;

	bool rightOfChar = false;
	int32 caretOffset = fLayout->TextOffsetAt(location.x, location.y,
		rightOfChar);

	if (rightOfChar)
		caretOffset++;

	_SetCaretOffset(caretOffset, true, extendSelection, true);
}

void
TextEditor::SelectAll()
{
	if (fDocument.Get() == NULL)
		return;

	SetSelection(TextSelection(0, fDocument->Length()));
}

void
TextEditor::SetSelection(TextSelection selection)
{
	_SetSelection(selection.Caret(), selection.Anchor(), true, true);
}

void
TextEditor::SetCharacterStyle(::CharacterStyle style)
{
	if (fStyleAtCaret == style)
		return;

	fStyleAtCaret = style;

	if (HasSelection()) {
		int32			i		= 0;
		int32			q		= 0;
		TextDocumentRef	tRef	= fDocument.Get()->SubDocument(fSelection.Start(),fSelection.Length());
		ParagraphList	prgList	= tRef.Get()->Paragraphs();
		Paragraph		tmpPrgh;
		TextSpanList	txtSpList;
		TextSpan		tmpSpan;
		for (i=0; i<prgList.CountItems();i++)
		{
			tmpPrgh=prgList.ItemAtFast(i);
			txtSpList=tmpPrgh.TextSpans();
			for (q=0; q<txtSpList.CountItems(); q++)
			{
				tmpSpan=txtSpList.ItemAtFast(q);
				//TODO get the style
				//Replace the changed style
			}

		}
		// TODO: Apply style to selection range
	}
}

void
TextEditor::KeyDown(KeyEvent event)
{
	if (fDocument.Get() == NULL)
		return;

	bool select = (event.modifiers & B_SHIFT_KEY) != 0;

	switch (event.key) {
		case B_UP_ARROW:
			LineUp(select);
			break;

		case B_DOWN_ARROW:
			LineDown(select);
			break;

		case B_LEFT_ARROW:
			if (HasSelection() && !select) {
				_SetCaretOffset(
					std::min(fSelection.Caret(), fSelection.Anchor()),
					true, false, true);
			} else
				_SetCaretOffset(fSelection.Caret() - 1, true, select, true);
			break;

		case B_RIGHT_ARROW:
			if (HasSelection() && !select) {
				_SetCaretOffset(
					std::max(fSelection.Caret(), fSelection.Anchor()),
					true, false, true);
			} else
				_SetCaretOffset(fSelection.Caret() + 1, true, select, true);
			break;

		case B_HOME:
			LineStart(select);
			break;

		case B_END:
			LineEnd(select);
			break;

		case B_ENTER:
			Insert(fSelection.Caret(), "\n");
			break;

		case B_TAB:
			// TODO: Tab support in TextLayout
			Insert(fSelection.Caret(), " ");
			break;

		case B_ESCAPE:
			break;

		case B_BACKSPACE:
			if (HasSelection()) {
				Remove(SelectionStart(), SelectionLength());
			} else {
				if (fSelection.Caret() > 0)
					Remove(fSelection.Caret() - 1, 1);
			}
			break;

		case B_DELETE:
			if (HasSelection()) {
				Remove(SelectionStart(), SelectionLength());
			} else {
				if (fSelection.Caret() < fDocument->Length())
					Remove(fSelection.Caret(), 1);
			}
			break;

		case B_INSERT:
			// TODO: Toggle insert mode (or maybe just don't support it)
			break;

		case B_PAGE_UP:
		case B_PAGE_DOWN:
		case B_SUBSTITUTE:
		case B_FUNCTION_KEY:
		case B_KATAKANA_HIRAGANA:
		case B_HANKAKU_ZENKAKU:
			break;

		default:
			if (event.bytes != NULL && event.length > 0) {
				// Handle null-termintating the string
				BString text(event.bytes, event.length);

				Replace(SelectionStart(), SelectionLength(), text);
			}
			break;
	}
}

status_t
TextEditor::Insert(int32 offset, const BString& string)
{
	if (!fEditingEnabled || fDocument.Get() == NULL)
		return B_ERROR;

	status_t ret = fDocument->Insert(offset, string, fStyleAtCaret);

	if (ret == B_OK) {
		_SetCaretOffset(offset + string.CountChars(), true, false, true);

		fDocument->PrintToStream();
	}

	return ret;
}

status_t
TextEditor::Remove(int32 offset, int32 length)
{
	if (!fEditingEnabled || fDocument.Get() == NULL)
		return B_ERROR;

	status_t ret = fDocument->Remove(offset, length);

	if (ret == B_OK) {
		_SetCaretOffset(offset, true, false, true);

		fDocument->PrintToStream();
	}

	return ret;
}

status_t
TextEditor::Replace(int32 offset, int32 length, const BString& string)
{
	if (!fEditingEnabled || fDocument.Get() == NULL)
		return B_ERROR;

	status_t ret = fDocument->Replace(offset, length, string);

	if (ret == B_OK) {
		_SetCaretOffset(offset + string.CountChars(), true, false, true);

		fDocument->PrintToStream();
	}

	return ret;
}

// #pragma mark -

void
TextEditor::LineUp(bool select)
{
	if (fLayout.Get() == NULL)
		return;

	int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret());
	_MoveToLine(lineIndex - 1, select);
}

void
TextEditor::LineDown(bool select)
{
	if (fLayout.Get() == NULL)
		return;

	int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret());
	_MoveToLine(lineIndex + 1, select);
}

void
TextEditor::LineStart(bool select)
{
	if (fLayout.Get() == NULL)
		return;

	int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret());
	_SetCaretOffset(fLayout->FirstOffsetOnLine(lineIndex), true, select,
		true);
}

void
TextEditor::LineEnd(bool select)
{
	if (fLayout.Get() == NULL)
		return;

	int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret());
	_SetCaretOffset(fLayout->LastOffsetOnLine(lineIndex), true, select,
		true);
}

// #pragma mark -

bool
TextEditor::HasSelection() const
{
	return SelectionLength() > 0;
}

int32
TextEditor::SelectionStart() const
{
	return std::min(fSelection.Caret(), fSelection.Anchor());
}

int32
TextEditor::SelectionEnd() const
{
	return std::max(fSelection.Caret(), fSelection.Anchor());
}

int32
TextEditor::SelectionLength() const
{
	return SelectionEnd() - SelectionStart();
}

// #pragma mark - private

// _MoveToLine
void
TextEditor::_MoveToLine(int32 lineIndex, bool select)
{
	if (lineIndex < 0) {
		// Move to beginning of line instead. Most editors do. Some only when
		// selecting. Note that we are not updating the horizontal anchor here,
		// even though the horizontal caret position changes. Most editors
		// return to the previous horizonal offset when moving back down from
		// the beginning of the line.
		_SetCaretOffset(0, false, select, true);
		return;
	}
	if (lineIndex >= fLayout->CountLines()) {
		// Move to end of line instead, see above for why we do not update the
		// horizontal anchor.
		_SetCaretOffset(fDocument->Length(), false, select, true);
		return;
	}

	float x1;
	float y1;
	float x2;
	float y2;
	fLayout->GetLineBounds(lineIndex , x1, y1, x2, y2);

	bool rightOfCenter;
	int32 textOffset = fLayout->TextOffsetAt(fCaretAnchorX, (y1 + y2) / 2,
		rightOfCenter);

	if (rightOfCenter)
		textOffset++;

	_SetCaretOffset(textOffset, false, select, true);
}

void
TextEditor::_SetCaretOffset(int32 offset, bool updateAnchor,
	bool lockSelectionAnchor, bool updateSelectionStyle)
{
	if (fDocument.Get() == NULL)
		return;

	if (offset < 0)
		offset = 0;
	int32 textLength = fDocument->Length();
	if (offset > textLength)
		offset = textLength;

	int32 caret = offset;
	int32 anchor = lockSelectionAnchor ? fSelection.Anchor() : offset;
	_SetSelection(caret, anchor, updateAnchor, updateSelectionStyle);
}

void
TextEditor::_SetSelection(int32 caret, int32 anchor, bool updateAnchor,
	bool updateSelectionStyle)
{
	if (fLayout.Get() == NULL)
		return;

	if (caret == fSelection.Caret() && anchor == fSelection.Anchor())
		return;

	fSelection.SetCaret(caret);
	fSelection.SetAnchor(anchor);

	if (updateAnchor) {
		float x1;
		float y1;
		float x2;
		float y2;

		fLayout->GetTextBounds(caret, x1, y1, x2, y2);
		fCaretAnchorX = x1;
	}

	if (updateSelectionStyle)
		_UpdateStyleAtCaret();
}

void
TextEditor::_UpdateStyleAtCaret()
{
	if (fDocument.Get() == NULL)
		return;

	int32 offset = fSelection.Caret() - 1;
	if (offset < 0)
		offset = 0;
	SetCharacterStyle(fDocument->CharacterStyleAt(offset));
}

<commit_msg>small comments<commit_after>/*
 * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>.
 * All rights reserved. Distributed under the terms of the MIT License.
 */

#include "TextEditor.h"

#include <algorithm>
#include <stdio.h>

TextEditor::TextEditor()
	:
	fDocument(),
	fLayout(),
	fSelection(),
	fCaretAnchorX(0.0f),
	fStyleAtCaret(),
	fEditingEnabled(true)
{
}

TextEditor::TextEditor(const TextEditor& other)
	:
	fDocument(other.fDocument),
	fLayout(other.fLayout),
	fSelection(other.fSelection),
	fCaretAnchorX(other.fCaretAnchorX),
	fStyleAtCaret(other.fStyleAtCaret),
	fEditingEnabled(other.fEditingEnabled)
{
}

TextEditor::~TextEditor()
{
}

TextEditor&
TextEditor::operator=(const TextEditor& other)
{
	if (this == &other)
		return *this;

	fDocument = other.fDocument;
	fLayout = other.fLayout;
	fSelection = other.fSelection;
	fCaretAnchorX = other.fCaretAnchorX;
	fStyleAtCaret = other.fStyleAtCaret;
	fEditingEnabled = other.fEditingEnabled;
	return *this;
}

bool
TextEditor::operator==(const TextEditor& other) const
{
	if (this == &other)
		return true;

	return fDocument == other.fDocument
		&& fLayout == other.fLayout
		&& fSelection == other.fSelection
		&& fCaretAnchorX == other.fCaretAnchorX
		&& fStyleAtCaret == other.fStyleAtCaret
		&& fEditingEnabled == other.fEditingEnabled;
}

bool
TextEditor::operator!=(const TextEditor& other) const
{
	return !(*this == other);
}

// #pragma mark -

void
TextEditor::SetDocument(const TextDocumentRef& ref)
{
	fDocument = ref;
	SetSelection(TextSelection());
}

void
TextEditor::SetLayout(const TextDocumentLayoutRef& ref)
{
	fLayout = ref;
	SetSelection(TextSelection());
}

void
TextEditor::SetEditingEnabled(bool enabled)
{
	fEditingEnabled = enabled;
}

void
TextEditor::SetCaret(BPoint location, bool extendSelection)
{
	if (fDocument.Get() == NULL || fLayout.Get() == NULL)
		return;

	bool rightOfChar = false;
	int32 caretOffset = fLayout->TextOffsetAt(location.x, location.y,
		rightOfChar);

	if (rightOfChar)
		caretOffset++;

	_SetCaretOffset(caretOffset, true, extendSelection, true);
}

void
TextEditor::SelectAll()
{
	if (fDocument.Get() == NULL)
		return;

	SetSelection(TextSelection(0, fDocument->Length()));
}

void
TextEditor::SetSelection(TextSelection selection)
{
	_SetSelection(selection.Caret(), selection.Anchor(), true, true);
}

void
TextEditor::SetCharacterStyle(::CharacterStyle style)
{
	if (fStyleAtCaret == style)
		return;

	fStyleAtCaret = style;

	if (HasSelection()) {
		int32			i		= 0;
		int32			q		= 0;
		TextDocumentRef	tRef	= fDocument.Get()->SubDocument(fSelection.Start(),fSelection.Length());
		ParagraphList	prgList	= tRef.Get()->Paragraphs();
		Paragraph		tmpPrgh;
		TextSpanList	txtSpList;
		TextSpan		tmpSpan;
		for (i=0; i<prgList.CountItems();i++)
		{
			tmpPrgh=prgList.ItemAtFast(i);
			txtSpList=tmpPrgh.TextSpans();
			for (q=0; q<txtSpList.CountItems(); q++)
			{
				tmpSpan=txtSpList.ItemAtFast(q);

				//TODO find out what property from CharacterStyle
				// should be applied because if you press bold you dont want to change all the other
				// properties wich are stored in CharacterStyle... thats a real challange
				//For now only Replace the whole style
				if (tmpSpan != NULL)
					tmpSpan.SetStyle(style)
			}

		}
		// TODO: Apply style to selection range
	}
}

void
TextEditor::KeyDown(KeyEvent event)
{
	if (fDocument.Get() == NULL)
		return;

	bool select = (event.modifiers & B_SHIFT_KEY) != 0;

	switch (event.key) {
		case B_UP_ARROW:
			LineUp(select);
			break;

		case B_DOWN_ARROW:
			LineDown(select);
			break;

		case B_LEFT_ARROW:
			if (HasSelection() && !select) {
				_SetCaretOffset(
					std::min(fSelection.Caret(), fSelection.Anchor()),
					true, false, true);
			} else
				_SetCaretOffset(fSelection.Caret() - 1, true, select, true);
			break;

		case B_RIGHT_ARROW:
			if (HasSelection() && !select) {
				_SetCaretOffset(
					std::max(fSelection.Caret(), fSelection.Anchor()),
					true, false, true);
			} else
				_SetCaretOffset(fSelection.Caret() + 1, true, select, true);
			break;

		case B_HOME:
			LineStart(select);
			break;

		case B_END:
			LineEnd(select);
			break;

		case B_ENTER:
			Insert(fSelection.Caret(), "\n");
			break;

		case B_TAB:
			// TODO: Tab support in TextLayout
			Insert(fSelection.Caret(), " ");
			break;

		case B_ESCAPE:
			break;

		case B_BACKSPACE:
			if (HasSelection()) {
				Remove(SelectionStart(), SelectionLength());
			} else {
				if (fSelection.Caret() > 0)
					Remove(fSelection.Caret() - 1, 1);
			}
			break;

		case B_DELETE:
			if (HasSelection()) {
				Remove(SelectionStart(), SelectionLength());
			} else {
				if (fSelection.Caret() < fDocument->Length())
					Remove(fSelection.Caret(), 1);
			}
			break;

		case B_INSERT:
			// TODO: Toggle insert mode (or maybe just don't support it)
			break;

		case B_PAGE_UP:
		case B_PAGE_DOWN:
		case B_SUBSTITUTE:
		case B_FUNCTION_KEY:
		case B_KATAKANA_HIRAGANA:
		case B_HANKAKU_ZENKAKU:
			break;

		default:
			if (event.bytes != NULL && event.length > 0) {
				// Handle null-termintating the string
				BString text(event.bytes, event.length);

				Replace(SelectionStart(), SelectionLength(), text);
			}
			break;
	}
}

status_t
TextEditor::Insert(int32 offset, const BString& string)
{
	if (!fEditingEnabled || fDocument.Get() == NULL)
		return B_ERROR;

	status_t ret = fDocument->Insert(offset, string, fStyleAtCaret);

	if (ret == B_OK) {
		_SetCaretOffset(offset + string.CountChars(), true, false, true);

		fDocument->PrintToStream();
	}

	return ret;
}

status_t
TextEditor::Remove(int32 offset, int32 length)
{
	if (!fEditingEnabled || fDocument.Get() == NULL)
		return B_ERROR;

	status_t ret = fDocument->Remove(offset, length);

	if (ret == B_OK) {
		_SetCaretOffset(offset, true, false, true);

		fDocument->PrintToStream();
	}

	return ret;
}

status_t
TextEditor::Replace(int32 offset, int32 length, const BString& string)
{
	if (!fEditingEnabled || fDocument.Get() == NULL)
		return B_ERROR;

	status_t ret = fDocument->Replace(offset, length, string);

	if (ret == B_OK) {
		_SetCaretOffset(offset + string.CountChars(), true, false, true);

		fDocument->PrintToStream();
	}

	return ret;
}

// #pragma mark -

void
TextEditor::LineUp(bool select)
{
	if (fLayout.Get() == NULL)
		return;

	int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret());
	_MoveToLine(lineIndex - 1, select);
}

void
TextEditor::LineDown(bool select)
{
	if (fLayout.Get() == NULL)
		return;

	int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret());
	_MoveToLine(lineIndex + 1, select);
}

void
TextEditor::LineStart(bool select)
{
	if (fLayout.Get() == NULL)
		return;

	int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret());
	_SetCaretOffset(fLayout->FirstOffsetOnLine(lineIndex), true, select,
		true);
}

void
TextEditor::LineEnd(bool select)
{
	if (fLayout.Get() == NULL)
		return;

	int32 lineIndex = fLayout->LineIndexForOffset(fSelection.Caret());
	_SetCaretOffset(fLayout->LastOffsetOnLine(lineIndex), true, select,
		true);
}

// #pragma mark -

bool
TextEditor::HasSelection() const
{
	return SelectionLength() > 0;
}

int32
TextEditor::SelectionStart() const
{
	return std::min(fSelection.Caret(), fSelection.Anchor());
}

int32
TextEditor::SelectionEnd() const
{
	return std::max(fSelection.Caret(), fSelection.Anchor());
}

int32
TextEditor::SelectionLength() const
{
	return SelectionEnd() - SelectionStart();
}

// #pragma mark - private

// _MoveToLine
void
TextEditor::_MoveToLine(int32 lineIndex, bool select)
{
	if (lineIndex < 0) {
		// Move to beginning of line instead. Most editors do. Some only when
		// selecting. Note that we are not updating the horizontal anchor here,
		// even though the horizontal caret position changes. Most editors
		// return to the previous horizonal offset when moving back down from
		// the beginning of the line.
		_SetCaretOffset(0, false, select, true);
		return;
	}
	if (lineIndex >= fLayout->CountLines()) {
		// Move to end of line instead, see above for why we do not update the
		// horizontal anchor.
		_SetCaretOffset(fDocument->Length(), false, select, true);
		return;
	}

	float x1;
	float y1;
	float x2;
	float y2;
	fLayout->GetLineBounds(lineIndex , x1, y1, x2, y2);

	bool rightOfCenter;
	int32 textOffset = fLayout->TextOffsetAt(fCaretAnchorX, (y1 + y2) / 2,
		rightOfCenter);

	if (rightOfCenter)
		textOffset++;

	_SetCaretOffset(textOffset, false, select, true);
}

void
TextEditor::_SetCaretOffset(int32 offset, bool updateAnchor,
	bool lockSelectionAnchor, bool updateSelectionStyle)
{
	if (fDocument.Get() == NULL)
		return;

	if (offset < 0)
		offset = 0;
	int32 textLength = fDocument->Length();
	if (offset > textLength)
		offset = textLength;

	int32 caret = offset;
	int32 anchor = lockSelectionAnchor ? fSelection.Anchor() : offset;
	_SetSelection(caret, anchor, updateAnchor, updateSelectionStyle);
}

void
TextEditor::_SetSelection(int32 caret, int32 anchor, bool updateAnchor,
	bool updateSelectionStyle)
{
	if (fLayout.Get() == NULL)
		return;

	if (caret == fSelection.Caret() && anchor == fSelection.Anchor())
		return;

	fSelection.SetCaret(caret);
	fSelection.SetAnchor(anchor);

	if (updateAnchor) {
		float x1;
		float y1;
		float x2;
		float y2;

		fLayout->GetTextBounds(caret, x1, y1, x2, y2);
		fCaretAnchorX = x1;
	}

	if (updateSelectionStyle)
		_UpdateStyleAtCaret();
}

void
TextEditor::_UpdateStyleAtCaret()
{
	if (fDocument.Get() == NULL)
		return;

	int32 offset = fSelection.Caret() - 1;
	if (offset < 0)
		offset = 0;
	SetCharacterStyle(fDocument->CharacterStyleAt(offset));
}

<|endoftext|>


<commit_before>/* ************************************************************************* */
/* This file is part of Shard.                                               */
/*                                                                           */
/* Shard is free software: you can redistribute it and/or modify             */
/* it under the terms of the GNU Affero General Public License as            */
/* published by the Free Software Foundation.                                */
/*                                                                           */
/* 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 Affero General Public License for more details.                       */
/*                                                                           */
/* You should have received a copy of the GNU Affero General Public License  */
/* along with this program. If not, see <http://www.gnu.org/licenses/>.      */
/* ************************************************************************* */

#include "shard/tokenizer/Tokenizer.hpp"

/* ************************************************************************* */

// C++
#include <algorithm>
#include <cmath>

// Shard
#include "shard/StaticArray.hpp"

/* ************************************************************************* */

namespace shard {
inline namespace v1 {
namespace tokenizer {

/* ************************************************************************* */

namespace
{
    static const StaticArray<std::pair<String, KeywordType>, 22> g_keywordMap
    {{
    #define KEYWORD(name, str) { str, KeywordType::name },
    #include "shard/tokenizer/Token.def"
    }};

    static char getEscaped(const char value)
    {
        switch (value)
        {
            case '"': return '"';
            case '\'': return '\'';
            case '?': return '\?';
            case '\\': return '\\';
            case '0': return '\0';
            case 'a': return '\a';
            case 'b': return '\b';
            case 'f': return '\f';
            case 'n': return '\n';
            case 'r': return '\r';
            case 't': return '\t';
            case 'v': return '\v';
            default: throw InvalidEscapeSequenceException();
        }
    }
}

/* ************************************************************************* */

void Tokenizer::tokenizeNumber()
{
    bool floatFlag = false;
    int digitSize = 0;

    const auto readNumber = [&]() -> Token::IntType
    {
        digitSize = 0;
        if (!isDigit())
        {
            throw ExpectedNumberException();
        }
        Token::IntType res = 0;
        do
        {
            res = res * 10 + (m_src.extract() - '0');
            ++digitSize;
        }
        while (isDigit());
        return res;
    };

    Token::IntType base = readNumber();

    Token::FloatType decimal = 0;
    if (match('.'))
    {
        floatFlag = true;
        decimal = readNumber();
        decimal = decimal / std::pow(10.0, digitSize);
    }

    Token::FloatType exp = 1;
    if (match('e', 'E'))
    {
        floatFlag = true;
        bool negativeExp = false;
        switch (m_src.get())
        {
            case '-': negativeExp = true;
            case '+': m_src.extract();
            default: break;
        }
        exp = std::pow(10.0, readNumber());
        exp = negativeExp ? (1 / exp) : exp;
    }

    Token::FloatType value = (static_cast<Token::FloatType>(base) + decimal) * exp;

    m_current = floatFlag ? Token(value) : Token(base);
}

void Tokenizer::tokenizeString()
{
    String value;

    while (!match(string_literal_border))
    {
        if (empty())
        {
            throw StringWithoutEndException();
        }
        if (match('\\'))
        {
            if (empty())
            {
                throw StringWithoutEndException();
            }
            value += getEscaped(m_src.extract());
        }
        else
        {
            value += m_src.extract();
        }
    }

    m_current = Token(TokenType::String, value);
}

void Tokenizer::tokenizeChar()
{
    char value;

    switch (char local = m_src.extract())
    {
        case '\\':
        {
            if (empty())
            {
                throw CharWithoutEndException();
            }
            value = getEscaped(m_src.extract());
            break;
        }
        case char_literal_border:
        {
            throw EmptyCharLiteralException();
        }
        default:
        {
            value = local;
        }
    }
    if (!match(char_literal_border))
    {
        throw CharWithoutEndException();
    }

    m_current = Token(value);
}

void Tokenizer::tokenizeIdentifier() noexcept
{
    String value;

    do
    {
        value += m_src.extract();
    }
    while (isIdentifier());
    auto search = std::find_if(
        g_keywordMap.begin(), g_keywordMap.end(),
        [&](const std::pair<String, KeywordType>& test){ return test.first == value; }
    );
    if (search != g_keywordMap.end())
    {
        m_current = Token(search->second);
    }
    else
    {
        m_current = Token(value);
    }
}

void Tokenizer::tokenizeOperator()
{
    switch (char local = m_src.extract())
    {
        case '.': m_current = Token(TokenType::Period); break;
        case ',': m_current = Token(TokenType::Comma); break;
        case ':': m_current = Token(TokenType::Colon); break;
        case ';': m_current = Token(TokenType::Semicolon); break;
        case '{': m_current = Token(TokenType::BraceO); break;
        case '}': m_current = Token(TokenType::BraceC); break;
        case '[': m_current = Token(TokenType::SquareO); break;
        case ']': m_current = Token(TokenType::SquareC); break;
        case '(': m_current = Token(TokenType::ParenO); break;
        case ')': m_current = Token(TokenType::ParenC); break;
        case '=':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::EqualEqual); m_src.extract(); break;
                case '<': m_current = Token(TokenType::LessEqual); m_src.extract(); break;
                case '>': m_current = Token(TokenType::GreaterEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Equal); break;
            } break;
        }
        case '+':
        {
            switch (m_src.get())
            {
                case '+': m_current = Token(TokenType::PlusPlus); m_src.extract(); break;
                case '=': m_current = Token(TokenType::PlusEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Plus); break;
            } break;
        }
        case '-':
        {
            switch (m_src.get())
            {
                case '-': m_current = Token(TokenType::MinusMinus); m_src.extract(); break;
                case '=': m_current = Token(TokenType::MinusEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Minus); break;
            } break;
        }
        case '*':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::StarEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Star); break;
            } break;
        }
        case '/':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::SlashEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Slash); break;
            } break;
        }
        case '^':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::CaretEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Caret); break;
            } break;
        }
        case '~': m_current = Token(TokenType::Tilde); break;
        case '#': m_current = Token(TokenType::Hash); break;
        case '\\': m_current = Token(TokenType::Backslash); break;
        case '%':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::PercentEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Equal); break;
            } break;
        }
        case '&':
        {
            switch (m_src.get())
            {
                case '&': m_current = Token(TokenType::AmpAmp); m_src.extract(); break;
                default: m_current = Token(TokenType::Amp); break;
            } break;
        }
        case '|':
        {
            switch (m_src.get())
            {
                case '|': m_current = Token(TokenType::PipePipe); m_src.extract(); break;
                case '=': m_current = Token(TokenType::PipeEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Pipe); break;
            } break;
        }
        case '?': m_current = Token(TokenType::QMark); break;
        case '!':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::EMarkEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::EMark); break;
            } break;
        }
        case '<':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::LessEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Less); break;
            } break;
        }
        case '>':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::GreaterEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Greater); break;
            } break;
        }
        default: throw UnknownOperatorException(local);
    }
}

void Tokenizer::next()
{
    skipWhitespace();
    skipComments();
    skipWhitespace();

    if (empty())
    {
        m_current = Token(TokenType::End);
    }
    else if (match(string_literal_border))
    {
        tokenizeString();
    }
    else if (match(char_literal_border))
    {
        tokenizeChar();
    }
    else if (isDigit())
    {
        tokenizeNumber();
    }
    else if (isIdentifier())
    {
        tokenizeIdentifier();
    }
    else
    {
        tokenizeOperator();
    }
}

/* ************************************************************************* */

}
}
}

/* ************************************************************************* */

<commit_msg>added missing commentary<commit_after>/* ************************************************************************* */
/* This file is part of Shard.                                               */
/*                                                                           */
/* Shard is free software: you can redistribute it and/or modify             */
/* it under the terms of the GNU Affero General Public License as            */
/* published by the Free Software Foundation.                                */
/*                                                                           */
/* 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 Affero General Public License for more details.                       */
/*                                                                           */
/* You should have received a copy of the GNU Affero General Public License  */
/* along with this program. If not, see <http://www.gnu.org/licenses/>.      */
/* ************************************************************************* */

#include "shard/tokenizer/Tokenizer.hpp"

/* ************************************************************************* */

// C++
#include <algorithm>
#include <cmath>

// Shard
#include "shard/StaticArray.hpp"

/* ************************************************************************* */

namespace shard {
inline namespace v1 {
namespace tokenizer {

/* ************************************************************************* */

namespace
{
    static const StaticArray<std::pair<String, KeywordType>, 22> g_keywordMap
    {{
    #define KEYWORD(name, str) { str, KeywordType::name },
    #include "shard/tokenizer/Token.def"
    }};

    /**
     * @brief returns escaped char value.
     */
    static char getEscaped(const char value)
    {
        switch (value)
        {
            case '"': return '"';
            case '\'': return '\'';
            case '?': return '\?';
            case '\\': return '\\';
            case '0': return '\0';
            case 'a': return '\a';
            case 'b': return '\b';
            case 'f': return '\f';
            case 'n': return '\n';
            case 'r': return '\r';
            case 't': return '\t';
            case 'v': return '\v';
            default: throw InvalidEscapeSequenceException();
        }
    }
}

/* ************************************************************************* */

void Tokenizer::tokenizeNumber()
{
    bool floatFlag = false;
    int digitSize = 0;

    const auto readNumber = [&]() -> Token::IntType
    {
        digitSize = 0;
        if (!isDigit())
        {
            throw ExpectedNumberException();
        }
        Token::IntType res = 0;
        do
        {
            res = res * 10 + (m_src.extract() - '0');
            ++digitSize;
        }
        while (isDigit());
        return res;
    };

    Token::IntType base = readNumber();

    Token::FloatType decimal = 0;
    if (match('.'))
    {
        floatFlag = true;
        decimal = readNumber();
        decimal = decimal / std::pow(10.0, digitSize);
    }

    Token::FloatType exp = 1;
    if (match('e', 'E'))
    {
        floatFlag = true;
        bool negativeExp = false;
        switch (m_src.get())
        {
            case '-': negativeExp = true;
            case '+': m_src.extract();
            default: break;
        }
        exp = std::pow(10.0, readNumber());
        exp = negativeExp ? (1 / exp) : exp;
    }

    Token::FloatType value = (static_cast<Token::FloatType>(base) + decimal) * exp;

    m_current = floatFlag ? Token(value) : Token(base);
}

void Tokenizer::tokenizeString()
{
    String value;

    while (!match(string_literal_border))
    {
        if (empty())
        {
            throw StringWithoutEndException();
        }
        if (match('\\'))
        {
            if (empty())
            {
                throw StringWithoutEndException();
            }
            value += getEscaped(m_src.extract());
        }
        else
        {
            value += m_src.extract();
        }
    }

    m_current = Token(TokenType::String, value);
}

void Tokenizer::tokenizeChar()
{
    char value;

    switch (char local = m_src.extract())
    {
        case '\\':
        {
            if (empty())
            {
                throw CharWithoutEndException();
            }
            value = getEscaped(m_src.extract());
            break;
        }
        case char_literal_border:
        {
            throw EmptyCharLiteralException();
        }
        default:
        {
            value = local;
        }
    }
    if (!match(char_literal_border))
    {
        throw CharWithoutEndException();
    }

    m_current = Token(value);
}

void Tokenizer::tokenizeIdentifier() noexcept
{
    String value;

    do
    {
        value += m_src.extract();
    }
    while (isIdentifier());
    auto search = std::find_if(
        g_keywordMap.begin(), g_keywordMap.end(),
        [&](const std::pair<String, KeywordType>& test){ return test.first == value; }
    );
    if (search != g_keywordMap.end())
    {
        m_current = Token(search->second);
    }
    else
    {
        m_current = Token(value);
    }
}

void Tokenizer::tokenizeOperator()
{
    switch (char local = m_src.extract())
    {
        case '.': m_current = Token(TokenType::Period); break;
        case ',': m_current = Token(TokenType::Comma); break;
        case ':': m_current = Token(TokenType::Colon); break;
        case ';': m_current = Token(TokenType::Semicolon); break;
        case '{': m_current = Token(TokenType::BraceO); break;
        case '}': m_current = Token(TokenType::BraceC); break;
        case '[': m_current = Token(TokenType::SquareO); break;
        case ']': m_current = Token(TokenType::SquareC); break;
        case '(': m_current = Token(TokenType::ParenO); break;
        case ')': m_current = Token(TokenType::ParenC); break;
        case '=':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::EqualEqual); m_src.extract(); break;
                case '<': m_current = Token(TokenType::LessEqual); m_src.extract(); break;
                case '>': m_current = Token(TokenType::GreaterEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Equal); break;
            } break;
        }
        case '+':
        {
            switch (m_src.get())
            {
                case '+': m_current = Token(TokenType::PlusPlus); m_src.extract(); break;
                case '=': m_current = Token(TokenType::PlusEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Plus); break;
            } break;
        }
        case '-':
        {
            switch (m_src.get())
            {
                case '-': m_current = Token(TokenType::MinusMinus); m_src.extract(); break;
                case '=': m_current = Token(TokenType::MinusEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Minus); break;
            } break;
        }
        case '*':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::StarEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Star); break;
            } break;
        }
        case '/':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::SlashEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Slash); break;
            } break;
        }
        case '^':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::CaretEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Caret); break;
            } break;
        }
        case '~': m_current = Token(TokenType::Tilde); break;
        case '#': m_current = Token(TokenType::Hash); break;
        case '\\': m_current = Token(TokenType::Backslash); break;
        case '%':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::PercentEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Equal); break;
            } break;
        }
        case '&':
        {
            switch (m_src.get())
            {
                case '&': m_current = Token(TokenType::AmpAmp); m_src.extract(); break;
                default: m_current = Token(TokenType::Amp); break;
            } break;
        }
        case '|':
        {
            switch (m_src.get())
            {
                case '|': m_current = Token(TokenType::PipePipe); m_src.extract(); break;
                case '=': m_current = Token(TokenType::PipeEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Pipe); break;
            } break;
        }
        case '?': m_current = Token(TokenType::QMark); break;
        case '!':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::EMarkEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::EMark); break;
            } break;
        }
        case '<':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::LessEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Less); break;
            } break;
        }
        case '>':
        {
            switch (m_src.get())
            {
                case '=': m_current = Token(TokenType::GreaterEqual); m_src.extract(); break;
                default: m_current = Token(TokenType::Greater); break;
            } break;
        }
        default: throw UnknownOperatorException(local);
    }
}

void Tokenizer::next()
{
    skipWhitespace();
    skipComments();
    skipWhitespace();

    if (empty())
    {
        m_current = Token(TokenType::End);
    }
    else if (match(string_literal_border))
    {
        tokenizeString();
    }
    else if (match(char_literal_border))
    {
        tokenizeChar();
    }
    else if (isDigit())
    {
        tokenizeNumber();
    }
    else if (isIdentifier())
    {
        tokenizeIdentifier();
    }
    else
    {
        tokenizeOperator();
    }
}

/* ************************************************************************* */

}
}
}

/* ************************************************************************* */

<|endoftext|>


<commit_before>#ifndef ALGORITHM_THR
#define ALGORITHM_THR
#include<algorithm>	//move, remove_if
#include<cstddef>	//ptrdiff_t
#include<functional>	//bind, equal_to, function, placeholders, ref
#include<iterator>	//distance, iterator_traits, next
#include<type_traits>	//make_unsigned
#include"algorithm.hpp"
#include"../thread/CSmartThread.hpp"

namespace nAlgorithm
{
	//unique_without_sort_thr will reorder the input permutation.
	template<class FwdIter,class BinaryPred=std::equal_to<typename std::iterator_traits<FwdIter>::value_type>>
	FwdIter unique_without_sort_thr(const FwdIter begin,const FwdIter end,const std::size_t N,const BinaryPred pred=BinaryPred())
	{
		using namespace std;
		function<void(FwdIter,FwdIter,FwdIter &)> unique_without_sort_thr_{[&,N,pred](const FwdIter begin,const FwdIter end,FwdIter &divide){
			const size_t size{static_cast<make_unsigned<ptrdiff_t>::type>(distance(begin,end))};
			if(N&&N<size)
			{
				divide=end;
				FwdIter lhs_end,rhs_end;
				const auto mid{next(begin,size/2)};
				{
					nThread::CSmartThread lhs{unique_without_sort_thr_,begin,mid,ref(lhs_end)},
						rhs{unique_without_sort_thr_,mid,end,ref(rhs_end)};
				}
				for_each(begin,lhs_end,[&,pred,mid](const typename iterator_traits<FwdIter>::value_type &val){
					rhs_end=remove_if(mid,rhs_end,bind(pred,ref(val),placeholders::_1));
				});
				divide=move(mid,rhs_end,lhs_end);
			}
			else
				divide=unique_without_sort(begin,end,pred);
		}};
		FwdIter retVal;
		unique_without_sort_thr_(begin,end,retVal);
		return retVal;
	}

	template<class FwdIter,class BinaryPred=std::equal_to<typename std::iterator_traits<FwdIter>::value_type>>
	inline FwdIter unique_without_sort_thr(FwdIter begin,FwdIter end,BinaryPred pred=BinaryPred())
	{
		return unique_without_sort_thr(begin,end,std::distance(begin,end)/2,pred);
	}
}

#endif<commit_msg>use async instead of CSmartThread<commit_after>#ifndef ALGORITHM_THR
#define ALGORITHM_THR
#include<algorithm>	//for_each, move, remove_if
#include<cstddef>	//size_t
#include<functional>	//bind, equal_to, function, placeholders, ref
#include<future>	//async, launch
#include<iterator>	//distance, iterator_traits, next
#include"algorithm.hpp"

namespace nAlgorithm
{
	//will reorder the permutation of [begin,end)
	template<class FwdIter,class BinaryPred=std::equal_to<typename std::iterator_traits<FwdIter>::value_type>>
	FwdIter unique_without_sort_thr(const FwdIter begin,const FwdIter end,const std::size_t N,const BinaryPred pred=BinaryPred())
	{
		using namespace std;
		function<FwdIter(FwdIter,FwdIter)> unique_without_sort_thr_{[&,N,pred](const FwdIter begin,const FwdIter end){
			const auto size{static_cast<size_t>(distance(begin,end))};
			if(N&&N<size)
			{
				const auto mid{next(begin,size/2)};
				const auto lhs_end{async(launch::async,unique_without_sort_thr_,begin,mid).get()};
				auto rhs_end{async(launch::async,unique_without_sort_thr_,mid,end).get()};
				for_each(begin,lhs_end,[&,pred,mid](const typename iterator_traits<FwdIter>::value_type &val){
					rhs_end=remove_if(mid,rhs_end,bind(pred,ref(val),placeholders::_1));
				});
				return move(mid,rhs_end,lhs_end);
			}
			return unique_without_sort(begin,end,pred);
		}};
		return unique_without_sort_thr_(begin,end);
	}

	template<class FwdIter>
	inline FwdIter unique_without_sort_thr(const FwdIter begin,const FwdIter end)
	{
		return unique_without_sort_thr(begin,end,std::distance(begin,end)/2);
	}
}

#endif<|endoftext|>


<commit_before>/*

Copyright (c) 2007-2010, Python File Format Interface
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 Python File Format Interface
     project 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 <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/support_ostream_iterator.hpp>

#include "pyffi/object_models/ast.hpp"

namespace pyffi
{

namespace object_models
{

namespace karma = boost::spirit::karma;

template <typename OutputIterator>
struct scope_karma_grammar : karma::grammar<OutputIterator, Scope()> {
    karma::rule<OutputIterator, Scope()> start;
    karma::rule<OutputIterator, Class(int)> class_;
    karma::rule<OutputIterator, Attr(int)> attr;
    karma::rule<OutputIterator, Scope(int)> scope;
    karma::rule<OutputIterator, void(int)> indent;

    scope_karma_grammar()
        : scope_karma_grammar::base_type(start) {

    indent = karma::left_align(karma::_r1)[karma::eps];

    start = scope(0);

    scope = *(class_(karma::_r1) | attr(karma::_r1));

    class_ =
        indent(karma::_r1)
        << "class "
        << karma::string // Class.name
        << -('(' << karma::string << ')') // Class.base_name
        << -(':' << karma::eol << scope(karma::_r1 + 4)) // Class.scope
        << karma::eol;

    attr =
        indent(karma::_r1)
        << karma::string // Attr.class_name
        << ' ' << karma::string // Attr.name
        << karma::eol;
}
};

bool generate(std::ostream & out, Scope const & scope)
{
    // wrap ostream into iterator
    boost::spirit::ostream_iterator sink(out);

    // create parser
    scope_karma_grammar<boost::spirit::ostream_iterator> parser;

    // use iterator to parse class
    return karma::generate(sink, parser, scope);
}

}

}
<commit_msg>Eol bugfix.<commit_after>/*

Copyright (c) 2007-2010, Python File Format Interface
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 Python File Format Interface
     project 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 <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/support_ostream_iterator.hpp>

#include "pyffi/object_models/ast.hpp"

namespace pyffi
{

namespace object_models
{

namespace karma = boost::spirit::karma;

template <typename OutputIterator>
struct scope_karma_grammar : karma::grammar<OutputIterator, Scope()> {
    karma::rule<OutputIterator, Scope()> start;
    karma::rule<OutputIterator, Declaration(int)> declaration;
    karma::rule<OutputIterator, Class(int)> class_;
    karma::rule<OutputIterator, Attr(int)> attr;
    karma::rule<OutputIterator, Scope(int)> scope;
    karma::rule<OutputIterator, void(int)> indent;

    scope_karma_grammar()
        : scope_karma_grammar::base_type(start) {

    indent = karma::left_align(karma::_r1)[karma::eps];

    start = scope(0) << karma::eol;

    declaration = class_(karma::_r1) | attr(karma::_r1);

    scope = declaration(karma::_r1) % karma::eol;

    class_ =
        indent(karma::_r1)
        << "class "
        << karma::string // Class.name
        << -('(' << karma::string << ')') // Class.base_name
        << -(':' << karma::eol << scope(karma::_r1 + 4)); // Class.scope

    attr =
        indent(karma::_r1)
        << karma::string // Attr.class_name
        << ' ' << karma::string; // Attr.name
}
};

bool generate(std::ostream & out, Scope const & scope)
{
    // wrap ostream into iterator
    boost::spirit::ostream_iterator sink(out);

    // create parser
    scope_karma_grammar<boost::spirit::ostream_iterator> parser;

    // use iterator to parse class
    return karma::generate(sink, parser, scope);
}

}

}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see doc/COPYING or http://www.libelektra.org)
 */

#include <mountbase.hpp>

#include <backend.hpp>
#include <backends.hpp>
#include <cmdline.hpp>

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

using namespace std;
using namespace kdb;
using namespace kdb::tools;

/**
 * @brief Read in configuration and print warnings
 *
 * @post will update mountConf
 */
void MountBaseCommand::readMountConf (Cmdline const & cl)
{
	Key parentKey (mountpointsPath, KEY_END);

	kdb.get (mountConf, parentKey);

	if (!cl.null && cl.first && cl.second && cl.third)
	{
		printWarnings (cerr, parentKey);
	}
}

void MountBaseCommand::outputMissingRecommends (std::vector<std::string> missingRecommends)
{
	if (!missingRecommends.empty ())
	{
		std::cout << "Missing recommended plugins: ";
		for (auto const & p : missingRecommends)
		{
			std::cout << p << " ";
		}
		std::cout << std::endl;
	}
}

/**
 * @brief set mp (interactive or by commandline)
 *
 * @see getName()
 */
void MountBaseCommand::getMountpoint (Cmdline const & cl)
{
	Key cur;
	std::vector<std::string> mountpoints;
	mountpoints.push_back ("system/elektra");
	mountConf.rewind ();
	while ((cur = mountConf.next ()))
	{
		if (cur.getBaseName () == "mountpoint")
		{
			if (cur.getString ().at (0) == '/')
			{
				mountpoints.push_back (Key ("user" + cur.getString (), KEY_END).getName ());
				mountpoints.push_back (Key ("system" + cur.getString (), KEY_END).getName ());
			}
			else
			{
				mountpoints.push_back (cur.getString ());
			}
		};
	}

	if (cl.interactive)
	{
		cout << "Already used are: ";
		std::copy (mountpoints.begin (), mountpoints.end (), ostream_iterator<std::string> (cout, " "));
		cout << endl;
		cout << "Please start with / for a cascading backend" << endl;
		cout << "Enter the mountpoint: ";
		cin >> mp;
	}
	else
	{
		mp = cl.createKey (1).getName ();
	}
}

void MountBaseCommand::askForConfirmation (Cmdline const & cl)
{
	if (cl.interactive)
	{
		cout << endl;
		cout << "Ready to mount with following configuration:" << endl;
		cout << "Mountpoint: " << mp << endl;
		cout << "Path:       " << path << endl;
	}

	if (cl.debug)
	{
		cout << "The configuration which will be set is:" << endl;
		mountConf.rewind ();
		while (Key k = mountConf.next ())
		{
			cout << k.getName () << " " << k.getString () << endl;
		}
	}

	if (cl.interactive)
	{
		cout << "Are you sure you want to do that (y/N): ";
		std::string answer;
		cin >> answer;
		if (answer != "y") throw CommandAbortException ();
	}

	if (cl.debug)
	{
		cout << "Now writing the mountpoint configuration";
	}
}

class KDBMountException : public KDBException
{
	std::string msg;

public:
	KDBMountException (std::string const & e) : KDBException (Key ())
	{
		msg = e;
	}

	virtual const char * what () const noexcept override
	{
		return msg.c_str ();
	}
};

/**
 * @brief Really write out config
 */
void MountBaseCommand::doIt ()
{
	Key parentKey (mountpointsPath, KEY_END);

	try
	{
		kdb.set (mountConf, parentKey);
	}
	catch (KDBException const & e)
	{
		throw KDBMountException (std::string (e.what ()) +
					 "\n\n"
					 "IMPORTANT: Mounting tries to write to system/elektra/mountpoints.\n"
					 "           Make sure that you can write to `Configfile:` as mentioned above.\n"
					 "           Usually you need to be root for that (use `sudo !!`).");
	}

	printWarnings (cerr, parentKey);
}
<commit_msg>kdb mount: improve error message<commit_after>/**
 * @file
 *
 * @brief
 *
 * @copyright BSD License (see doc/COPYING or http://www.libelektra.org)
 */

#include <mountbase.hpp>

#include <backend.hpp>
#include <backends.hpp>
#include <cmdline.hpp>

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>

using namespace std;
using namespace kdb;
using namespace kdb::tools;

/**
 * @brief Read in configuration and print warnings
 *
 * @post will update mountConf
 */
void MountBaseCommand::readMountConf (Cmdline const & cl)
{
	Key parentKey (mountpointsPath, KEY_END);

	kdb.get (mountConf, parentKey);

	if (!cl.null && cl.first && cl.second && cl.third)
	{
		printWarnings (cerr, parentKey);
	}
}

void MountBaseCommand::outputMissingRecommends (std::vector<std::string> missingRecommends)
{
	if (!missingRecommends.empty ())
	{
		std::cout << "Missing recommended plugins: ";
		for (auto const & p : missingRecommends)
		{
			std::cout << p << " ";
		}
		std::cout << std::endl;
	}
}

/**
 * @brief set mp (interactive or by commandline)
 *
 * @see getName()
 */
void MountBaseCommand::getMountpoint (Cmdline const & cl)
{
	Key cur;
	std::vector<std::string> mountpoints;
	mountpoints.push_back ("system/elektra");
	mountConf.rewind ();
	while ((cur = mountConf.next ()))
	{
		if (cur.getBaseName () == "mountpoint")
		{
			if (cur.getString ().at (0) == '/')
			{
				mountpoints.push_back (Key ("user" + cur.getString (), KEY_END).getName ());
				mountpoints.push_back (Key ("system" + cur.getString (), KEY_END).getName ());
			}
			else
			{
				mountpoints.push_back (cur.getString ());
			}
		};
	}

	if (cl.interactive)
	{
		cout << "Already used are: ";
		std::copy (mountpoints.begin (), mountpoints.end (), ostream_iterator<std::string> (cout, " "));
		cout << endl;
		cout << "Please start with / for a cascading backend" << endl;
		cout << "Enter the mountpoint: ";
		cin >> mp;
	}
	else
	{
		mp = cl.createKey (1).getName ();
	}
}

void MountBaseCommand::askForConfirmation (Cmdline const & cl)
{
	if (cl.interactive)
	{
		cout << endl;
		cout << "Ready to mount with following configuration:" << endl;
		cout << "Mountpoint: " << mp << endl;
		cout << "Path:       " << path << endl;
	}

	if (cl.debug)
	{
		cout << "The configuration which will be set is:" << endl;
		mountConf.rewind ();
		while (Key k = mountConf.next ())
		{
			cout << k.getName () << " " << k.getString () << endl;
		}
	}

	if (cl.interactive)
	{
		cout << "Are you sure you want to do that (y/N): ";
		std::string answer;
		cin >> answer;
		if (answer != "y") throw CommandAbortException ();
	}

	if (cl.debug)
	{
		cout << "Now writing the mountpoint configuration";
	}
}

class KDBMountException : public KDBException
{
	std::string msg;

public:
	KDBMountException (std::string const & e) : KDBException (Key ())
	{
		msg = e;
	}

	virtual const char * what () const noexcept override
	{
		return msg.c_str ();
	}
};

/**
 * @brief Really write out config
 */
void MountBaseCommand::doIt ()
{
	Key parentKey (mountpointsPath, KEY_END);

	try
	{
		kdb.set (mountConf, parentKey);
	}
	catch (KDBException const & e)
	{
		throw KDBMountException (std::string (e.what ()) +
					 "\n\n"
					 "IMPORTANT: Sorry, I am unable to write your requested mountpoint to system/elektra/mountpoints.\n"
					 "           Make sure that you can write to `Configfile:` as mentioned above.\n"
					 "           Usually you need to be root for that (use `sudo !!`).");
	}

	printWarnings (cerr, parentKey);
}
<|endoftext|>


<commit_before>
//#include <QCoreApplication>
#include <QStringList>
#include <QFile>
#include <QVector>
#include <QTextStream>
#include <iostream>

int main(int argc, char *argv[])
{
    if (argc != 4) {
        std::cerr << "Usage: qpatch file.list oldQtDir newQtDir" << std::endl;
        return EXIT_FAILURE;
    }

    const QByteArray files = argv[1];
    const QByteArray qtDirPath = argv[2];
    const QByteArray newQtPath = argv[3];

    if (qtDirPath.size() < newQtPath.size()) {
        std::cerr << "qpatch: error: newQtDir needs to be less than " << qtDirPath.size() << " characters."
                << std::endl;
        return EXIT_FAILURE;
    }

    QFile fn(QFile::decodeName(files));
    if (! fn.open(QFile::ReadOnly)) {
        std::cerr << "qpatch: error: file not found" << std::endl;
        return EXIT_FAILURE;
    }

    QStringList filesToPatch, textFilesToPatch;
    bool readingTextFilesToPatch = false;

    // read the input file
    QTextStream in(&fn);

    forever {
        const QString line = in.readLine();

        if (line.isNull())
            break;

        else if (line.isEmpty())
            continue;

        else if (line.startsWith(QLatin1String("%%")))
            readingTextFilesToPatch = true;

        else if (readingTextFilesToPatch)
            textFilesToPatch.append(line);

        else
            filesToPatch.append(line);
    }

    foreach (QString fileName, filesToPatch) {
        QString prefix = QFile::decodeName(newQtPath);

        if (! prefix.endsWith(QLatin1Char('/')))
            prefix += QLatin1Char('/');

        fileName.prepend(prefix);

        QFile file(fileName);
        if (! file.open(QFile::ReadOnly)) {
            std::cerr << "qpatch: warning: file `" << qPrintable(fileName) << "' not found" << std::endl;
            continue;
        }

        const QByteArray source = file.readAll();
        file.close();

        int index = 0;

        if (! file.open(QFile::WriteOnly | QFile::Truncate)) {
            std::cerr << "qpatch: error: file `" << qPrintable(fileName) << "' not writable" << std::endl;
            continue;
        }

        forever {
            int start = source.indexOf(qtDirPath, index);
            if (start == -1)
                break;

            int endOfString = start;
            for (; endOfString < source.size(); ++endOfString) {
                if (! source.at(endOfString))
                    break;
            }

            ++endOfString; // include the '\0'

            if (index != start)
                file.write(source.constData() + index, start - index);

            int length = endOfString - start;
            QVector<char> s;

            for (const char *x = newQtPath.constData(); x != newQtPath.constEnd(); ++x)
                s.append(*x);

            const int qtDirPathLength = qtDirPath.size();

            for (const char *x = source.constData() + start + qtDirPathLength;
                    x != source.constData() + endOfString; ++x)
                s.append(*x);

            const int oldSize = s.size();

            for (int i = oldSize; i < length; ++i)
                s.append('\0');

#if 0
            std::cout << "replace string: " << source.mid(start, endOfString - start).constData()
                    << " with: " << s.constData() << std::endl;
#endif

            file.write(s.constData(), s.size());

            index = endOfString;
        }

        if (index != source.size())
            file.write(source.constData() + index, source.size() - index);
    }

    foreach (QString fileName, textFilesToPatch) {
        QString prefix = QFile::decodeName(newQtPath);

        if (! prefix.endsWith(QLatin1Char('/')))
            prefix += QLatin1Char('/');

        fileName.prepend(prefix);

        QFile file(fileName);
        if (! file.open(QFile::ReadOnly)) {
            std::cerr << "qpatch: warning: file `" << qPrintable(fileName) << "' not found" << std::endl;
            continue;
        }

        QByteArray source = file.readAll();
        file.close();

        if (! file.open(QFile::WriteOnly | QFile::Truncate)) {
            std::cerr << "qpatch: error: file `" << qPrintable(fileName) << "' not writable" << std::endl;
            continue;
        }

        source.replace(qtDirPath, newQtPath);
        file.write(source);
    }

    return 0;
}
<commit_msg>Added some addition output to qpatch<commit_after>
//#include <QCoreApplication>
#include <QStringList>
#include <QFile>
#include <QVector>
#include <QTextStream>
#include <iostream>

int main(int argc, char *argv[])
{
    if (argc != 4) {
        std::cerr << "Usage: qpatch file.list oldQtDir newQtDir" << std::endl;
        return EXIT_FAILURE;
    }

    const QByteArray files = argv[1];
    const QByteArray qtDirPath = argv[2];
    const QByteArray newQtPath = argv[3];

    if (qtDirPath.size() < newQtPath.size()) {
        std::cerr << "qpatch: error: newQtDir needs to be less than " << qtDirPath.size() << " characters."
                << std::endl;
        return EXIT_FAILURE;
    }

    QFile fn(QFile::decodeName(files));
    if (! fn.open(QFile::ReadOnly)) {
        std::cerr << "qpatch: error: file not found" << std::endl;
        return EXIT_FAILURE;
    }

    QStringList filesToPatch, textFilesToPatch;
    bool readingTextFilesToPatch = false;

    // read the input file
    QTextStream in(&fn);

    forever {
        const QString line = in.readLine();

        if (line.isNull())
            break;

        else if (line.isEmpty())
            continue;

        else if (line.startsWith(QLatin1String("%%")))
            readingTextFilesToPatch = true;

        else if (readingTextFilesToPatch)
            textFilesToPatch.append(line);

        else
            filesToPatch.append(line);
    }

    foreach (QString fileName, filesToPatch) {
        QString prefix = QFile::decodeName(newQtPath);

        if (! prefix.endsWith(QLatin1Char('/')))
            prefix += QLatin1Char('/');

        fileName.prepend(prefix);

        QFile file(fileName);
        if (! file.open(QFile::ReadOnly)) {
            std::cerr << "qpatch: warning: file `" << qPrintable(fileName) << "' not found" << std::endl;
            continue;
        }

        const QByteArray source = file.readAll();
        file.close();

        int index = 0;

        if (! file.open(QFile::WriteOnly | QFile::Truncate)) {
            std::cerr << "qpatch: error: file `" << qPrintable(fileName) << "' not writable" << std::endl;
            continue;
        }
        std::cout << "patching file `" << qPrintable(fileName) << "'" << std::endl;

        forever {
            int start = source.indexOf(qtDirPath, index);
            if (start == -1)
                break;

            int endOfString = start;
            for (; endOfString < source.size(); ++endOfString) {
                if (! source.at(endOfString))
                    break;
            }

            ++endOfString; // include the '\0'

            if (index != start)
                file.write(source.constData() + index, start - index);

            int length = endOfString - start;
            QVector<char> s;

            for (const char *x = newQtPath.constData(); x != newQtPath.constEnd(); ++x)
                s.append(*x);

            const int qtDirPathLength = qtDirPath.size();

            for (const char *x = source.constData() + start + qtDirPathLength;
                    x != source.constData() + endOfString; ++x)
                s.append(*x);

            const int oldSize = s.size();

            for (int i = oldSize; i < length; ++i)
                s.append('\0');

#if 0
            std::cout << "replace string: " << source.mid(start, endOfString - start).constData()
                    << " with: " << s.constData() << std::endl;
#endif

            file.write(s.constData(), s.size());

            index = endOfString;
        }

        if (index == 0) {
            std::cerr << "qpatch: warning: file `" << qPrintable(fileName) << "' didn't contain string to patch" << std::endl;
        }

        if (index != source.size())
            file.write(source.constData() + index, source.size() - index);
    }

    foreach (QString fileName, textFilesToPatch) {
        QString prefix = QFile::decodeName(newQtPath);

        if (! prefix.endsWith(QLatin1Char('/')))
            prefix += QLatin1Char('/');

        fileName.prepend(prefix);

        QFile file(fileName);
        if (! file.open(QFile::ReadOnly)) {
            std::cerr << "qpatch: warning: file `" << qPrintable(fileName) << "' not found" << std::endl;
            continue;
        }

        QByteArray source = file.readAll();
        file.close();

        if (! file.open(QFile::WriteOnly | QFile::Truncate)) {
            std::cerr << "qpatch: error: file `" << qPrintable(fileName) << "' not writable" << std::endl;
            continue;
        }

        std::cout << "patching text file `" << qPrintable(fileName) << "'" << std::endl;

        source.replace(qtDirPath, newQtPath);
        file.write(source);
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 *   CrissCross
 *   A multi-purpose cross-platform library.
 *
 *   A product of Uplink Laboratories.
 *
 *   (c) 2006-2009 Steven Noonan.
 *   Licensed under the New BSD License.
 *
 */

#include <crisscross/universal_include.h>

#ifdef TARGET_OS_MACOSX
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif

#include <crisscross/compare.h>
#include <crisscross/profiler.h>
#include <crisscross/system.h>

#include <float.h>

namespace CrissCross
{
	namespace System
	{
		ProfiledElement::ProfiledElement(char const *_name, ProfiledElement *_parent, Profiler *_profiler)
		:	m_profiler(_profiler),
			m_currentTotalTime(0.0),
			m_currentNumCalls(0),
			m_lastTotalTime(0.0),
			m_lastNumCalls(0),
			m_longest(DBL_MIN),
			m_shortest(DBL_MAX),
			m_callStartTime(0.0),
			m_historyTotalTime(0.0),
			m_historyNumSeconds(0.0),
			m_historyNumCalls(0),
			m_parent(_parent),
			m_isExpanded(false)
		{
			m_name = strdup(_name);
		}

		ProfiledElement::~ProfiledElement()
		{
			free(m_name);
			m_children.EmptyAndDelete();
		}

		void ProfiledElement::Start()
		{
			m_callStartTime = CrissCross::System::GetHighResTime();
		}

		void ProfiledElement::End()
		{
			double const timeNow = CrissCross::System::GetHighResTime();

			m_currentNumCalls++;
			double const duration = timeNow - m_callStartTime;
			m_currentTotalTime += duration;

			if (duration > m_longest) {
				m_longest = duration;
			}

			if (duration < m_shortest) {
				m_shortest = duration;
			}
		}

		void ProfiledElement::Advance()
		{
			m_lastTotalTime = m_currentTotalTime;
			m_lastNumCalls = m_currentNumCalls;
			m_currentTotalTime = 0.0;
			m_currentNumCalls = 0;
			m_historyTotalTime += m_lastTotalTime;
			m_historyNumSeconds += 1.0;
			m_historyNumCalls += m_lastNumCalls;

			float thisMax = m_lastTotalTime;
			if( thisMax > m_profiler->m_maxFound ) m_profiler->m_maxFound = thisMax;

			for (int i = 0; i < m_children.Size(); ++i) {
				if (m_children.ValidIndex(i)) {
					m_children[i]->Advance();
				}
			}
		}

		void ProfiledElement::ResetHistory()
		{
			m_historyTotalTime = 0.0;
			m_historyNumSeconds = 0.0;
			m_historyNumCalls = 0;
			m_longest = DBL_MIN;
			m_shortest = DBL_MAX;

			for (unsigned int i = 0; i < m_children.Size(); ++i) {
				if (m_children.ValidIndex(i)) {
					m_children[i]->ResetHistory();
				}
			}
		}

		double ProfiledElement::GetMaxChildTime()
		{
			double rv = 0.0;

			short  first = m_children.StartOrderedWalk();
			if (first == -1) {
				return 0.0;
			}

			short  i = first;
			while (i != -1)
			{
				float            val = m_children[i]->m_historyTotalTime;

				if (val > rv) {
					rv = val;
				}

				i = m_children.GetNextOrderedIndex();
			}

			return rv / m_children[first]->m_historyNumSeconds;
		}

		Profiler::Profiler()
		:
			m_currentElement(NULL)
		{
			m_rootElement = new ProfiledElement("Root", NULL, this);
			m_rootElement->m_isExpanded = true;
			m_currentElement = m_rootElement;
			m_inRenderSection = false;
			m_endOfSecond = CrissCross::System::GetHighResTime() + 1.0f;
			SetMasterThread();
		}

		Profiler::~Profiler()
		{
			delete m_rootElement;
		}

		void Profiler::Advance()
		{
			double timeNow = CrissCross::System::GetHighResTime();
			if (timeNow > m_endOfSecond)
			{
				m_lengthOfLastSecond = timeNow - (m_endOfSecond - 1.0);
				m_endOfSecond = timeNow + 1.0;

				m_maxFound = 0.0f;
				m_rootElement->Advance();
			}

			if( m_lastFrameStart >= 0 )
			{
				double lastFrameTime = timeNow - m_lastFrameStart;
				m_frameTimes.insert_front( int( lastFrameTime * 1000 ) );
			}

			while( m_frameTimes.valid(200) )
				m_frameTimes.remove(200);

			m_lastFrameStart = timeNow;
		}

		void Profiler::ResetHistory()
		{
			m_rootElement->ResetHistory();
		}

		void Profiler::SetMasterThread()
		{
	#ifdef TARGET_OS_WINDOWS
			m_masterThread = GetCurrentThreadId();
	#else
			m_masterThread = pthread_self();
	#endif
		}

		bool Profiler::IsMasterThread()
		{
	#ifdef TARGET_OS_WINDOWS
			return m_masterThread == GetCurrentThreadId();
	#else
			return pthread_equal(m_masterThread, pthread_self());
	#endif
		}

		void Profiler::StartProfile(char const *_name)
		{
			if (!IsMasterThread()) return;

			ProfiledElement *pe = m_currentElement->m_children.GetData(_name);
			if (!pe) {
				pe = new ProfiledElement(_name, m_currentElement, this);
				m_currentElement->m_children.PutData(_name, pe);
			}

			CoreAssert(m_rootElement->m_isExpanded);

			bool wasExpanded = m_currentElement->m_isExpanded;

			if (m_currentElement->m_isExpanded) {
				if (m_doGlFinish && m_inRenderSection) {
					glFinish();
				}
				pe->Start();
			}

			m_currentElement = pe;

			m_currentElement->m_wasExpanded = wasExpanded;
		}

		void Profiler::EndProfile(char const *_name)
		{
			if (!IsMasterThread()) return;

			//CoreAssert(m_currentElement->m_wasExpanded == m_currentElement->m_parent->m_isExpanded);

			if (m_currentElement &&
				m_currentElement->m_parent )
			{
				if (m_currentElement->m_parent->m_isExpanded) {
					if (m_doGlFinish && m_inRenderSection) {
						glFinish();
					}

					CoreAssert(m_currentElement != m_rootElement);
					CoreAssert(CrissCross::Data::Compare(_name, (const char *)m_currentElement->m_name) == 0);

					m_currentElement->End();
				}

				CoreAssert(CrissCross::Data::Compare(m_currentElement->m_name, m_currentElement->m_parent->m_name) != 0);
				m_currentElement = m_currentElement->m_parent;
			}
		}
	}
}
<commit_msg>profiler: fix miscellaneous compilation warnings<commit_after>/*
 *   CrissCross
 *   A multi-purpose cross-platform library.
 *
 *   A product of Uplink Laboratories.
 *
 *   (c) 2006-2009 Steven Noonan.
 *   Licensed under the New BSD License.
 *
 */

#include <crisscross/universal_include.h>

#ifdef TARGET_OS_MACOSX
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif

#include <crisscross/compare.h>
#include <crisscross/profiler.h>
#include <crisscross/system.h>

#include <float.h>

namespace CrissCross
{
	namespace System
	{
		ProfiledElement::ProfiledElement(char const *_name, ProfiledElement *_parent, Profiler *_profiler)
		:	m_profiler(_profiler),
			m_currentTotalTime(0.0),
			m_currentNumCalls(0),
			m_lastTotalTime(0.0),
			m_lastNumCalls(0),
			m_historyTotalTime(0.0),
			m_historyNumSeconds(0.0),
			m_historyNumCalls(0),
			m_shortest(DBL_MAX),
			m_longest(DBL_MIN),
			m_callStartTime(0.0),
			m_parent(_parent),
			m_isExpanded(false)
		{
			m_name = strdup(_name);
		}

		ProfiledElement::~ProfiledElement()
		{
			free(m_name);
			m_children.EmptyAndDelete();
		}

		void ProfiledElement::Start()
		{
			m_callStartTime = CrissCross::System::GetHighResTime();
		}

		void ProfiledElement::End()
		{
			double const timeNow = CrissCross::System::GetHighResTime();

			m_currentNumCalls++;
			double const duration = timeNow - m_callStartTime;
			m_currentTotalTime += duration;

			if (duration > m_longest) {
				m_longest = duration;
			}

			if (duration < m_shortest) {
				m_shortest = duration;
			}
		}

		void ProfiledElement::Advance()
		{
			m_lastTotalTime = m_currentTotalTime;
			m_lastNumCalls = m_currentNumCalls;
			m_currentTotalTime = 0.0;
			m_currentNumCalls = 0;
			m_historyTotalTime += m_lastTotalTime;
			m_historyNumSeconds += 1.0;
			m_historyNumCalls += m_lastNumCalls;

			float thisMax = m_lastTotalTime;
			if( thisMax > m_profiler->m_maxFound ) m_profiler->m_maxFound = thisMax;

			for (size_t i = 0; i < m_children.Size(); ++i) {
				if (m_children.ValidIndex(i)) {
					m_children[i]->Advance();
				}
			}
		}

		void ProfiledElement::ResetHistory()
		{
			m_historyTotalTime = 0.0;
			m_historyNumSeconds = 0.0;
			m_historyNumCalls = 0;
			m_longest = DBL_MIN;
			m_shortest = DBL_MAX;

			for (unsigned int i = 0; i < m_children.Size(); ++i) {
				if (m_children.ValidIndex(i)) {
					m_children[i]->ResetHistory();
				}
			}
		}

		double ProfiledElement::GetMaxChildTime()
		{
			double rv = 0.0;

			short  first = m_children.StartOrderedWalk();
			if (first == -1) {
				return 0.0;
			}

			short  i = first;
			while (i != -1)
			{
				float            val = m_children[i]->m_historyTotalTime;

				if (val > rv) {
					rv = val;
				}

				i = m_children.GetNextOrderedIndex();
			}

			return rv / m_children[first]->m_historyNumSeconds;
		}

		Profiler::Profiler()
		:
			m_currentElement(NULL)
		{
			m_rootElement = new ProfiledElement("Root", NULL, this);
			m_rootElement->m_isExpanded = true;
			m_currentElement = m_rootElement;
			m_inRenderSection = false;
			m_endOfSecond = CrissCross::System::GetHighResTime() + 1.0f;
			SetMasterThread();
		}

		Profiler::~Profiler()
		{
			delete m_rootElement;
		}

		void Profiler::Advance()
		{
			double timeNow = CrissCross::System::GetHighResTime();
			if (timeNow > m_endOfSecond)
			{
				m_lengthOfLastSecond = timeNow - (m_endOfSecond - 1.0);
				m_endOfSecond = timeNow + 1.0;

				m_maxFound = 0.0f;
				m_rootElement->Advance();
			}

			if( m_lastFrameStart >= 0 )
			{
				double lastFrameTime = timeNow - m_lastFrameStart;
				m_frameTimes.insert_front( int( lastFrameTime * 1000 ) );
			}

			while( m_frameTimes.valid(200) )
				m_frameTimes.remove(200);

			m_lastFrameStart = timeNow;
		}

		void Profiler::ResetHistory()
		{
			m_rootElement->ResetHistory();
		}

		void Profiler::SetMasterThread()
		{
	#ifdef TARGET_OS_WINDOWS
			m_masterThread = GetCurrentThreadId();
	#else
			m_masterThread = pthread_self();
	#endif
		}

		bool Profiler::IsMasterThread()
		{
	#ifdef TARGET_OS_WINDOWS
			return m_masterThread == GetCurrentThreadId();
	#else
			return pthread_equal(m_masterThread, pthread_self());
	#endif
		}

		void Profiler::StartProfile(char const *_name)
		{
			if (!IsMasterThread()) return;

			ProfiledElement *pe = m_currentElement->m_children.GetData(_name);
			if (!pe) {
				pe = new ProfiledElement(_name, m_currentElement, this);
				m_currentElement->m_children.PutData(_name, pe);
			}

			CoreAssert(m_rootElement->m_isExpanded);

			bool wasExpanded = m_currentElement->m_isExpanded;

			if (m_currentElement->m_isExpanded) {
				if (m_doGlFinish && m_inRenderSection) {
					glFinish();
				}
				pe->Start();
			}

			m_currentElement = pe;

			m_currentElement->m_wasExpanded = wasExpanded;
		}

		void Profiler::EndProfile(char const *_name)
		{
			if (!IsMasterThread()) return;

			//CoreAssert(m_currentElement->m_wasExpanded == m_currentElement->m_parent->m_isExpanded);

			if (m_currentElement &&
				m_currentElement->m_parent )
			{
				if (m_currentElement->m_parent->m_isExpanded) {
					if (m_doGlFinish && m_inRenderSection) {
						glFinish();
					}

					CoreAssert(m_currentElement != m_rootElement);
					CoreAssert(CrissCross::Data::Compare(_name, (const char *)m_currentElement->m_name) == 0);

					m_currentElement->End();
				}

				CoreAssert(CrissCross::Data::Compare(m_currentElement->m_name, m_currentElement->m_parent->m_name) != 0);
				m_currentElement = m_currentElement->m_parent;
			}
		}
	}
}
<|endoftext|>


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

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "vaapiencoder_vp8.h"
#include "common/scopedlogger.h"
#include "common/common_def.h"
#include "vaapi/vaapicontext.h"
#include "vaapi/vaapidisplay.h"
#include "vaapicodedbuffer.h"
#include "vaapiencpicture.h"
#include "vaapiencoder_factory.h"
#include <algorithm>

namespace YamiMediaCodec{

//golden, alter, last
#define MAX_REFERECNE_FRAME 3
#define VP8_DEFAULT_QP     40

class VaapiEncPictureVP8 : public VaapiEncPicture
{
public:
    VaapiEncPictureVP8(const ContextPtr& context, const SurfacePtr& surface,
                       int64_t timeStamp)
        : VaapiEncPicture(context, surface, timeStamp)
    {
        return;
    }

    VAGenericID getCodedBufferID()
    {
        return m_codedBuffer->getID();
    }
};

VaapiEncoderVP8::VaapiEncoderVP8():
	m_frameCount(0),
	m_qIndex(VP8_DEFAULT_QP)
{
    m_videoParamCommon.profile = VAProfileVP8Version0_3;
    m_videoParamCommon.rcParams.minQP = 9;
    m_videoParamCommon.rcParams.maxQP = 127;
    m_videoParamCommon.rcParams.initQP = VP8_DEFAULT_QP;
}

VaapiEncoderVP8::~VaapiEncoderVP8()
{
}

YamiStatus VaapiEncoderVP8::getMaxOutSize(uint32_t* maxSize)
{
    FUNC_ENTER();
    *maxSize = m_maxCodedbufSize;
    return YAMI_SUCCESS;
}

void VaapiEncoderVP8::resetParams()
{
    //5 times compress ratio
    m_maxCodedbufSize = width() * height() * 3 / 2;
    //when the resolution of video is very small such as 96x96 and buffer plus the header of vp8,
    //the size of actual output buffer maybe be bigger the m_maxCodedbufSize.
    //So plusing 4096 avoids the situation.
    m_maxCodedbufSize += 0x1000;
}

YamiStatus VaapiEncoderVP8::start()
{
    FUNC_ENTER();
    resetParams();
    return VaapiEncoderBase::start();
}

void VaapiEncoderVP8::flush()
{
    FUNC_ENTER();
    m_frameCount = 0;
    m_reference.clear();
    VaapiEncoderBase::flush();
}

YamiStatus VaapiEncoderVP8::stop()
{
    flush();
    return VaapiEncoderBase::stop();
}

YamiStatus VaapiEncoderVP8::setParameters(VideoParamConfigType type, Yami_PTR videoEncParams)
{
    YamiStatus status = YAMI_SUCCESS;
    FUNC_ENTER();
    if (!videoEncParams)
        return YAMI_INVALID_PARAM;

    switch (type) {
    default:
        status = VaapiEncoderBase::setParameters(type, videoEncParams);
        break;
    }
    return status;
}

YamiStatus VaapiEncoderVP8::getParameters(VideoParamConfigType type, Yami_PTR videoEncParams)
{
    FUNC_ENTER();
    if (!videoEncParams)
        return YAMI_INVALID_PARAM;

    // TODO, update video resolution basing on hw requirement
    return VaapiEncoderBase::getParameters(type, videoEncParams);
}

YamiStatus VaapiEncoderVP8::doEncode(const SurfacePtr& surface, uint64_t timeStamp, bool forceKeyFrame)
{
    YamiStatus ret;
    if (!surface)
        return YAMI_INVALID_PARAM;

    PicturePtr picture(new VaapiEncPictureVP8(m_context, surface, timeStamp));

    m_frameCount %= keyFramePeriod();
    picture->m_type = (m_frameCount ? VAAPI_PICTURE_P : VAAPI_PICTURE_I);
    m_frameCount++;

    m_qIndex = (initQP() > minQP() && initQP() < maxQP()) ? initQP() : VP8_DEFAULT_QP;

    CodedBufferPtr codedBuffer = VaapiCodedBuffer::create(m_context, m_maxCodedbufSize);
    if (!codedBuffer)
        return YAMI_OUT_MEMORY;
    picture->m_codedBuffer = codedBuffer;
    codedBuffer->setFlag(ENCODE_BUFFERFLAG_ENDOFFRAME);
    INFO("picture->m_type: 0x%x\n", picture->m_type);
    if (picture->m_type == VAAPI_PICTURE_I) {
        codedBuffer->setFlag(ENCODE_BUFFERFLAG_SYNCFRAME);
    }
    ret = encodePicture(picture);
    if (ret != YAMI_SUCCESS) {
        return ret;
    }
    output(picture);
    return YAMI_SUCCESS;
}

bool VaapiEncoderVP8::fill(VAEncSequenceParameterBufferVP8* seqParam) const
{
    seqParam->frame_width = width();
    seqParam->frame_height = height();
    seqParam->bits_per_second = bitRate();
    seqParam->intra_period = intraPeriod();
    return true;
}

/* Fills in VA picture parameter buffer */
bool VaapiEncoderVP8::fill(VAEncPictureParameterBufferVP8* picParam, const PicturePtr& picture,
                           const SurfacePtr& surface) const
{
    picParam->reconstructed_frame = surface->getID();
    if (picture->m_type == VAAPI_PICTURE_P) {
        picParam->pic_flags.bits.frame_type = 1;
        ReferenceQueue::const_iterator it = m_reference.begin();
        picParam->ref_arf_frame = (*it++)->getID();
        picParam->ref_gf_frame = (*it++)->getID();
        picParam->ref_last_frame = (*it)->getID();
        picParam->pic_flags.bits.refresh_last = 1;
        picParam->pic_flags.bits.refresh_golden_frame = 0;
        picParam->pic_flags.bits.copy_buffer_to_golden = 1;
        picParam->pic_flags.bits.refresh_alternate_frame = 0;
        picParam->pic_flags.bits.copy_buffer_to_alternate = 2;
    } else {
        picParam->ref_last_frame = VA_INVALID_SURFACE;
        picParam->ref_gf_frame = VA_INVALID_SURFACE;
        picParam->ref_arf_frame = VA_INVALID_SURFACE;
    }

    picParam->coded_buf = picture->getCodedBufferID();

    picParam->pic_flags.bits.show_frame = 1;
    /*TODO: multi partition*/
    picParam->pic_flags.bits.num_token_partitions = 0;
    //REMOVE THIS
    picParam->pic_flags.bits.refresh_entropy_probs = 0;
    /*pic_flags end */
    for (int i = 0; i < 4; i++) {
        picParam->loop_filter_level[i] = 19;
    }

    picParam->clamp_qindex_low = minQP();
    picParam->clamp_qindex_high = maxQP();
    return TRUE;
}

bool VaapiEncoderVP8::fill(VAQMatrixBufferVP8* qMatrix) const
{
    size_t i;

    for (i = 0; i < N_ELEMENTS(qMatrix->quantization_index); i++) {
        qMatrix->quantization_index[i] = m_qIndex;
    }

    for (i = 0; i < N_ELEMENTS(qMatrix->quantization_index_delta); i++) {
        qMatrix->quantization_index_delta[i] = 0;
    }

    return true;
}

bool VaapiEncoderVP8::ensureSequence(const PicturePtr& picture)
{
    if (picture->m_type != VAAPI_PICTURE_I)
        return true;

    VAEncSequenceParameterBufferVP8* seqParam;
    if (!picture->editSequence(seqParam) || !fill(seqParam)) {
        ERROR("failed to create sequence parameter buffer (SPS)");
        return false;
    }
    return true;
}

bool VaapiEncoderVP8::ensurePicture (const PicturePtr& picture,
                                     const SurfacePtr& surface)
{
    VAEncPictureParameterBufferVP8 *picParam;

    if (!picture->editPicture(picParam) || !fill(picParam, picture, surface)) {
        ERROR("failed to create picture parameter buffer (PPS)");
        return false;
    }
    return true;
}

bool VaapiEncoderVP8::ensureQMatrix (const PicturePtr& picture)
{
    VAQMatrixBufferVP8 *qMatrix;

    if (!picture->editQMatrix(qMatrix) || !fill(qMatrix)) {
        ERROR("failed to create qMatrix");
        return false;
    }
    return true;
}

bool VaapiEncoderVP8::referenceListUpdate (const PicturePtr& pic, const SurfacePtr& recon)
{

    if (pic->m_type == VAAPI_PICTURE_I) {
        m_reference.clear();
        m_reference.insert(m_reference.end(), MAX_REFERECNE_FRAME, recon);
    } else {
        m_reference.pop_front();
        m_reference.push_back(recon);
    }

    return true;
}

YamiStatus VaapiEncoderVP8::encodePicture(const PicturePtr& picture)
{
    YamiStatus ret = YAMI_FAIL;
    SurfacePtr reconstruct = createSurface();
    if (!reconstruct)
        return ret;

    if (!ensureSequence (picture))
        return ret;

    if (!ensureMiscParams (picture.get()))
        return ret;

    if (!ensurePicture(picture, reconstruct))
        return ret;

    if (!ensureQMatrix(picture))
        return ret;

    if (!picture->encode())
        return ret;

    if (!referenceListUpdate (picture, reconstruct))
        return ret;

    return YAMI_SUCCESS;
}

const bool VaapiEncoderVP8::s_registered =
    VaapiEncoderFactory::register_<VaapiEncoderVP8>(YAMI_MIME_VP8);

}
<commit_msg>vp8enc: use VP8_HEADER_MAX_SIZE instead of magic number for m_maxCodedbufSize<commit_after>/*
 * Copyright (C) 2014 Intel Corporation. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "vaapiencoder_vp8.h"
#include "common/scopedlogger.h"
#include "common/common_def.h"
#include "vaapi/vaapicontext.h"
#include "vaapi/vaapidisplay.h"
#include "vaapicodedbuffer.h"
#include "vaapiencpicture.h"
#include "vaapiencoder_factory.h"
#include <algorithm>

namespace YamiMediaCodec{

//golden, alter, last
#define MAX_REFERECNE_FRAME 3
#define VP8_DEFAULT_QP     40

class VaapiEncPictureVP8 : public VaapiEncPicture
{
public:
    VaapiEncPictureVP8(const ContextPtr& context, const SurfacePtr& surface,
                       int64_t timeStamp)
        : VaapiEncPicture(context, surface, timeStamp)
    {
        return;
    }

    VAGenericID getCodedBufferID()
    {
        return m_codedBuffer->getID();
    }
};

VaapiEncoderVP8::VaapiEncoderVP8():
	m_frameCount(0),
	m_qIndex(VP8_DEFAULT_QP)
{
    m_videoParamCommon.profile = VAProfileVP8Version0_3;
    m_videoParamCommon.rcParams.minQP = 9;
    m_videoParamCommon.rcParams.maxQP = 127;
    m_videoParamCommon.rcParams.initQP = VP8_DEFAULT_QP;
}

VaapiEncoderVP8::~VaapiEncoderVP8()
{
}

YamiStatus VaapiEncoderVP8::getMaxOutSize(uint32_t* maxSize)
{
    FUNC_ENTER();
    *maxSize = m_maxCodedbufSize;
    return YAMI_SUCCESS;
}

//if the context is very complex and the quantization value is very small,
//the coded slice data will be very close to the limitation value width() * height() * 3 / 2.
//And the coded bitstream (slice_data + frame headers) will more than width() * height() * 3 / 2.
//so we add VP8_HEADER_MAX_SIZE to m_maxCodedbufSize to make sure it's not overflow.
#define VP8_HEADER_MAX_SIZE 0x4000

void VaapiEncoderVP8::resetParams()
{
    m_maxCodedbufSize = width() * height() * 3 / 2 + VP8_HEADER_MAX_SIZE;
}

YamiStatus VaapiEncoderVP8::start()
{
    FUNC_ENTER();
    resetParams();
    return VaapiEncoderBase::start();
}

void VaapiEncoderVP8::flush()
{
    FUNC_ENTER();
    m_frameCount = 0;
    m_reference.clear();
    VaapiEncoderBase::flush();
}

YamiStatus VaapiEncoderVP8::stop()
{
    flush();
    return VaapiEncoderBase::stop();
}

YamiStatus VaapiEncoderVP8::setParameters(VideoParamConfigType type, Yami_PTR videoEncParams)
{
    YamiStatus status = YAMI_SUCCESS;
    FUNC_ENTER();
    if (!videoEncParams)
        return YAMI_INVALID_PARAM;

    switch (type) {
    default:
        status = VaapiEncoderBase::setParameters(type, videoEncParams);
        break;
    }
    return status;
}

YamiStatus VaapiEncoderVP8::getParameters(VideoParamConfigType type, Yami_PTR videoEncParams)
{
    FUNC_ENTER();
    if (!videoEncParams)
        return YAMI_INVALID_PARAM;

    // TODO, update video resolution basing on hw requirement
    return VaapiEncoderBase::getParameters(type, videoEncParams);
}

YamiStatus VaapiEncoderVP8::doEncode(const SurfacePtr& surface, uint64_t timeStamp, bool forceKeyFrame)
{
    YamiStatus ret;
    if (!surface)
        return YAMI_INVALID_PARAM;

    PicturePtr picture(new VaapiEncPictureVP8(m_context, surface, timeStamp));

    m_frameCount %= keyFramePeriod();
    picture->m_type = (m_frameCount ? VAAPI_PICTURE_P : VAAPI_PICTURE_I);
    m_frameCount++;

    m_qIndex = (initQP() > minQP() && initQP() < maxQP()) ? initQP() : VP8_DEFAULT_QP;

    CodedBufferPtr codedBuffer = VaapiCodedBuffer::create(m_context, m_maxCodedbufSize);
    if (!codedBuffer)
        return YAMI_OUT_MEMORY;
    picture->m_codedBuffer = codedBuffer;
    codedBuffer->setFlag(ENCODE_BUFFERFLAG_ENDOFFRAME);
    INFO("picture->m_type: 0x%x\n", picture->m_type);
    if (picture->m_type == VAAPI_PICTURE_I) {
        codedBuffer->setFlag(ENCODE_BUFFERFLAG_SYNCFRAME);
    }
    ret = encodePicture(picture);
    if (ret != YAMI_SUCCESS) {
        return ret;
    }
    output(picture);
    return YAMI_SUCCESS;
}

bool VaapiEncoderVP8::fill(VAEncSequenceParameterBufferVP8* seqParam) const
{
    seqParam->frame_width = width();
    seqParam->frame_height = height();
    seqParam->bits_per_second = bitRate();
    seqParam->intra_period = intraPeriod();
    return true;
}

/* Fills in VA picture parameter buffer */
bool VaapiEncoderVP8::fill(VAEncPictureParameterBufferVP8* picParam, const PicturePtr& picture,
                           const SurfacePtr& surface) const
{
    picParam->reconstructed_frame = surface->getID();
    if (picture->m_type == VAAPI_PICTURE_P) {
        picParam->pic_flags.bits.frame_type = 1;
        ReferenceQueue::const_iterator it = m_reference.begin();
        picParam->ref_arf_frame = (*it++)->getID();
        picParam->ref_gf_frame = (*it++)->getID();
        picParam->ref_last_frame = (*it)->getID();
        picParam->pic_flags.bits.refresh_last = 1;
        picParam->pic_flags.bits.refresh_golden_frame = 0;
        picParam->pic_flags.bits.copy_buffer_to_golden = 1;
        picParam->pic_flags.bits.refresh_alternate_frame = 0;
        picParam->pic_flags.bits.copy_buffer_to_alternate = 2;
    } else {
        picParam->ref_last_frame = VA_INVALID_SURFACE;
        picParam->ref_gf_frame = VA_INVALID_SURFACE;
        picParam->ref_arf_frame = VA_INVALID_SURFACE;
    }

    picParam->coded_buf = picture->getCodedBufferID();

    picParam->pic_flags.bits.show_frame = 1;
    /*TODO: multi partition*/
    picParam->pic_flags.bits.num_token_partitions = 0;
    //REMOVE THIS
    picParam->pic_flags.bits.refresh_entropy_probs = 0;
    /*pic_flags end */
    for (int i = 0; i < 4; i++) {
        picParam->loop_filter_level[i] = 19;
    }

    picParam->clamp_qindex_low = minQP();
    picParam->clamp_qindex_high = maxQP();
    return TRUE;
}

bool VaapiEncoderVP8::fill(VAQMatrixBufferVP8* qMatrix) const
{
    size_t i;

    for (i = 0; i < N_ELEMENTS(qMatrix->quantization_index); i++) {
        qMatrix->quantization_index[i] = m_qIndex;
    }

    for (i = 0; i < N_ELEMENTS(qMatrix->quantization_index_delta); i++) {
        qMatrix->quantization_index_delta[i] = 0;
    }

    return true;
}

bool VaapiEncoderVP8::ensureSequence(const PicturePtr& picture)
{
    if (picture->m_type != VAAPI_PICTURE_I)
        return true;

    VAEncSequenceParameterBufferVP8* seqParam;
    if (!picture->editSequence(seqParam) || !fill(seqParam)) {
        ERROR("failed to create sequence parameter buffer (SPS)");
        return false;
    }
    return true;
}

bool VaapiEncoderVP8::ensurePicture (const PicturePtr& picture,
                                     const SurfacePtr& surface)
{
    VAEncPictureParameterBufferVP8 *picParam;

    if (!picture->editPicture(picParam) || !fill(picParam, picture, surface)) {
        ERROR("failed to create picture parameter buffer (PPS)");
        return false;
    }
    return true;
}

bool VaapiEncoderVP8::ensureQMatrix (const PicturePtr& picture)
{
    VAQMatrixBufferVP8 *qMatrix;

    if (!picture->editQMatrix(qMatrix) || !fill(qMatrix)) {
        ERROR("failed to create qMatrix");
        return false;
    }
    return true;
}

bool VaapiEncoderVP8::referenceListUpdate (const PicturePtr& pic, const SurfacePtr& recon)
{

    if (pic->m_type == VAAPI_PICTURE_I) {
        m_reference.clear();
        m_reference.insert(m_reference.end(), MAX_REFERECNE_FRAME, recon);
    } else {
        m_reference.pop_front();
        m_reference.push_back(recon);
    }

    return true;
}

YamiStatus VaapiEncoderVP8::encodePicture(const PicturePtr& picture)
{
    YamiStatus ret = YAMI_FAIL;
    SurfacePtr reconstruct = createSurface();
    if (!reconstruct)
        return ret;

    if (!ensureSequence (picture))
        return ret;

    if (!ensureMiscParams (picture.get()))
        return ret;

    if (!ensurePicture(picture, reconstruct))
        return ret;

    if (!ensureQMatrix(picture))
        return ret;

    if (!picture->encode())
        return ret;

    if (!referenceListUpdate (picture, reconstruct))
        return ret;

    return YAMI_SUCCESS;
}

const bool VaapiEncoderVP8::s_registered =
    VaapiEncoderFactory::register_<VaapiEncoderVP8>(YAMI_MIME_VP8);

}
<|endoftext|>