<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "cpprefactoringchanges.h"

#include <TranslationUnit.h>
#include <AST.h>
#include <cpptools/cppcodeformatter.h>
#include <cpptools/cppmodelmanager.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/tabsettings.h>

#include <QtGui/QTextBlock>

using namespace CPlusPlus;
using namespace CppTools;
using namespace Utils;

CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot)
    : m_snapshot(snapshot)
    , m_modelManager(Internal::CppModelManager::instance())
{
    Q_ASSERT(m_modelManager);
    m_workingCopy = m_modelManager->workingCopy();
}

const Snapshot &CppRefactoringChanges::snapshot() const
{
    return m_snapshot;
}

CppRefactoringFile CppRefactoringChanges::file(const QString &fileName)
{
    return CppRefactoringFile(fileName, this);
}

void CppRefactoringChanges::indentSelection(const QTextCursor &selection) const
{
    // ### shares code with CPPEditor::indent()
    QTextDocument *doc = selection.document();

    QTextBlock block = doc->findBlock(selection.selectionStart());
    const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();

    const TextEditor::TabSettings &tabSettings(TextEditor::TextEditorSettings::instance()->tabSettings());
    CppTools::QtStyleCodeFormatter codeFormatter(tabSettings);
    codeFormatter.updateStateUntil(block);

    do {
        int indent;
        int padding;
        codeFormatter.indentFor(block, &indent, &padding);
        tabSettings.indentLine(block, indent + padding, padding);
        codeFormatter.updateLineStateChange(block);
        block = block.next();
    } while (block.isValid() && block != end);
}

void CppRefactoringChanges::fileChanged(const QString &fileName)
{
    m_modelManager->updateSourceFiles(QStringList(fileName));
}

CppRefactoringFile::CppRefactoringFile()
{ }

CppRefactoringFile::CppRefactoringFile(const QString &fileName, CppRefactoringChanges *refactoringChanges)
    : RefactoringFile(fileName, refactoringChanges)
{ }

CppRefactoringFile::CppRefactoringFile(TextEditor::BaseTextEditor *editor, CPlusPlus::Document::Ptr document)
    : RefactoringFile()
    , m_cppDocument(document)
{
    m_fileName = document->fileName();
    m_editor = editor;
}

Document::Ptr CppRefactoringFile::cppDocument() const
{
    if (!m_cppDocument || !m_cppDocument->translationUnit() ||
            !m_cppDocument->translationUnit()->ast()) {
        const QString source = document()->toPlainText();
        const QString name = fileName();
        const Snapshot &snapshot = refactoringChanges()->snapshot();

        const QByteArray contents = snapshot.preprocessedCode(source, name);
        m_cppDocument = snapshot.documentFromSource(contents, name);
        m_cppDocument->check();
    }

    return m_cppDocument;
}

Scope *CppRefactoringFile::scopeAt(unsigned index) const
{
    unsigned line, column;
    cppDocument()->translationUnit()->getTokenStartPosition(index, &line, &column);
    return cppDocument()->scopeAt(line, column);
}

bool CppRefactoringFile::isCursorOn(unsigned tokenIndex) const
{
    QTextCursor tc = cursor();
    int cursorBegin = tc.selectionStart();

    int start = startOf(tokenIndex);
    int end = endOf(tokenIndex);

    if (cursorBegin >= start && cursorBegin <= end)
        return true;

    return false;
}

bool CppRefactoringFile::isCursorOn(const AST *ast) const
{
    QTextCursor tc = cursor();
    int cursorBegin = tc.selectionStart();

    int start = startOf(ast);
    int end = endOf(ast);

    if (cursorBegin >= start && cursorBegin <= end)
        return true;

    return false;
}

ChangeSet::Range CppRefactoringFile::range(unsigned tokenIndex) const
{
    const Token &token = tokenAt(tokenIndex);
    unsigned line, column;
    cppDocument()->translationUnit()->getPosition(token.begin(), &line, &column);
    const int start = document()->findBlockByNumber(line - 1).position() + column - 1;
    return ChangeSet::Range(start, start + token.length());
}

ChangeSet::Range CppRefactoringFile::range(AST *ast) const
{
    return ChangeSet::Range(startOf(ast), endOf(ast));
}

int CppRefactoringFile::startOf(unsigned index) const
{
    unsigned line, column;
    cppDocument()->translationUnit()->getPosition(tokenAt(index).begin(), &line, &column);
    return document()->findBlockByNumber(line - 1).position() + column - 1;
}

int CppRefactoringFile::startOf(const AST *ast) const
{
    return startOf(ast->firstToken());
}

int CppRefactoringFile::endOf(unsigned index) const
{
    unsigned line, column;
    cppDocument()->translationUnit()->getPosition(tokenAt(index).end(), &line, &column);
    return document()->findBlockByNumber(line - 1).position() + column - 1;
}

int CppRefactoringFile::endOf(const AST *ast) const
{
    unsigned end = ast->lastToken();
    Q_ASSERT(end > 0);
    return endOf(end - 1);
}

void CppRefactoringFile::startAndEndOf(unsigned index, int *start, int *end) const
{
    unsigned line, column;
    Token token(tokenAt(index));
    cppDocument()->translationUnit()->getPosition(token.begin(), &line, &column);
    *start = document()->findBlockByNumber(line - 1).position() + column - 1;
    *end = *start + token.length();
}

QString CppRefactoringFile::textOf(const AST *ast) const
{
    return textOf(startOf(ast), endOf(ast));
}

const Token &CppRefactoringFile::tokenAt(unsigned index) const
{
    return cppDocument()->translationUnit()->tokenAt(index);
}

CppRefactoringChanges *CppRefactoringFile::refactoringChanges() const
{
    return static_cast<CppRefactoringChanges *>(m_refactoringChanges);
}
<commit_msg>Fixed regression in tst_Codegen.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "cpprefactoringchanges.h"

#include <TranslationUnit.h>
#include <AST.h>
#include <cpptools/cppcodeformatter.h>
#include <cpptools/cppmodelmanager.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/tabsettings.h>

#include <QtGui/QTextBlock>

using namespace CPlusPlus;
using namespace CppTools;
using namespace Utils;

CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot)
    : m_snapshot(snapshot)
    , m_modelManager(Internal::CppModelManager::instance())
{
    Q_ASSERT(m_modelManager);
    m_workingCopy = m_modelManager->workingCopy();
}

const Snapshot &CppRefactoringChanges::snapshot() const
{
    return m_snapshot;
}

CppRefactoringFile CppRefactoringChanges::file(const QString &fileName)
{
    return CppRefactoringFile(fileName, this);
}

void CppRefactoringChanges::indentSelection(const QTextCursor &selection) const
{
    // ### shares code with CPPEditor::indent()
    QTextDocument *doc = selection.document();

    QTextBlock block = doc->findBlock(selection.selectionStart());
    const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();

    const TextEditor::TabSettings &tabSettings(TextEditor::TextEditorSettings::instance()->tabSettings());
    CppTools::QtStyleCodeFormatter codeFormatter(tabSettings);
    codeFormatter.updateStateUntil(block);

    do {
        int indent;
        int padding;
        codeFormatter.indentFor(block, &indent, &padding);
        tabSettings.indentLine(block, indent + padding, padding);
        codeFormatter.updateLineStateChange(block);
        block = block.next();
    } while (block.isValid() && block != end);
}

void CppRefactoringChanges::fileChanged(const QString &fileName)
{
    m_modelManager->updateSourceFiles(QStringList(fileName));
}

CppRefactoringFile::CppRefactoringFile()
{ }

CppRefactoringFile::CppRefactoringFile(const QString &fileName, CppRefactoringChanges *refactoringChanges)
    : RefactoringFile(fileName, refactoringChanges)
{
    const Snapshot &snapshot = refactoringChanges->snapshot();
    m_cppDocument = snapshot.document(fileName);
}

CppRefactoringFile::CppRefactoringFile(TextEditor::BaseTextEditor *editor, CPlusPlus::Document::Ptr document)
    : RefactoringFile()
    , m_cppDocument(document)
{
    m_fileName = document->fileName();
    m_editor = editor;
}

Document::Ptr CppRefactoringFile::cppDocument() const
{
    if (!m_cppDocument || !m_cppDocument->translationUnit() ||
            !m_cppDocument->translationUnit()->ast()) {
        const QString source = document()->toPlainText();
        const QString name = fileName();
        const Snapshot &snapshot = refactoringChanges()->snapshot();

        const QByteArray contents = snapshot.preprocessedCode(source, name);
        m_cppDocument = snapshot.documentFromSource(contents, name);
        m_cppDocument->check();
    }

    return m_cppDocument;
}

Scope *CppRefactoringFile::scopeAt(unsigned index) const
{
    unsigned line, column;
    cppDocument()->translationUnit()->getTokenStartPosition(index, &line, &column);
    return cppDocument()->scopeAt(line, column);
}

bool CppRefactoringFile::isCursorOn(unsigned tokenIndex) const
{
    QTextCursor tc = cursor();
    int cursorBegin = tc.selectionStart();

    int start = startOf(tokenIndex);
    int end = endOf(tokenIndex);

    if (cursorBegin >= start && cursorBegin <= end)
        return true;

    return false;
}

bool CppRefactoringFile::isCursorOn(const AST *ast) const
{
    QTextCursor tc = cursor();
    int cursorBegin = tc.selectionStart();

    int start = startOf(ast);
    int end = endOf(ast);

    if (cursorBegin >= start && cursorBegin <= end)
        return true;

    return false;
}

ChangeSet::Range CppRefactoringFile::range(unsigned tokenIndex) const
{
    const Token &token = tokenAt(tokenIndex);
    unsigned line, column;
    cppDocument()->translationUnit()->getPosition(token.begin(), &line, &column);
    const int start = document()->findBlockByNumber(line - 1).position() + column - 1;
    return ChangeSet::Range(start, start + token.length());
}

ChangeSet::Range CppRefactoringFile::range(AST *ast) const
{
    return ChangeSet::Range(startOf(ast), endOf(ast));
}

int CppRefactoringFile::startOf(unsigned index) const
{
    unsigned line, column;
    cppDocument()->translationUnit()->getPosition(tokenAt(index).begin(), &line, &column);
    return document()->findBlockByNumber(line - 1).position() + column - 1;
}

int CppRefactoringFile::startOf(const AST *ast) const
{
    return startOf(ast->firstToken());
}

int CppRefactoringFile::endOf(unsigned index) const
{
    unsigned line, column;
    cppDocument()->translationUnit()->getPosition(tokenAt(index).end(), &line, &column);
    return document()->findBlockByNumber(line - 1).position() + column - 1;
}

int CppRefactoringFile::endOf(const AST *ast) const
{
    unsigned end = ast->lastToken();
    Q_ASSERT(end > 0);
    return endOf(end - 1);
}

void CppRefactoringFile::startAndEndOf(unsigned index, int *start, int *end) const
{
    unsigned line, column;
    Token token(tokenAt(index));
    cppDocument()->translationUnit()->getPosition(token.begin(), &line, &column);
    *start = document()->findBlockByNumber(line - 1).position() + column - 1;
    *end = *start + token.length();
}

QString CppRefactoringFile::textOf(const AST *ast) const
{
    return textOf(startOf(ast), endOf(ast));
}

const Token &CppRefactoringFile::tokenAt(unsigned index) const
{
    return cppDocument()->translationUnit()->tokenAt(index);
}

CppRefactoringChanges *CppRefactoringFile::refactoringChanges() const
{
    return static_cast<CppRefactoringChanges *>(m_refactoringChanges);
}
<|endoftext|>


<commit_before>#include "qmljspreviewrunner.h"

#include <projectexplorer/environment.h>
#include <utils/synchronousprocess.h>

#include <QtGui/QMessageBox>
#include <QtGui/QApplication>

#include <QDebug>

namespace QmlJSEditor {
namespace Internal {

QmlJSPreviewRunner::QmlJSPreviewRunner(QObject *parent) :
    QObject(parent)
{
    // prepend creator/bin dir to search path (only useful for special creator-qml package)
    const QString searchPath = QCoreApplication::applicationDirPath()
                               + Utils::SynchronousProcess::pathSeparator()
                               + QString(qgetenv("PATH"));
    m_qmlViewerDefaultPath = Utils::SynchronousProcess::locateBinary(searchPath, QLatin1String("qml"));

    ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
    m_applicationLauncher.setEnvironment(environment.toStringList());
}

void QmlJSPreviewRunner::run(const QString &filename)
{
    QString errorMessage;
    if (!filename.isEmpty()) {
        m_applicationLauncher.start(ProjectExplorer::ApplicationLauncher::Gui, m_qmlViewerDefaultPath,
                                    QStringList() << filename);

    } else {
        errorMessage = "No file specified.";
    }

    if (!errorMessage.isEmpty())
        QMessageBox::warning(0, tr("Failed to preview Qt Quick file"),
                             tr("Could not preview Qt Quick (QML) file. Reason: \n%1").arg(errorMessage));
}

} // namespace Internal
} // namespace QmlJSEditor
<commit_msg>Fix QtQuick->Preview shortcut to start a qmlviewer<commit_after>#include "qmljspreviewrunner.h"

#include <projectexplorer/environment.h>
#include <utils/synchronousprocess.h>

#include <QtGui/QMessageBox>
#include <QtGui/QApplication>

#include <QDebug>

namespace QmlJSEditor {
namespace Internal {

QmlJSPreviewRunner::QmlJSPreviewRunner(QObject *parent) :
    QObject(parent)
{
    // prepend creator/bin dir to search path (only useful for special creator-qml package)
    const QString searchPath = QCoreApplication::applicationDirPath()
                               + Utils::SynchronousProcess::pathSeparator()
                               + QString(qgetenv("PATH"));
    m_qmlViewerDefaultPath = Utils::SynchronousProcess::locateBinary(searchPath, QLatin1String("qmlviewer"));

    ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment();
    m_applicationLauncher.setEnvironment(environment.toStringList());
}

void QmlJSPreviewRunner::run(const QString &filename)
{
    QString errorMessage;
    if (!filename.isEmpty()) {
        m_applicationLauncher.start(ProjectExplorer::ApplicationLauncher::Gui, m_qmlViewerDefaultPath,
                                    QStringList() << filename);

    } else {
        errorMessage = "No file specified.";
    }

    if (!errorMessage.isEmpty())
        QMessageBox::warning(0, tr("Failed to preview Qt Quick file"),
                             tr("Could not preview Qt Quick (QML) file. Reason: \n%1").arg(errorMessage));
}

} // namespace Internal
} // namespace QmlJSEditor
<|endoftext|>


<commit_before>/*
Copyright (c) 2012-2015 The SSDB Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include "../util/log.h"
#include "../util/strings.h"
#include "SSDB.h"

void welcome(){
	printf("ssdb-split - Split ssdb-server\n");
	printf("Copyright (c) 2012-2015 ssdb.io\n");
	printf("\n");
}

void usage(int argc, char **argv){
	printf("Usage:\n");
	printf("    %sr\n", argv[0]);
	printf("\n");
	printf("Options:\n");
	printf("    xx - \n");
}

ssdb::Client *src_client;
ssdb::Client *dst_client;
const int COPY_BATCH_SIZE = 2;

int copy_kv_data(const std::string &start_key, const std::string &end_key);

int main(int argc, char **argv){
	welcome();

	const char *src_ip = "127.0.0.1";
	int src_port = 8888;
	const char *dst_ip = "127.0.0.1";
	int dst_port = 8889;

	src_client = ssdb::Client::connect(src_ip, src_port);
	if(src_client == NULL){
		printf("fail to connect to src server!\n");
		return 0;
	}

	dst_client = ssdb::Client::connect(dst_ip, dst_port);
	if(dst_client == NULL){
		printf("fail to connect to dst server!\n");
		return 0;
	}

	std::string start_key;
	while(1){
		std::vector<std::string> keys;
		ssdb::Status s;
		s = src_client->keys(start_key, "", COPY_BATCH_SIZE, &keys);
		if(!s.ok()){
			log_error("response error: %s", s.code().c_str());
			break;
		}
		if(keys.empty()){
			break;
		}

		std::string end_key = keys[keys.size() - 1];

		// 1. lock key range in ("", end_key]
		log_debug("lock (\"\", \"%s\"] for read", str_escape(end_key).c_str());

		// 2. copy keys in range (start_key, end_key]
		log_debug("copy (\"%s\", \"%s\"] begin", str_escape(start_key).c_str(), str_escape(end_key).c_str());
		int ret = copy_kv_data(start_key, end_key);
		if(ret == -1){
			log_error("copy error!");
			break;
		}
		log_debug("copy (\"%s\", \"%s\"] end", str_escape(start_key).c_str(), str_escape(end_key).c_str());

		start_key = end_key;
	}

	delete src_client;
	delete dst_client;
	return 0;
}

int copy_kv_data(const std::string &start_key, const std::string &end_key){
	int ret = 0;
	ssdb::Status s;
	std::string iterate_key_start = start_key;
	while(1){
		std::vector<std::string> keys;
		ssdb::Status s;
		s = src_client->keys(iterate_key_start, end_key, COPY_BATCH_SIZE + 100, &keys);
		if(!s.ok()){
			log_error("response error: %s", s.code().c_str());
			return -1;
		}
		if(keys.empty()){
			break;
		}
		ret += (int)keys.size();

		// copy keys one by one, because scan() may exceed max_packet_size
		for(int i=0; i<keys.size(); i++){
			const std::string &key = keys[i];
			std::string val;
			s = src_client->get(key, &val);
			if(!s.ok()){
				log_error("read from src error: %s", s.code().c_str());
				return -1;
			}

			//log_debug("copy %s = %s", key.c_str(), val.c_str());

			s = dst_client->set(key, val);
			if(!s.ok()){
				log_error("write to dst error: %s", s.code().c_str());
				return -1;
			}
		}

		iterate_key_start = keys[keys.size() - 1];
		if(iterate_key_start == end_key){
			break;
		}
	}
	return ret;
}
<commit_msg>update<commit_after>/*
Copyright (c) 2012-2015 The SSDB Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include "../util/log.h"
#include "../util/strings.h"
#include "SSDB.h"

void welcome(){
	printf("ssdb-split - Split ssdb-server\n");
	printf("Copyright (c) 2012-2015 ssdb.io\n");
	printf("\n");
}

void usage(int argc, char **argv){
	printf("Usage:\n");
	printf("    %sr\n", argv[0]);
	printf("\n");
	printf("Options:\n");
	printf("    xx - \n");
}

ssdb::Client *src_client;
ssdb::Client *dst_client;
const int COPY_BATCH_SIZE = 2;

int copy_kv_data(const std::string &start_key, const std::string &end_key);

int main(int argc, char **argv){
	welcome();

	const char *src_ip = "127.0.0.1";
	int src_port = 8888;
	const char *dst_ip = "127.0.0.1";
	int dst_port = 8889;

	src_client = ssdb::Client::connect(src_ip, src_port);
	if(src_client == NULL){
		printf("fail to connect to src server!\n");
		return 0;
	}

	dst_client = ssdb::Client::connect(dst_ip, dst_port);
	if(dst_client == NULL){
		printf("fail to connect to dst server!\n");
		return 0;
	}

	std::string start_key;
	std::string end_key;
	while(1){
		std::vector<std::string> keys;
		ssdb::Status s;
		start_key = end_key;
		s = src_client->keys(start_key, "", COPY_BATCH_SIZE, &keys);
		if(!s.ok()){
			log_error("response error: %s", s.code().c_str());
			break;
		}
		if(keys.empty()){
			break;
		}
		end_key = keys[keys.size() - 1];

		// 0. CLUSTER: log source shrink range
		log_debug("lock (\"\", \"%s\"] for read", str_escape(end_key).c_str());

		// 1. SOURCE: lock key range ("", end_key] for read

		// 2. CLUSTER: copy keys in range (start_key, end_key]
		log_debug("copy (\"%s\", \"%s\"] begin", str_escape(start_key).c_str(), str_escape(end_key).c_str());
		int ret = copy_kv_data(start_key, end_key);
		if(ret == -1){
			log_error("copy error!");
			break;
		}
		log_debug("copy (\"%s\", \"%s\"] end", str_escape(start_key).c_str(), str_escape(end_key).c_str());

		// 3. CLUSTER: log destination expand range

		// 4. DESTINATION: expand range

		// 5. SOURCE: delete depricated keys
	}

	// end. CLUSTER: end splitting

	delete src_client;
	delete dst_client;
	return 0;
}

int copy_kv_data(const std::string &start_key, const std::string &end_key){
	int ret = 0;
	ssdb::Status s;
	std::string iterate_key_start = start_key;
	while(1){
		std::vector<std::string> keys;
		ssdb::Status s;
		s = src_client->keys(iterate_key_start, end_key, COPY_BATCH_SIZE + 100, &keys);
		if(!s.ok()){
			log_error("response error: %s", s.code().c_str());
			return -1;
		}
		if(keys.empty()){
			break;
		}
		ret += (int)keys.size();

		// copy keys one by one, because scan() may exceed max_packet_size
		for(int i=0; i<keys.size(); i++){
			const std::string &key = keys[i];
			std::string val;
			s = src_client->get(key, &val);
			if(!s.ok()){
				log_error("read from src error: %s", s.code().c_str());
				return -1;
			}

			//log_debug("copy %s = %s", key.c_str(), val.c_str());

			s = dst_client->set(key, val);
			if(!s.ok()){
				log_error("write to dst error: %s", s.code().c_str());
				return -1;
			}
		}

		iterate_key_start = keys[keys.size() - 1];
		if(iterate_key_start == end_key){
			break;
		}
	}
	return ret;
}
<|endoftext|>


<commit_before>#ifndef NANOCV_THREAD_LOOP_H
#define NANOCV_THREAD_LOOP_H

#include "thread_pool.h"

namespace ncv
{
        ///
        /// \brief split a loop computation of the given size using a thread pool
        ///
        template
        <
                typename tsize,
                class toperator
        >
        void thread_loopi(tsize N, toperator op, thread_pool_t& pool)
        {
                const tsize n_tasks = static_cast<tsize>(pool.n_workers());
                const tsize task_size = N / n_tasks + 1;

                for (tsize t = 0; t < n_tasks; t ++)
                {
                        pool.enqueue([=,&op]()
                        {
                                for (tsize i = t * task_size, iend = std::min(i + task_size, N); i < iend; i ++)
                                {
                                        op(i);
                                }
                        });
                }

                pool.wait();
        }

        ///
        /// \brief split a loop computation of the given size using a thread pool
        ///
        template
        <
                typename tsize,
                class toperator
        >
        void thread_loopit(tsize N, toperator op, thread_pool_t& pool)
        {
                const tsize n_tasks = static_cast<tsize>(pool.n_workers());
                const tsize task_size = N / n_tasks + 1;

                for (tsize t = 0; t < n_tasks; t ++)
                {
                        pool.enqueue([=,&op]()
                        {
                                for (tsize i = t * task_size, iend = std::min(i + task_size, N); i < iend; i ++)
                                {
                                        op(i, t);
                                }
                        });
                }

                pool.wait();
        }

        ///
        /// \brief split a loop computation of the given size using multiple threads
        ///
        template
        <
                typename tsize,
                class toperator
        >
        void thread_loopi(tsize N, toperator op, tsize nthreads = tsize(0))
        {
                thread_pool_t pool(nthreads);
                thread_loopi(N, op, pool);
        }

        ///
        /// \brief split a loop computation of the given size using multiple threads
        ///
        template
        <
                typename tsize,
                class toperator
        >
        void thread_loopit(tsize N, toperator op, tsize nthreads = tsize(0))
        {
                thread_pool_t pool(nthreads);
                thread_loopit(N, op, pool);
        }
}

#endif // NANOCV_THREAD_LOOP_H

<commit_msg>comments<commit_after>#ifndef NANOCV_THREAD_LOOP_H
#define NANOCV_THREAD_LOOP_H

#include "thread_pool.h"

namespace ncv
{
        ///
        /// \brief split a loop computation of the given size using a thread pool
        /// NB: the operator receives the index of the sample to process: op(i)
        ///
        template
        <
                typename tsize,
                class toperator
        >
        void thread_loopi(tsize N, toperator op, thread_pool_t& pool)
        {
                const tsize n_tasks = static_cast<tsize>(pool.n_workers());
                const tsize task_size = N / n_tasks + 1;

                for (tsize t = 0; t < n_tasks; t ++)
                {
                        pool.enqueue([=,&op]()
                        {
                                for (tsize i = t * task_size, iend = std::min(i + task_size, N); i < iend; i ++)
                                {
                                        op(i);
                                }
                        });
                }

                pool.wait();
        }

        ///
        /// \brief split a loop computation of the given size using a thread pool
        /// NB: the operator receives the index of the sample to process and the assigned thread index: op(i, t)
        ///
        template
        <
                typename tsize,
                class toperator
        >
        void thread_loopit(tsize N, toperator op, thread_pool_t& pool)
        {
                const tsize n_tasks = static_cast<tsize>(pool.n_workers());
                const tsize task_size = N / n_tasks + 1;

                for (tsize t = 0; t < n_tasks; t ++)
                {
                        pool.enqueue([=,&op]()
                        {
                                for (tsize i = t * task_size, iend = std::min(i + task_size, N); i < iend; i ++)
                                {
                                        op(i, t);
                                }
                        });
                }

                pool.wait();
        }

        ///
        /// \brief split a loop computation of the given size using multiple threads
        ///
        template
        <
                typename tsize,
                class toperator
        >
        void thread_loopi(tsize N, toperator op, tsize nthreads = tsize(0))
        {
                thread_pool_t pool(nthreads);
                thread_loopi(N, op, pool);
        }

        ///
        /// \brief split a loop computation of the given size using multiple threads
        ///
        template
        <
                typename tsize,
                class toperator
        >
        void thread_loopit(tsize N, toperator op, tsize nthreads = tsize(0))
        {
                thread_pool_t pool(nthreads);
                thread_loopit(N, op, pool);
        }
}

#endif // NANOCV_THREAD_LOOP_H

<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <vector>

#include <Support/CmdLine.h>
#include <Support/CmdLineUtil.h>

#include "input/keyboard.h"
#include "input/mouse.h"
#include "manip/camera_manipulator.h"
#include "viewer_base.h"

using namespace support;
using namespace visionaray;

using manipulators      = std::vector<std::shared_ptr<camera_manipulator>>;
using cmdline_options   = std::vector<std::shared_ptr<cl::OptionBase>>;

struct viewer_base::impl
{
    manipulators    manips;
    cmdline_options options;
    cl::CmdLine     cmd;

    bool            full_screen     = false;
    int             width           = 512;
    int             height          = 512;
    std::string     window_title    = "";
    vec3            bgcolor         = { 0.1f, 0.4f, 1.0f };

    impl(int width, int height, std::string window_title);

    void init(int argc, char** argv);

    void parse_cmd_line(int argc, char** argv);
};

viewer_base::impl::impl(int width, int height, std::string window_title)
    : width(width)
    , height(height)
    , window_title(window_title)
{
    // add default options (-fullscreen, -width, -height, -bgcolor)

    options.emplace_back( cl::makeOption<bool&>(
        cl::Parser<>(),
        "fullscreen",
        cl::Desc("Full screen window"),
        cl::ArgDisallowed,
        cl::init(viewer_base::impl::full_screen)
        ) );

    options.emplace_back( cl::makeOption<int&>(
        cl::Parser<>(),
        "width",
        cl::Desc("Window width"),
        cl::ArgRequired,
        cl::init(viewer_base::impl::width)
        ) );

    options.emplace_back( cl::makeOption<int&>(
        cl::Parser<>(),
        "height",
        cl::Desc("Window height"),
        cl::ArgRequired,
        cl::init(viewer_base::impl::height)
        ) );

    options.emplace_back( cl::makeOption<vec3&, cl::ScalarType>(
        [&](StringRef name, StringRef /*arg*/, vec3& value)
        {
            cl::Parser<>()(name + "-r", cmd.bump(), value.x);
            cl::Parser<>()(name + "-g", cmd.bump(), value.y);
            cl::Parser<>()(name + "-b", cmd.bump(), value.z);
        },
        "bgcolor",
        cl::Desc("Background color"),
        cl::ArgDisallowed,
        cl::init(viewer_base::impl::bgcolor)
        ) );
}

void viewer_base::impl::init(int argc, char** argv)
{
    parse_cmd_line(argc, argv);
}

//-------------------------------------------------------------------------------------------------
// Parse default command line options
//

void viewer_base::impl::parse_cmd_line(int argc, char** argv)
{
    for (auto& opt : options)
    {
        cmd.add(*opt);
    }

    auto args = std::vector<std::string>(argv + 1, argv + argc);
    cl::expandWildcards(args);
    cl::expandResponseFiles(args, cl::TokenizeUnix());

    cmd.parse(args);
}

viewer_base::viewer_base(
        int width,
        int height,
        std::string window_title
        )
    : impl_(new impl(width, height, window_title))
{
}

viewer_base::~viewer_base()
{
}

void viewer_base::init(int argc, char** argv)
{
    impl_->init(argc, argv);
}

void viewer_base::add_manipulator( std::shared_ptr<camera_manipulator> manip )
{
    impl_->manips.push_back(manip);
}

void viewer_base::add_cmdline_option( std::shared_ptr<cl::OptionBase> option )
{
    impl_->options.emplace_back(option);
}

std::string viewer_base::window_title() const
{
    return impl_->window_title;
}

bool viewer_base::full_screen() const
{
    return impl_->full_screen;
}

int viewer_base::width() const
{
    return impl_->width;
}

int viewer_base::height() const
{
    return impl_->height;
}

vec3 viewer_base::background_color() const
{
    return impl_->bgcolor;
}

void viewer_base::event_loop()
{
}

void viewer_base::resize(int width, int height)
{
    impl_->width = width;
    impl_->height = height;
}

void viewer_base::toggle_full_screen()
{
    impl_->full_screen = !impl_->full_screen;
}

//-------------------------------------------------------------------------------------------------
// Event handlers
//

void viewer_base::on_display()
{
}

void viewer_base::on_idle()
{
}

void viewer_base::on_key_press(visionaray::key_event const& event)
{
    if (event.key() == keyboard::F5)
    {
        toggle_full_screen();
    }

    if (event.key() == keyboard::Escape && impl_->full_screen)
    {
        toggle_full_screen();
    }

    for (auto& manip : impl_->manips)
    {
        manip->handle_key_press(event);
    }
}

void viewer_base::on_key_release(visionaray::key_event const& event)
{
    for (auto& manip : impl_->manips)
    {
        manip->handle_key_release(event);
    }
}

void viewer_base::on_mouse_move(visionaray::mouse_event const& event)
{
    for (auto& manip : impl_->manips)
    {
        manip->handle_mouse_move(event);
    }
}

void viewer_base::on_mouse_down(visionaray::mouse_event const& event)
{
    for (auto& manip : impl_->manips)
    {
        manip->handle_mouse_down(event);
    }
}

void viewer_base::on_mouse_up(visionaray::mouse_event const& event)
{
    for (auto& manip : impl_->manips)
    {
        manip->handle_mouse_up(event);
    }
}

void viewer_base::on_resize(int w, int h)
{
    glViewport(0, 0, w, h);
}
<commit_msg>Update width and height when viewer gets resized<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <vector>

#include <Support/CmdLine.h>
#include <Support/CmdLineUtil.h>

#include "input/keyboard.h"
#include "input/mouse.h"
#include "manip/camera_manipulator.h"
#include "viewer_base.h"

using namespace support;
using namespace visionaray;

using manipulators      = std::vector<std::shared_ptr<camera_manipulator>>;
using cmdline_options   = std::vector<std::shared_ptr<cl::OptionBase>>;

struct viewer_base::impl
{
    manipulators    manips;
    cmdline_options options;
    cl::CmdLine     cmd;

    bool            full_screen     = false;
    int             width           = 512;
    int             height          = 512;
    std::string     window_title    = "";
    vec3            bgcolor         = { 0.1f, 0.4f, 1.0f };

    impl(int width, int height, std::string window_title);

    void init(int argc, char** argv);

    void parse_cmd_line(int argc, char** argv);
};

viewer_base::impl::impl(int width, int height, std::string window_title)
    : width(width)
    , height(height)
    , window_title(window_title)
{
    // add default options (-fullscreen, -width, -height, -bgcolor)

    options.emplace_back( cl::makeOption<bool&>(
        cl::Parser<>(),
        "fullscreen",
        cl::Desc("Full screen window"),
        cl::ArgDisallowed,
        cl::init(viewer_base::impl::full_screen)
        ) );

    options.emplace_back( cl::makeOption<int&>(
        cl::Parser<>(),
        "width",
        cl::Desc("Window width"),
        cl::ArgRequired,
        cl::init(viewer_base::impl::width)
        ) );

    options.emplace_back( cl::makeOption<int&>(
        cl::Parser<>(),
        "height",
        cl::Desc("Window height"),
        cl::ArgRequired,
        cl::init(viewer_base::impl::height)
        ) );

    options.emplace_back( cl::makeOption<vec3&, cl::ScalarType>(
        [&](StringRef name, StringRef /*arg*/, vec3& value)
        {
            cl::Parser<>()(name + "-r", cmd.bump(), value.x);
            cl::Parser<>()(name + "-g", cmd.bump(), value.y);
            cl::Parser<>()(name + "-b", cmd.bump(), value.z);
        },
        "bgcolor",
        cl::Desc("Background color"),
        cl::ArgDisallowed,
        cl::init(viewer_base::impl::bgcolor)
        ) );
}

void viewer_base::impl::init(int argc, char** argv)
{
    parse_cmd_line(argc, argv);
}

//-------------------------------------------------------------------------------------------------
// Parse default command line options
//

void viewer_base::impl::parse_cmd_line(int argc, char** argv)
{
    for (auto& opt : options)
    {
        cmd.add(*opt);
    }

    auto args = std::vector<std::string>(argv + 1, argv + argc);
    cl::expandWildcards(args);
    cl::expandResponseFiles(args, cl::TokenizeUnix());

    cmd.parse(args);
}

viewer_base::viewer_base(
        int width,
        int height,
        std::string window_title
        )
    : impl_(new impl(width, height, window_title))
{
}

viewer_base::~viewer_base()
{
}

void viewer_base::init(int argc, char** argv)
{
    impl_->init(argc, argv);
}

void viewer_base::add_manipulator( std::shared_ptr<camera_manipulator> manip )
{
    impl_->manips.push_back(manip);
}

void viewer_base::add_cmdline_option( std::shared_ptr<cl::OptionBase> option )
{
    impl_->options.emplace_back(option);
}

std::string viewer_base::window_title() const
{
    return impl_->window_title;
}

bool viewer_base::full_screen() const
{
    return impl_->full_screen;
}

int viewer_base::width() const
{
    return impl_->width;
}

int viewer_base::height() const
{
    return impl_->height;
}

vec3 viewer_base::background_color() const
{
    return impl_->bgcolor;
}

void viewer_base::event_loop()
{
}

void viewer_base::resize(int width, int height)
{
    impl_->width = width;
    impl_->height = height;
}

void viewer_base::toggle_full_screen()
{
    impl_->full_screen = !impl_->full_screen;
}

//-------------------------------------------------------------------------------------------------
// Event handlers
//

void viewer_base::on_display()
{
}

void viewer_base::on_idle()
{
}

void viewer_base::on_key_press(visionaray::key_event const& event)
{
    if (event.key() == keyboard::F5)
    {
        toggle_full_screen();
    }

    if (event.key() == keyboard::Escape && impl_->full_screen)
    {
        toggle_full_screen();
    }

    for (auto& manip : impl_->manips)
    {
        manip->handle_key_press(event);
    }
}

void viewer_base::on_key_release(visionaray::key_event const& event)
{
    for (auto& manip : impl_->manips)
    {
        manip->handle_key_release(event);
    }
}

void viewer_base::on_mouse_move(visionaray::mouse_event const& event)
{
    for (auto& manip : impl_->manips)
    {
        manip->handle_mouse_move(event);
    }
}

void viewer_base::on_mouse_down(visionaray::mouse_event const& event)
{
    for (auto& manip : impl_->manips)
    {
        manip->handle_mouse_down(event);
    }
}

void viewer_base::on_mouse_up(visionaray::mouse_event const& event)
{
    for (auto& manip : impl_->manips)
    {
        manip->handle_mouse_up(event);
    }
}

void viewer_base::on_resize(int w, int h)
{
    impl_->width = w;
    impl_->height = h;

    glViewport(0, 0, w, h);
}
<|endoftext|>


<commit_before>#include "components/builder.hpp"
#include "utils/math.hpp"
#include "utils/string.hpp"

POLYBAR_NS

void builder::set_lazy(bool mode) {
  m_lazy = mode;
}

string builder::flush() {
  if (m_lazy) {
    while (m_counters[syntaxtag::A] > 0) cmd_close(true);
    while (m_counters[syntaxtag::B] > 0) background_close(true);
    while (m_counters[syntaxtag::F] > 0) color_close(true);
    while (m_counters[syntaxtag::T] > 0) font_close(true);
    while (m_counters[syntaxtag::U] > 0) line_color_close(true);
    while (m_counters[syntaxtag::u] > 0) underline_close(true);
    while (m_counters[syntaxtag::o] > 0) overline_close(true);
  }

  string output = m_output.data();

  // reset values
  m_output.clear();
  for (auto& counter : m_counters) counter.second = 0;
  for (auto& value : m_colors) value.second = "";
  m_fontindex = 1;

  return string_util::replace_all(output, string{BUILDER_SPACE_TOKEN}, " ");
}

void builder::append(string text) {
  string str(text);
  auto len = str.length();
  if (len > 2 && str[0] == '"' && str[len - 1] == '"')
    m_output += str.substr(1, len - 2);
  else
    m_output += str;
}

void builder::node(string str, bool add_space) {
  string::size_type n, m;
  string s(str);

  while (true) {
    if (s.empty()) {
      break;

    } else if ((n = s.find("%{F-}")) == 0) {
      color_close(!m_lazy);
      s.erase(0, 5);

    } else if ((n = s.find("%{F#")) == 0 && (m = s.find("}")) != string::npos) {
      if (m - n - 4 == 2)
        color_alpha(s.substr(n + 3, m - 3));
      else
        color(s.substr(n + 3, m - 3));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{B-}")) == 0) {
      background_close(!m_lazy);
      s.erase(0, 5);

    } else if ((n = s.find("%{B#")) == 0 && (m = s.find("}")) != string::npos) {
      background(s.substr(n + 3, m - 3));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{T-}")) == 0) {
      font_close(!m_lazy);
      s.erase(0, 5);

    } else if ((n = s.find("%{T")) == 0 && (m = s.find("}")) != string::npos) {
      font(std::atoi(s.substr(n + 3, m - 3).c_str()));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{U-}")) == 0) {
      line_color_close(!m_lazy);
      s.erase(0, 5);

    } else if ((n = s.find("%{U#")) == 0 && (m = s.find("}")) != string::npos) {
      line_color(s.substr(n + 3, m - 3));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{+u}")) == 0) {
      underline();
      s.erase(0, 5);

    } else if ((n = s.find("%{+o}")) == 0) {
      overline();
      s.erase(0, 5);

    } else if ((n = s.find("%{-u}")) == 0) {
      underline_close(true);
      s.erase(0, 5);

    } else if ((n = s.find("%{-o}")) == 0) {
      overline_close(true);
      s.erase(0, 5);

    } else if ((n = s.find("%{A}")) == 0) {
      cmd_close(true);
      s.erase(0, 4);

    } else if ((n = s.find("%{")) == 0 && (m = s.find("}")) != string::npos) {
      append(s.substr(n, m + 1));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{")) > 0) {
      append(s.substr(0, n));
      s.erase(0, n);

    } else
      break;
  }

  if (!s.empty())
    append(s);
  if (add_space)
    space();
}

void builder::node(string str, int font_index, bool add_space) {
  font(font_index);
  node(str, add_space);
  font_close();
}

// void builder::node(progressbar_t bar, float perc, bool add_space) {
//   if (!bar)
//     return;
//   node(bar->get_output(math_util::cap<float>(0, 100, perc)), add_space);
// }

void builder::node(label_t label, bool add_space) {
  if (!label || !*label)
    return;

  auto text = label->get();

  if (label->m_maxlen > 0 && text.length() > label->m_maxlen) {
    text = text.substr(0, label->m_maxlen) + "...";
  }

  if ((label->m_overline.empty() && m_counters[syntaxtag::o] > 0) ||
      (m_counters[syntaxtag::o] > 0 && label->m_margin > 0))
    overline_close(true);
  if ((label->m_underline.empty() && m_counters[syntaxtag::u] > 0) ||
      (m_counters[syntaxtag::u] > 0 && label->m_margin > 0))
    underline_close(true);

  if (label->m_margin > 0)
    space(label->m_margin);

  if (!label->m_overline.empty())
    overline(label->m_overline);
  if (!label->m_underline.empty())
    underline(label->m_underline);

  background(label->m_background);
  color(label->m_foreground);

  if (label->m_padding > 0)
    space(label->m_padding);

  node(text, label->m_font, add_space);

  if (label->m_padding > 0)
    space(label->m_padding);

  color_close(m_lazy && label->m_margin > 0);
  background_close(m_lazy && label->m_margin > 0);

  if (!label->m_underline.empty() || (label->m_margin > 0 && m_counters[syntaxtag::u] > 0))
    underline_close(m_lazy && label->m_margin > 0);
  if (!label->m_overline.empty() || (label->m_margin > 0 && m_counters[syntaxtag::o] > 0))
    overline_close(m_lazy && label->m_margin > 0);

  if (label->m_margin > 0)
    space(label->m_margin);
}

// void builder::node(ramp_t ramp, float perc, bool add_space) {
//   if (!ramp)
//     return;
//   node(ramp->get_by_percentage(math_util::cap<float>(0, 100, perc)), add_space);
// }

// void builder::node(animation_t animation, bool add_space) {
//   if (!animation)
//     return;
//   node(animation->get(), add_space);
// }

void builder::offset(int pixels) {
  if (pixels != 0)
    tag_open('O', std::to_string(pixels));
}

void builder::space(int width) {
  if (width == DEFAULT_SPACING)
    width = m_bar.spacing;
  if (width <= 0)
    return;
  string str(width, ' ');
  append(str);
}

void builder::remove_trailing_space(int width) {
  if (width == DEFAULT_SPACING)
    width = m_bar.spacing;
  if (width <= 0)
    return;
  string::size_type spacing = width;
  string str(spacing, ' ');
  if (m_output.length() >= spacing && m_output.substr(m_output.length() - spacing) == str)
    m_output = m_output.substr(0, m_output.length() - spacing);
}

void builder::invert() {
  tag_open('R', "");
}

void builder::font(int index) {
  if (index <= 0 && m_counters[syntaxtag::T] > 0)
    font_close(true);
  if (index <= 0 || index == m_fontindex)
    return;
  if (m_lazy && m_counters[syntaxtag::T] > 0)
    font_close(true);

  m_counters[syntaxtag::T]++;
  m_fontindex = index;
  tag_open('T', std::to_string(index));
}

void builder::font_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::T] <= 0)
    return;

  m_counters[syntaxtag::T]--;
  m_fontindex = 1;
  tag_close('T');
}

void builder::background(string color) {
  if (color.length() == 2 || (color.find("#") == 0 && color.length() == 3)) {
    color = "#" + color.substr(color.length() - 2);
    auto bg = m_bar.background.source();
    color += bg.substr(bg.length() - (bg.length() < 6 ? 3 : 6));
  } else if (color.length() >= 7 && color == "#" + string(color.length() - 1, color[1])) {
    color = color.substr(0, 4);
  }

  if (color.empty() && m_counters[syntaxtag::B] > 0)
    background_close(true);
  if (color.empty() || color == m_colors[syntaxtag::B])
    return;
  if (m_lazy && m_counters[syntaxtag::B] > 0)
    background_close(true);

  m_counters[syntaxtag::B]++;
  m_colors[syntaxtag::B] = color;
  tag_open('B', color);
}

void builder::background_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::B] <= 0)
    return;

  m_counters[syntaxtag::B]--;
  m_colors[syntaxtag::B] = "";
  tag_close('B');
}

void builder::color(string color_) {
  auto color(color_);
  if (color.length() == 2 || (color.find("#") == 0 && color.length() == 3)) {
    color = "#" + color.substr(color.length() - 2);
    auto fg = m_bar.foreground.source();
    color += fg.substr(fg.length() - (fg.length() < 6 ? 3 : 6));
  } else if (color.length() >= 7 && color == "#" + string(color.length() - 1, color[1])) {
    color = color.substr(0, 4);
  }

  if (color.empty() && m_counters[syntaxtag::F] > 0)
    color_close(true);
  if (color.empty() || color == m_colors[syntaxtag::F])
    return;
  if (m_lazy && m_counters[syntaxtag::F] > 0)
    color_close(true);

  m_counters[syntaxtag::F]++;
  m_colors[syntaxtag::F] = color;
  tag_open('F', color);
}

void builder::color_alpha(string alpha_) {
  auto alpha(alpha_);
  string val = m_bar.foreground.source();
  if (alpha.find("#") == std::string::npos) {
    alpha = "#" + alpha;
  }

  if (alpha.size() == 4) {
    color(alpha);
    return;
  }

  if (val.size() < 6 && val.size() > 2) {
    val.append(val.substr(val.size() - 3));
  }

  color((alpha.substr(0, 3) + val.substr(val.size() - 6)).substr(0, 9));
}

void builder::color_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::F] <= 0)
    return;

  m_counters[syntaxtag::F]--;
  m_colors[syntaxtag::F] = "";
  tag_close('F');
}

void builder::line_color(string color) {
  if (color.empty() && m_counters[syntaxtag::U] > 0)
    line_color_close(true);
  if (color.empty() || color == m_colors[syntaxtag::U])
    return;
  if (m_lazy && m_counters[syntaxtag::U] > 0)
    line_color_close(true);

  m_counters[syntaxtag::U]++;
  m_colors[syntaxtag::U] = color;
  tag_open('U', color);
}

void builder::line_color_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::U] <= 0)
    return;

  m_counters[syntaxtag::U]--;
  m_colors[syntaxtag::U] = "";
  tag_close('U');
}

void builder::overline(string color) {
  if (!color.empty())
    line_color(color);
  if (m_counters[syntaxtag::o] > 0)
    return;

  m_counters[syntaxtag::o]++;
  append("%{+o}");
}

void builder::overline_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::o] <= 0)
    return;

  m_counters[syntaxtag::o]--;
  append("%{-o}");
}

void builder::underline(string color) {
  if (!color.empty())
    line_color(color);
  if (m_counters[syntaxtag::u] > 0)
    return;

  m_counters[syntaxtag::u]++;
  append("%{+u}");
}

void builder::underline_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::u] <= 0)
    return;

  m_counters[syntaxtag::u]--;
  append("%{-u}");
}

void builder::cmd(mousebtn index, string action, bool condition) {
  int button = static_cast<int>(index);

  if (!condition || action.empty())
    return;

  action = string_util::replace_all(action, ":", "\\:");
  action = string_util::replace_all(action, "$", "\\$");
  action = string_util::replace_all(action, "}", "\\}");
  action = string_util::replace_all(action, "{", "\\{");
  action = string_util::replace_all(action, "%", "\x0025");

  append("%{A" + std::to_string(button) + ":" + action + ":}");
  m_counters[syntaxtag::A]++;
}

void builder::cmd_close(bool force) {
  if (m_counters[syntaxtag::A] > 0 || force)
    append("%{A}");
  if (m_counters[syntaxtag::A] > 0)
    m_counters[syntaxtag::A]--;
}

void builder::tag_open(char tag, string value) {
  append("%{" + string({tag}) + value + "}");
}

void builder::tag_close(char tag) {
  append("%{" + string({tag}) + "-}");
}

POLYBAR_NS_END
<commit_msg>fix(builder): Always close raw syntax tags<commit_after>#include "components/builder.hpp"
#include "utils/math.hpp"
#include "utils/string.hpp"

POLYBAR_NS

void builder::set_lazy(bool mode) {
  m_lazy = mode;
}

string builder::flush() {
  if (m_lazy) {
    while (m_counters[syntaxtag::A] > 0) cmd_close(true);
    while (m_counters[syntaxtag::B] > 0) background_close(true);
    while (m_counters[syntaxtag::F] > 0) color_close(true);
    while (m_counters[syntaxtag::T] > 0) font_close(true);
    while (m_counters[syntaxtag::U] > 0) line_color_close(true);
    while (m_counters[syntaxtag::u] > 0) underline_close(true);
    while (m_counters[syntaxtag::o] > 0) overline_close(true);
  }

  string output = m_output.data();

  // reset values
  m_output.clear();
  for (auto& counter : m_counters) counter.second = 0;
  for (auto& value : m_colors) value.second = "";
  m_fontindex = 1;

  return string_util::replace_all(output, string{BUILDER_SPACE_TOKEN}, " ");
}

void builder::append(string text) {
  string str(text);
  auto len = str.length();
  if (len > 2 && str[0] == '"' && str[len - 1] == '"')
    m_output += str.substr(1, len - 2);
  else
    m_output += str;
}

void builder::node(string str, bool add_space) {
  string::size_type n, m;
  string s(str);

  while (true) {
    if (s.empty()) {
      break;

    } else if ((n = s.find("%{F-}")) == 0) {
      color_close(true);
      s.erase(0, 5);

    } else if ((n = s.find("%{F#")) == 0 && (m = s.find("}")) != string::npos) {
      if (m - n - 4 == 2)
        color_alpha(s.substr(n + 3, m - 3));
      else
        color(s.substr(n + 3, m - 3));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{B-}")) == 0) {
      background_close(true);
      s.erase(0, 5);

    } else if ((n = s.find("%{B#")) == 0 && (m = s.find("}")) != string::npos) {
      background(s.substr(n + 3, m - 3));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{T-}")) == 0) {
      font_close(true);
      s.erase(0, 5);

    } else if ((n = s.find("%{T")) == 0 && (m = s.find("}")) != string::npos) {
      font(std::atoi(s.substr(n + 3, m - 3).c_str()));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{U-}")) == 0) {
      line_color_close(true);
      s.erase(0, 5);

    } else if ((n = s.find("%{U#")) == 0 && (m = s.find("}")) != string::npos) {
      line_color(s.substr(n + 3, m - 3));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{+u}")) == 0) {
      underline();
      s.erase(0, 5);

    } else if ((n = s.find("%{+o}")) == 0) {
      overline();
      s.erase(0, 5);

    } else if ((n = s.find("%{-u}")) == 0) {
      underline_close(true);
      s.erase(0, 5);

    } else if ((n = s.find("%{-o}")) == 0) {
      overline_close(true);
      s.erase(0, 5);

    } else if ((n = s.find("%{A}")) == 0) {
      cmd_close(true);
      s.erase(0, 4);

    } else if ((n = s.find("%{")) == 0 && (m = s.find("}")) != string::npos) {
      append(s.substr(n, m + 1));
      s.erase(n, m + 1);

    } else if ((n = s.find("%{")) > 0) {
      append(s.substr(0, n));
      s.erase(0, n);

    } else
      break;
  }

  if (!s.empty())
    append(s);
  if (add_space)
    space();
}

void builder::node(string str, int font_index, bool add_space) {
  font(font_index);
  node(str, add_space);
  font_close();
}

// void builder::node(progressbar_t bar, float perc, bool add_space) {
//   if (!bar)
//     return;
//   node(bar->get_output(math_util::cap<float>(0, 100, perc)), add_space);
// }

void builder::node(label_t label, bool add_space) {
  if (!label || !*label)
    return;

  auto text = label->get();

  if (label->m_maxlen > 0 && text.length() > label->m_maxlen) {
    text = text.substr(0, label->m_maxlen) + "...";
  }

  if ((label->m_overline.empty() && m_counters[syntaxtag::o] > 0) ||
      (m_counters[syntaxtag::o] > 0 && label->m_margin > 0))
    overline_close(true);
  if ((label->m_underline.empty() && m_counters[syntaxtag::u] > 0) ||
      (m_counters[syntaxtag::u] > 0 && label->m_margin > 0))
    underline_close(true);

  if (label->m_margin > 0)
    space(label->m_margin);

  if (!label->m_overline.empty())
    overline(label->m_overline);
  if (!label->m_underline.empty())
    underline(label->m_underline);

  background(label->m_background);
  color(label->m_foreground);

  if (label->m_padding > 0)
    space(label->m_padding);

  node(text, label->m_font, add_space);

  if (label->m_padding > 0)
    space(label->m_padding);

  color_close(m_lazy && label->m_margin > 0);
  background_close(m_lazy && label->m_margin > 0);

  if (!label->m_underline.empty() || (label->m_margin > 0 && m_counters[syntaxtag::u] > 0))
    underline_close(m_lazy && label->m_margin > 0);
  if (!label->m_overline.empty() || (label->m_margin > 0 && m_counters[syntaxtag::o] > 0))
    overline_close(m_lazy && label->m_margin > 0);

  if (label->m_margin > 0)
    space(label->m_margin);
}

// void builder::node(ramp_t ramp, float perc, bool add_space) {
//   if (!ramp)
//     return;
//   node(ramp->get_by_percentage(math_util::cap<float>(0, 100, perc)), add_space);
// }

// void builder::node(animation_t animation, bool add_space) {
//   if (!animation)
//     return;
//   node(animation->get(), add_space);
// }

void builder::offset(int pixels) {
  if (pixels != 0)
    tag_open('O', std::to_string(pixels));
}

void builder::space(int width) {
  if (width == DEFAULT_SPACING)
    width = m_bar.spacing;
  if (width <= 0)
    return;
  string str(width, ' ');
  append(str);
}

void builder::remove_trailing_space(int width) {
  if (width == DEFAULT_SPACING)
    width = m_bar.spacing;
  if (width <= 0)
    return;
  string::size_type spacing = width;
  string str(spacing, ' ');
  if (m_output.length() >= spacing && m_output.substr(m_output.length() - spacing) == str)
    m_output = m_output.substr(0, m_output.length() - spacing);
}

void builder::invert() {
  tag_open('R', "");
}

void builder::font(int index) {
  if (index <= 0 && m_counters[syntaxtag::T] > 0)
    font_close(true);
  if (index <= 0 || index == m_fontindex)
    return;
  if (m_lazy && m_counters[syntaxtag::T] > 0)
    font_close(true);

  m_counters[syntaxtag::T]++;
  m_fontindex = index;
  tag_open('T', std::to_string(index));
}

void builder::font_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::T] <= 0)
    return;

  m_counters[syntaxtag::T]--;
  m_fontindex = 1;
  tag_close('T');
}

void builder::background(string color) {
  if (color.length() == 2 || (color.find("#") == 0 && color.length() == 3)) {
    color = "#" + color.substr(color.length() - 2);
    auto bg = m_bar.background.source();
    color += bg.substr(bg.length() - (bg.length() < 6 ? 3 : 6));
  } else if (color.length() >= 7 && color == "#" + string(color.length() - 1, color[1])) {
    color = color.substr(0, 4);
  }

  if (color.empty() && m_counters[syntaxtag::B] > 0)
    background_close(true);
  if (color.empty() || color == m_colors[syntaxtag::B])
    return;
  if (m_lazy && m_counters[syntaxtag::B] > 0)
    background_close(true);

  m_counters[syntaxtag::B]++;
  m_colors[syntaxtag::B] = color;
  tag_open('B', color);
}

void builder::background_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::B] <= 0)
    return;

  m_counters[syntaxtag::B]--;
  m_colors[syntaxtag::B] = "";
  tag_close('B');
}

void builder::color(string color_) {
  auto color(color_);
  if (color.length() == 2 || (color.find("#") == 0 && color.length() == 3)) {
    color = "#" + color.substr(color.length() - 2);
    auto fg = m_bar.foreground.source();
    color += fg.substr(fg.length() - (fg.length() < 6 ? 3 : 6));
  } else if (color.length() >= 7 && color == "#" + string(color.length() - 1, color[1])) {
    color = color.substr(0, 4);
  }

  if (color.empty() && m_counters[syntaxtag::F] > 0)
    color_close(true);
  if (color.empty() || color == m_colors[syntaxtag::F])
    return;
  if (m_lazy && m_counters[syntaxtag::F] > 0)
    color_close(true);

  m_counters[syntaxtag::F]++;
  m_colors[syntaxtag::F] = color;
  tag_open('F', color);
}

void builder::color_alpha(string alpha_) {
  auto alpha(alpha_);
  string val = m_bar.foreground.source();
  if (alpha.find("#") == std::string::npos) {
    alpha = "#" + alpha;
  }

  if (alpha.size() == 4) {
    color(alpha);
    return;
  }

  if (val.size() < 6 && val.size() > 2) {
    val.append(val.substr(val.size() - 3));
  }

  color((alpha.substr(0, 3) + val.substr(val.size() - 6)).substr(0, 9));
}

void builder::color_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::F] <= 0)
    return;

  m_counters[syntaxtag::F]--;
  m_colors[syntaxtag::F] = "";
  tag_close('F');
}

void builder::line_color(string color) {
  if (color.empty() && m_counters[syntaxtag::U] > 0)
    line_color_close(true);
  if (color.empty() || color == m_colors[syntaxtag::U])
    return;
  if (m_lazy && m_counters[syntaxtag::U] > 0)
    line_color_close(true);

  m_counters[syntaxtag::U]++;
  m_colors[syntaxtag::U] = color;
  tag_open('U', color);
}

void builder::line_color_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::U] <= 0)
    return;

  m_counters[syntaxtag::U]--;
  m_colors[syntaxtag::U] = "";
  tag_close('U');
}

void builder::overline(string color) {
  if (!color.empty())
    line_color(color);
  if (m_counters[syntaxtag::o] > 0)
    return;

  m_counters[syntaxtag::o]++;
  append("%{+o}");
}

void builder::overline_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::o] <= 0)
    return;

  m_counters[syntaxtag::o]--;
  append("%{-o}");
}

void builder::underline(string color) {
  if (!color.empty())
    line_color(color);
  if (m_counters[syntaxtag::u] > 0)
    return;

  m_counters[syntaxtag::u]++;
  append("%{+u}");
}

void builder::underline_close(bool force) {
  if ((!force && m_lazy) || m_counters[syntaxtag::u] <= 0)
    return;

  m_counters[syntaxtag::u]--;
  append("%{-u}");
}

void builder::cmd(mousebtn index, string action, bool condition) {
  int button = static_cast<int>(index);

  if (!condition || action.empty())
    return;

  action = string_util::replace_all(action, ":", "\\:");
  action = string_util::replace_all(action, "$", "\\$");
  action = string_util::replace_all(action, "}", "\\}");
  action = string_util::replace_all(action, "{", "\\{");
  action = string_util::replace_all(action, "%", "\x0025");

  append("%{A" + std::to_string(button) + ":" + action + ":}");
  m_counters[syntaxtag::A]++;
}

void builder::cmd_close(bool force) {
  if (m_counters[syntaxtag::A] > 0 || force)
    append("%{A}");
  if (m_counters[syntaxtag::A] > 0)
    m_counters[syntaxtag::A]--;
}

void builder::tag_open(char tag, string value) {
  append("%{" + string({tag}) + value + "}");
}

void builder::tag_close(char tag) {
  append("%{" + string({tag}) + "-}");
}

POLYBAR_NS_END
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
//    you must not claim that you wrote the original software.
//    If you use this software in a product, an acknowledgment
//    in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
//    and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <cpp3ds/Audio/Sound.hpp>
#include <cpp3ds/Audio/SoundBuffer.hpp>
#include <3ds.h>
#include <string.h>
#include <cpp3ds/System/Err.hpp>
#include <cpp3ds/System/Lock.hpp>

namespace cpp3ds
{

////////////////////////////////////////////////////////////
Sound::Sound()
: m_buffer(nullptr)
, m_loop(false)
, m_isADPCM(false)
{
}

////////////////////////////////////////////////////////////
Sound::Sound(const SoundBuffer& buffer)
: m_buffer(nullptr)
, m_loop(false)
, m_isADPCM(false)
{
    setBuffer(buffer);
}

////////////////////////////////////////////////////////////
Sound::Sound(const Sound& copy)
: SoundSource(copy)
, m_buffer(nullptr)
{
    if (copy.m_buffer)
        setBuffer(*copy.m_buffer);

    setLoop(copy.getLoop());
	setStateADPCM(copy.getStateADPCM());
}

////////////////////////////////////////////////////////////
Sound::~Sound()
{
    stop();
    if (m_buffer)
        m_buffer->detachSound(this);
}

////////////////////////////////////////////////////////////
void Sound::play()
{
	if (!m_buffer || m_buffer->getSampleCount() == 0)
		return;
	if (getStatus() == Playing)
		stop();
	if (getStatus() == Paused) {
		ndspChnSetPaused(m_channel, false);
		return;
	}

	{
		Lock lock(g_activeNdspChannelsMutex);
		m_channel = 0;
		while (m_channel < 24 && ((g_activeNdspChannels >> m_channel) & 1))
			m_channel++;

		if (m_channel == 24) {
			err() << "Failed to play audio stream: all channels are in use." << std::endl;
			m_channel = -1;
			return;
		}

		g_activeNdspChannels |= 1 << m_channel;
	}

	setPlayingOffset(Time::Zero);

	u32 size = sizeof(Int16) * m_buffer->getSampleCount();

	ndspChnReset(m_channel);
	ndspChnSetInterp(m_channel, NDSP_INTERP_POLYPHASE);
	ndspChnSetRate(m_channel, float(m_buffer->getSampleRate()));
	ndspChnSetFormat(m_channel, (m_buffer->getChannelCount() == 1) ? NDSP_FORMAT_MONO_PCM16 : NDSP_FORMAT_STEREO_PCM16);

	DSP_FlushDataCache(m_buffer->getSamples(), size);

	ndspChnWaveBufAdd(m_channel, &m_ndspWaveBuf);
}

////////////////////////////////////////////////////////////
void Sound::pause()
{
	if (getStatus() != Playing)
		return;

	ndspChnSetPaused(m_channel, true);
}

////////////////////////////////////////////////////////////
void Sound::stop()
{
	if (getStatus() == Stopped)
		return;

	ndspChnWaveBufClear(m_channel);

	{
		Lock lock(g_activeNdspChannelsMutex);
		g_activeNdspChannels &= ~(1 << m_channel);
		m_channel = -1;
	}
}

////////////////////////////////////////////////////////////
void Sound::setBuffer(const SoundBuffer& buffer)
{
    // First detach from the previous buffer
    if (m_buffer)
    {
        stop();
        m_buffer->detachSound(this);
    }

	memset(&m_ndspWaveBuf, 0, sizeof(ndspWaveBuf));
	m_ndspWaveBuf.data_vaddr = buffer.getSamples();
	m_ndspWaveBuf.nsamples = buffer.getSampleCount() / buffer.getChannelCount();
	m_ndspWaveBuf.looping = m_loop; // Loop enabled
	m_ndspWaveBuf.status = NDSP_WBUF_FREE;

    // Assign and use the new buffer
    m_buffer = &buffer;
    m_buffer->attachSound(this);
}

////////////////////////////////////////////////////////////
void Sound::setStateADPCM(bool enable)
{
	m_isADPCM = enable;
}

////////////////////////////////////////////////////////////
bool Sound::getStateADPCM() const
{
	return m_isADPCM;
}

////////////////////////////////////////////////////////////
void Sound::setLoop(bool loop)
{
	m_loop = loop;
	m_ndspWaveBuf.looping = m_loop;
}

////////////////////////////////////////////////////////////
void Sound::setPlayingOffset(Time timeOffset)
{
	Status status = getStatus();
	stop();
	m_playOffset = timeOffset;
	int offset = m_buffer->getSampleRate() * m_buffer->getChannelCount() * timeOffset.asSeconds();
	m_ndspWaveBuf.data_vaddr = m_buffer->getSamples() + offset;
	m_ndspWaveBuf.nsamples = m_buffer->getSampleCount() / m_buffer->getChannelCount() - offset;
	if (status == Playing)
		ndspChnWaveBufAdd(m_channel, &m_ndspWaveBuf);
}

////////////////////////////////////////////////////////////
const SoundBuffer* Sound::getBuffer() const
{
    return m_buffer;
}

////////////////////////////////////////////////////////////
bool Sound::getLoop() const
{
    return m_loop;
}

////////////////////////////////////////////////////////////
Time Sound::getPlayingOffset() const
{
	if (getStatus() == Stopped)
		return Time::Zero;

	u32 samplePos = ndspChnGetSamplePos(m_channel);
	return seconds(static_cast<float>(samplePos) / m_buffer->getSampleRate()) + m_playOffset;
}

////////////////////////////////////////////////////////////
Sound::Status Sound::getStatus() const
{
    return SoundSource::getStatus();
}

////////////////////////////////////////////////////////////
Sound& Sound::operator =(const Sound& right)
{
    // Here we don't use the copy-and-swap idiom, because it would mess up
    // the list of sound instances contained in the buffers

    // Detach the sound instance from the previous buffer (if any)
    if (m_buffer)
    {
        stop();
        m_buffer->detachSound(this);
        m_buffer = NULL;
    }

    // Copy the sound attributes
    if (right.m_buffer)
        setBuffer(*right.m_buffer);
    setLoop(right.getLoop());
    setPitch(right.getPitch());
    setVolume(right.getVolume());
    setPosition(right.getPosition());
    setRelativeToListener(right.isRelativeToListener());
    setMinDistance(right.getMinDistance());
    setAttenuation(right.getAttenuation());

    return *this;
}

////////////////////////////////////////////////////////////
void Sound::resetBuffer()
{
    // First stop the sound in case it is playing
    stop();

    // Detach the buffer
    if (m_buffer)
    {
        m_buffer->detachSound(this);
        m_buffer = NULL;
    }
}

} // namespace cpp3ds
<commit_msg>Fix channel lock bug exhausting all channels<commit_after>////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
//    you must not claim that you wrote the original software.
//    If you use this software in a product, an acknowledgment
//    in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
//    and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <cpp3ds/Audio/Sound.hpp>
#include <cpp3ds/Audio/SoundBuffer.hpp>
#include <3ds.h>
#include <string.h>
#include <cpp3ds/System/Err.hpp>
#include <cpp3ds/System/Lock.hpp>

namespace cpp3ds
{

////////////////////////////////////////////////////////////
Sound::Sound()
: m_buffer(nullptr)
, m_loop(false)
, m_isADPCM(false)
{
}

////////////////////////////////////////////////////////////
Sound::Sound(const SoundBuffer& buffer)
: m_buffer(nullptr)
, m_loop(false)
, m_isADPCM(false)
{
    setBuffer(buffer);
}

////////////////////////////////////////////////////////////
Sound::Sound(const Sound& copy)
: SoundSource(copy)
, m_buffer(nullptr)
{
    if (copy.m_buffer)
        setBuffer(*copy.m_buffer);

    setLoop(copy.getLoop());
	setStateADPCM(copy.getStateADPCM());
}

////////////////////////////////////////////////////////////
Sound::~Sound()
{
    stop();
    if (m_buffer)
        m_buffer->detachSound(this);
}

////////////////////////////////////////////////////////////
void Sound::play()
{
	if (!m_buffer || m_buffer->getSampleCount() == 0)
		return;
	if (getStatus() == Playing)
		stop();
	if (getStatus() == Paused) {
		ndspChnSetPaused(m_channel, false);
		return;
	}

	if (m_channel == -1)
	{
		Lock lock(g_activeNdspChannelsMutex);
		m_channel = 0;
		while (m_channel < 24 && ((g_activeNdspChannels >> m_channel) & 1))
			m_channel++;

		if (m_channel == 24) {
			err() << "Failed to play audio stream: all channels are in use." << std::endl;
			m_channel = -1;
			return;
		}

		g_activeNdspChannels |= 1 << m_channel;
	}

	setPlayingOffset(Time::Zero);

	u32 size = sizeof(Int16) * m_buffer->getSampleCount();

	ndspChnReset(m_channel);
	ndspChnSetInterp(m_channel, NDSP_INTERP_POLYPHASE);
	ndspChnSetRate(m_channel, float(m_buffer->getSampleRate()));
	ndspChnSetFormat(m_channel, (m_buffer->getChannelCount() == 1) ? NDSP_FORMAT_MONO_PCM16 : NDSP_FORMAT_STEREO_PCM16);

	DSP_FlushDataCache(m_buffer->getSamples(), size);

	ndspChnWaveBufAdd(m_channel, &m_ndspWaveBuf);
}

////////////////////////////////////////////////////////////
void Sound::pause()
{
	if (getStatus() != Playing)
		return;

	ndspChnSetPaused(m_channel, true);
}

////////////////////////////////////////////////////////////
void Sound::stop()
{
	if (getStatus() == Stopped)
		return;

	ndspChnWaveBufClear(m_channel);

	// TODO: set ndsp callback to make channel inactive after playback finishes
	{
		Lock lock(g_activeNdspChannelsMutex);
		g_activeNdspChannels &= ~(1 << m_channel);
		m_channel = -1;
	}
}

////////////////////////////////////////////////////////////
void Sound::setBuffer(const SoundBuffer& buffer)
{
    // First detach from the previous buffer
    if (m_buffer)
    {
        stop();
        m_buffer->detachSound(this);
    }

	memset(&m_ndspWaveBuf, 0, sizeof(ndspWaveBuf));
	m_ndspWaveBuf.data_vaddr = buffer.getSamples();
	m_ndspWaveBuf.nsamples = buffer.getSampleCount() / buffer.getChannelCount();
	m_ndspWaveBuf.looping = m_loop; // Loop enabled
	m_ndspWaveBuf.status = NDSP_WBUF_FREE;

    // Assign and use the new buffer
    m_buffer = &buffer;
    m_buffer->attachSound(this);
}

////////////////////////////////////////////////////////////
void Sound::setStateADPCM(bool enable)
{
	m_isADPCM = enable;
}

////////////////////////////////////////////////////////////
bool Sound::getStateADPCM() const
{
	return m_isADPCM;
}

////////////////////////////////////////////////////////////
void Sound::setLoop(bool loop)
{
	m_loop = loop;
	m_ndspWaveBuf.looping = m_loop;
}

////////////////////////////////////////////////////////////
void Sound::setPlayingOffset(Time timeOffset)
{
	Status status = getStatus();
	stop();
	m_playOffset = timeOffset;
	int offset = m_buffer->getSampleRate() * m_buffer->getChannelCount() * timeOffset.asSeconds();
	m_ndspWaveBuf.data_vaddr = m_buffer->getSamples() + offset;
	m_ndspWaveBuf.nsamples = m_buffer->getSampleCount() / m_buffer->getChannelCount() - offset;
	if (status == Playing)
		ndspChnWaveBufAdd(m_channel, &m_ndspWaveBuf);
}

////////////////////////////////////////////////////////////
const SoundBuffer* Sound::getBuffer() const
{
    return m_buffer;
}

////////////////////////////////////////////////////////////
bool Sound::getLoop() const
{
    return m_loop;
}

////////////////////////////////////////////////////////////
Time Sound::getPlayingOffset() const
{
	if (getStatus() == Stopped)
		return Time::Zero;

	u32 samplePos = ndspChnGetSamplePos(m_channel);
	return seconds(static_cast<float>(samplePos) / m_buffer->getSampleRate()) + m_playOffset;
}

////////////////////////////////////////////////////////////
Sound::Status Sound::getStatus() const
{
    return SoundSource::getStatus();
}

////////////////////////////////////////////////////////////
Sound& Sound::operator =(const Sound& right)
{
    // Here we don't use the copy-and-swap idiom, because it would mess up
    // the list of sound instances contained in the buffers

    // Detach the sound instance from the previous buffer (if any)
    if (m_buffer)
    {
        stop();
        m_buffer->detachSound(this);
        m_buffer = NULL;
    }

    // Copy the sound attributes
    if (right.m_buffer)
        setBuffer(*right.m_buffer);
    setLoop(right.getLoop());
    setPitch(right.getPitch());
    setVolume(right.getVolume());
    setPosition(right.getPosition());
    setRelativeToListener(right.isRelativeToListener());
    setMinDistance(right.getMinDistance());
    setAttenuation(right.getAttenuation());

    return *this;
}

////////////////////////////////////////////////////////////
void Sound::resetBuffer()
{
    // First stop the sound in case it is playing
    stop();

    // Detach the buffer
    if (m_buffer)
    {
        m_buffer->detachSound(this);
        m_buffer = NULL;
    }
}

} // namespace cpp3ds
<|endoftext|>