<commit_before>///
/// @file   primesieve_iterator.cpp
/// @brief  C port of primesieve::iterator.
///
/// Copyright (C) 2013 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/soe/config.hpp>
#include <primesieve.hpp>
#include <primesieve.h>

#include <algorithm>
#include <cerrno>
#include <cmath>
#include <vector>
#include <limits>

namespace {

/// Convert pimpl pointer to std::vector
std::vector<uint64_t>& to_vector(uint64_t* primes_pimpl)
{
  std::vector<uint64_t>* primes = reinterpret_cast<std::vector<uint64_t>*>(primes_pimpl);
  return *primes;
}

/// Calculate an interval size that ensures a good load balance.
/// @param n  Start or stop number.
///
uint64_t get_interval_size(primesieve_iterator* pi, uint64_t n)
{
  using config::ITERATOR_CACHE_SMALL;
  using config::ITERATOR_CACHE_MEDIUM;
  using config::ITERATOR_CACHE_LARGE;

  pi->count_++;
  double x = std::max(static_cast<double>(n), 10.0);
  double sqrtx = std::sqrt(x);
  uint64_t sqrtx_primes = static_cast<uint64_t>(sqrtx / (std::log(sqrtx) - 1));

  uint64_t max_primes = ITERATOR_CACHE_LARGE / sizeof(uint64_t);
  uint64_t primes = ((pi->count_ < 10) ? ITERATOR_CACHE_SMALL : ITERATOR_CACHE_MEDIUM) / sizeof(uint64_t);
  primes = std::min(std::max(primes, sqrtx_primes), max_primes);

  return static_cast<uint64_t>(primes * std::log(x));
}

/// Generate the primes inside [start, stop] and
/// store them in the primes vector.
///
void generate_primes(primesieve_iterator* pi, uint64_t start, uint64_t stop)
{
  std::vector<uint64_t>& primes = to_vector(pi->primes_pimpl_);
  if (primes.empty() || primes[0] != PRIMESIEVE_ERROR)
  {
    try {
      primes.clear();
      primesieve::generate_primes(start, stop, &primes);
    } catch (std::exception&) {
      primes.clear();
    }
    if (primes.empty())
    {
      primes.resize(64, PRIMESIEVE_ERROR);
      errno = EDOM;
    }
    pi->primes_ = &primes[0];
    pi->size_ = primes.size();
  }
}

} // end anonymous namespace

/// C constructor
void primesieve_init(primesieve_iterator* pi)
{
  pi->primes_pimpl_ = reinterpret_cast<uint64_t*>(new std::vector<uint64_t>);
  primesieve_skipto(pi, 0);
}

/// C destructor
void primesieve_free(primesieve_iterator* pi)
{
  std::vector<uint64_t>* primes = &to_vector(pi->primes_pimpl_);
  delete primes;
}

/// Set primesieve_iterator to start
void primesieve_skipto(primesieve_iterator* pi, uint64_t start)
{
  pi->first_ = true;
  pi->adjust_skipto_ = false;
  pi->i_ = 0;
  pi->count_ = 0;
  pi->start_ = start;

  std::vector<uint64_t>& primes = to_vector(pi->primes_pimpl_);

  if (!primes.empty() &&
       primes.front() <= pi->start_ &&
       primes.back()  >= pi->start_)
  {
    pi->adjust_skipto_ = true;
    pi->i_ = std::lower_bound(primes.begin(), primes.end(), pi->start_) - primes.begin();
  }
  else
    primes.clear();
}

/// Generate new next primes
void generate_next_primes(primesieve_iterator* pi)
{
  std::vector<uint64_t>& primes = to_vector(pi->primes_pimpl_);
  if (pi->adjust_skipto_)
  {
    pi->adjust_skipto_ = false;
    if (pi->i_ > 0 && primes[pi->i_ - 1] >= pi->start_)
      pi->i_--;
  }
  else
  {
    uint64_t start = (pi->first_) ? pi->start_ : primes.back() + 1;
    uint64_t interval_size = get_interval_size(pi, start);
    uint64_t stop = (start < max_stop() - interval_size) ? start + interval_size : max_stop();
    generate_primes(pi, start, stop);
    pi->i_ = 0;
  }
  pi->first_ = false;
}

/// Generate new previous primes
void generate_previous_primes(primesieve_iterator* pi)
{
  std::vector<uint64_t>& primes = to_vector(pi->primes_pimpl_);
  if (pi->adjust_skipto_)
  {
    pi->adjust_skipto_ = false;
    if (pi->i_ > 0 && primes[pi->i_] > pi->start_)
      pi->i_--;
  }
  else
  {
    uint64_t stop = pi->start_;
    if (!pi->first_)
      stop = (primes.front() > 1) ? primes.front() - 1 : 0;
    uint64_t interval_size = get_interval_size(pi, stop);
    uint64_t start = (stop > interval_size) ? stop - interval_size : 0;
    generate_primes(pi, start, stop);
    pi->i_ = primes.size();
  }
  pi->first_ = false;
}
<commit_msg>Refactoring<commit_after>///
/// @file   primesieve_iterator.cpp
/// @brief  C port of primesieve::iterator.
///
/// Copyright (C) 2013 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/soe/config.hpp>
#include <primesieve.hpp>
#include <primesieve.h>

#include <algorithm>
#include <cerrno>
#include <cmath>
#include <vector>
#include <limits>

namespace {

/// Convert pimpl pointer to std::vector
std::vector<uint64_t>& to_vector(uint64_t* primes_pimpl)
{
  std::vector<uint64_t>* primes = reinterpret_cast<std::vector<uint64_t>*>(primes_pimpl);
  return *primes;
}

/// Calculate an interval size that ensures a good load balance.
/// @param n  Start or stop number.
///
uint64_t get_interval_size(primesieve_iterator* pi, uint64_t n)
{
  using config::ITERATOR_CACHE_SMALL;
  using config::ITERATOR_CACHE_MEDIUM;
  using config::ITERATOR_CACHE_LARGE;

  pi->count_++;
  double x = std::max(static_cast<double>(n), 10.0);
  double sqrtx = std::sqrt(x);
  uint64_t sqrtx_primes = static_cast<uint64_t>(sqrtx / (std::log(sqrtx) - 1));

  uint64_t max_primes = ITERATOR_CACHE_LARGE / sizeof(uint64_t);
  uint64_t primes = ((pi->count_ < 10) ? ITERATOR_CACHE_SMALL : ITERATOR_CACHE_MEDIUM) / sizeof(uint64_t);
  primes = std::min(std::max(primes, sqrtx_primes), max_primes);

  return static_cast<uint64_t>(primes * std::log(x));
}

/// Generate the primes inside [start, stop] and
/// store them in the primes vector.
///
void generate_primes(primesieve_iterator* pi, uint64_t start, uint64_t stop)
{
  std::vector<uint64_t>& primes = to_vector(pi->primes_pimpl_);
  if (primes.empty() || primes[0] != PRIMESIEVE_ERROR)
  {
    try {
      primes.clear();
      primesieve::generate_primes(start, stop, &primes);
    } catch (std::exception&) {
      primes.clear();
    }
    if (primes.empty())
    {
      primes.resize(64, PRIMESIEVE_ERROR);
      errno = EDOM;
    }
    pi->primes_ = &primes[0];
    pi->size_   =  primes.size();
  }
}

} // end anonymous namespace

/// C constructor
void primesieve_init(primesieve_iterator* pi)
{
  pi->primes_pimpl_ = reinterpret_cast<uint64_t*>(new std::vector<uint64_t>);
  primesieve_skipto(pi, 0);
}

/// C destructor
void primesieve_free(primesieve_iterator* pi)
{
  std::vector<uint64_t>* primes = &to_vector(pi->primes_pimpl_);
  delete primes;
}

/// Set primesieve_iterator to start
void primesieve_skipto(primesieve_iterator* pi, uint64_t start)
{
  pi->first_ = true;
  pi->adjust_skipto_ = false;
  pi->i_ = 0;
  pi->count_ = 0;
  pi->start_ = start;

  std::vector<uint64_t>& primes = to_vector(pi->primes_pimpl_);

  if (!primes.empty() &&
       primes.front() <= pi->start_ &&
       primes.back()  >= pi->start_)
  {
    pi->adjust_skipto_ = true;
    pi->i_ = std::lower_bound(primes.begin(), primes.end(), pi->start_) - primes.begin();
  }
  else
    primes.clear();
}

/// Generate new next primes
void generate_next_primes(primesieve_iterator* pi)
{
  std::vector<uint64_t>& primes = to_vector(pi->primes_pimpl_);
  if (pi->adjust_skipto_)
  {
    pi->adjust_skipto_ = false;
    if (pi->i_ > 0 && primes[pi->i_ - 1] >= pi->start_)
      pi->i_--;
  }
  else
  {
    uint64_t start = (pi->first_) ? pi->start_ : primes.back() + 1;
    uint64_t interval_size = get_interval_size(pi, start);
    uint64_t stop = (start < max_stop() - interval_size) ? start + interval_size : max_stop();
    generate_primes(pi, start, stop);
    pi->i_ = 0;
  }
  pi->first_ = false;
}

/// Generate new previous primes
void generate_previous_primes(primesieve_iterator* pi)
{
  std::vector<uint64_t>& primes = to_vector(pi->primes_pimpl_);
  if (pi->adjust_skipto_)
  {
    pi->adjust_skipto_ = false;
    if (pi->i_ > 0 && primes[pi->i_] > pi->start_)
      pi->i_--;
  }
  else
  {
    uint64_t stop = pi->start_;
    if (!pi->first_)
      stop = (primes.front() > 1) ? primes.front() - 1 : 0;
    uint64_t interval_size = get_interval_size(pi, stop);
    uint64_t start = (stop > interval_size) ? stop - interval_size : 0;
    generate_primes(pi, start, stop);
    pi->i_ = primes.size();
  }
  pi->first_ = false;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "diffutils.h"
#include "differ.h"
#include <QStringList>
#include "texteditor/fontsettings.h"

namespace DiffEditor {
namespace Internal {

static QList<TextLineData> assemblyRows(const QList<TextLineData> &lines,
                                        const QMap<int, int> &lineSpans)
{
    QList<TextLineData> data;

    const int lineCount = lines.count();
    for (int i = 0; i <= lineCount; i++) {
        for (int j = 0; j < lineSpans.value(i); j++)
            data.append(TextLineData(TextLineData::Separator));
        if (i < lineCount)
            data.append(lines.at(i));
    }
    return data;
}

static bool lastLinesEqual(const QList<TextLineData> &leftLines,
                           const QList<TextLineData> &rightLines)
{
    const bool leftLineEqual = leftLines.count()
            ? leftLines.last().text.isEmpty()
            : true;
    const bool rightLineEqual = rightLines.count()
            ? rightLines.last().text.isEmpty()
            : true;
    return leftLineEqual && rightLineEqual;
}

static void handleLine(const QStringList &newLines,
                       int line,
                       QList<TextLineData> *lines,
                       int *lineNumber)
{
    if (line < newLines.count()) {
        const QString text = newLines.at(line);
        if (lines->isEmpty() || line > 0) {
            if (line > 0)
                ++*lineNumber;
            lines->append(TextLineData(text));
        } else {
            lines->last().text += text;
        }
    }
}

static void handleDifference(const QString &text,
                             QList<TextLineData> *lines,
                             int *lineNumber)
{
    const QStringList newLines = text.split(QLatin1Char('\n'));
    for (int line = 0; line < newLines.count(); ++line) {
        const int startPos = line > 0
                ? -1
                : lines->isEmpty() ? 0 : lines->last().text.count();
        handleLine(newLines, line, lines, lineNumber);
        const int endPos = line < newLines.count() - 1
                ? -1
                : lines->isEmpty() ? 0 : lines->last().text.count();
        if (!lines->isEmpty())
            lines->last().changedPositions.insert(startPos, endPos);
    }
}

/*
 * leftDiffList can contain only deletions and equalities,
 * while rightDiffList can contain only insertions and equalities.
 * The number of equalities on both lists must be the same.
*/
ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
                                const QList<Diff> &rightDiffList)
{
    ChunkData chunkData;

    int i = 0;
    int j = 0;

    QList<TextLineData> leftLines;
    QList<TextLineData> rightLines;

    // <line number, span count>
    QMap<int, int> leftSpans;
    QMap<int, int> rightSpans;
    // <left line number, right line number>
    QMap<int, int> equalLines;

    int leftLineNumber = 0;
    int rightLineNumber = 0;
    int leftLineAligned = -1;
    int rightLineAligned = -1;
    bool lastLineEqual = true;

    while (i <= leftDiffList.count() && j <= rightDiffList.count()) {
        const Diff leftDiff = i < leftDiffList.count()
                ? leftDiffList.at(i)
                : Diff(Diff::Equal);
        const Diff rightDiff = j < rightDiffList.count()
                ? rightDiffList.at(j)
                : Diff(Diff::Equal);

        if (leftDiff.command == Diff::Delete) {
            // process delete
            handleDifference(leftDiff.text, &leftLines, &leftLineNumber);
            lastLineEqual = lastLinesEqual(leftLines, rightLines);
            i++;
        }
        if (rightDiff.command == Diff::Insert) {
            // process insert
            handleDifference(rightDiff.text, &rightLines, &rightLineNumber);
            lastLineEqual = lastLinesEqual(leftLines, rightLines);
            j++;
        }
        if (leftDiff.command == Diff::Equal && rightDiff.command == Diff::Equal) {
            // process equal
            const QStringList newLeftLines = leftDiff.text.split(QLatin1Char('\n'));
            const QStringList newRightLines = rightDiff.text.split(QLatin1Char('\n'));

            int line = 0;

            while (line < qMax(newLeftLines.count(), newRightLines.count())) {
                handleLine(newLeftLines, line, &leftLines, &leftLineNumber);
                handleLine(newRightLines, line, &rightLines, &rightLineNumber);

                const int commonLineCount = qMin(newLeftLines.count(), newRightLines.count());
                if (line < commonLineCount) {
                    // try to align
                    const int leftDifference = leftLineNumber - leftLineAligned;
                    const int rightDifference = rightLineNumber - rightLineAligned;

                    if (leftDifference && rightDifference) {
                        bool doAlign = true;
                        if (line == 0 // omit alignment when first lines of equalities are empty and last generated lines are not equal
                                && (newLeftLines.at(0).isEmpty() || newRightLines.at(0).isEmpty())
                                && !lastLineEqual) {
                            doAlign = false;
                        }

                        if (line == commonLineCount - 1) {
                            // omit alignment when last lines of equalities are empty
                            if (leftLines.last().text.isEmpty() || rightLines.last().text.isEmpty())
                                doAlign = false;

                            // unless it's the last dummy line (don't omit in that case)
                            if (i == leftDiffList.count() && j == rightDiffList.count())
                                doAlign = true;
                        }

                        if (doAlign) {
                            // align here
                            leftLineAligned = leftLineNumber;
                            rightLineAligned = rightLineNumber;

                            // insert separators if needed
                            if (rightDifference > leftDifference)
                                leftSpans.insert(leftLineNumber, rightDifference - leftDifference);
                            else if (leftDifference > rightDifference)
                                rightSpans.insert(rightLineNumber, leftDifference - rightDifference);
                        }
                    }
                }

                // check if lines are equal
                if ((line < commonLineCount - 1) // before the last common line in equality
                        || (line == commonLineCount - 1 // or the last common line in equality
                            && i == leftDiffList.count() // and it's the last iteration
                            && j == rightDiffList.count())) {
                    if (line > 0 || lastLineEqual)
                        equalLines.insert(leftLineNumber, rightLineNumber);
                }

                if (line > 0)
                    lastLineEqual = true;

                line++;
            }
            i++;
            j++;
        }
    }

    QList<TextLineData> leftData = assemblyRows(leftLines,
                                                leftSpans);
    QList<TextLineData> rightData = assemblyRows(rightLines,
                                                 rightSpans);

    // fill ending separators
    for (int i = leftData.count(); i < rightData.count(); i++)
        leftData.append(TextLineData(TextLineData::Separator));
    for (int i = rightData.count(); i < leftData.count(); i++)
        rightData.append(TextLineData(TextLineData::Separator));

    const int visualLineCount = leftData.count();
    int leftLine = -1;
    int rightLine = -1;
    for (int i = 0; i < visualLineCount; i++) {
        const TextLineData &leftTextLine = leftData.at(i);
        const TextLineData &rightTextLine = rightData.at(i);
        RowData row(leftTextLine, rightTextLine);

        if (leftTextLine.textLineType == TextLineData::TextLine)
            ++leftLine;
        if (rightTextLine.textLineType == TextLineData::TextLine)
            ++rightLine;
        if (equalLines.value(leftLine, -2) == rightLine)
            row.equal = true;

        chunkData.rows.append(row);
    }
    return chunkData;
}

FileData calculateContextData(const ChunkData &originalData, int contextLinesNumber)
{
    if (contextLinesNumber < 0)
        return FileData(originalData);

    const int joinChunkThreshold = 1;

    FileData fileData;
    QMap<int, bool> hiddenRows;
    int i = 0;
    while (i < originalData.rows.count()) {
        const RowData &row = originalData.rows[i];
        if (row.equal) {
            // count how many equal
            int equalRowStart = i;
            i++;
            while (i < originalData.rows.count()) {
                const RowData originalRow = originalData.rows.at(i);
                if (!originalRow.equal)
                    break;
                i++;
            }
            const bool first = equalRowStart == 0; // includes first line?
            const bool last = i == originalData.rows.count(); // includes last line?

            const int firstLine = first ? 0 : equalRowStart + contextLinesNumber;
            const int lastLine = last ? originalData.rows.count() : i - contextLinesNumber;

            if (firstLine < lastLine - joinChunkThreshold) {
                for (int j = firstLine; j < lastLine; j++) {
                    hiddenRows.insert(j, true);
                }
            }
        } else {
            // iterate to the next row
            i++;
        }
    }
    i = 0;
    while (i < originalData.rows.count()) {
        const bool contextChunk = hiddenRows.contains(i);
        ChunkData chunkData;
        chunkData.contextChunk = contextChunk;
        while (i < originalData.rows.count()) {
            if (contextChunk != hiddenRows.contains(i))
                break;
            RowData rowData = originalData.rows.at(i);
            chunkData.rows.append(rowData);
            ++i;
        }
        fileData.chunks.append(chunkData);
    }

    return fileData;
}

void addChangedPositions(int positionOffset, const QMap<int, int> &originalChangedPositions, QMap<int, int> *changedPositions)
{
    QMapIterator<int, int> it(originalChangedPositions);
    while (it.hasNext()) {
        it.next();
        const int startPos = it.key();
        const int endPos = it.value();
        const int newStartPos = startPos < 0 ? -1 : startPos + positionOffset;
        const int newEndPos = endPos < 0 ? -1 : endPos + positionOffset;
        if (startPos < 0 && !changedPositions->isEmpty())
            changedPositions->insert(changedPositions->lastKey(), newEndPos);
        else
            changedPositions->insert(newStartPos, newEndPos);
    }
}

QList<QTextEdit::ExtraSelection> colorPositions(
        const QTextCharFormat &format,
        QTextCursor &cursor,
        const QMap<int, int> &positions)
{
    QList<QTextEdit::ExtraSelection> lineSelections;

    cursor.setPosition(0);
    QMapIterator<int, int> itPositions(positions);
    while (itPositions.hasNext()) {
        itPositions.next();

        cursor.setPosition(itPositions.key());
        cursor.setPosition(itPositions.value(), QTextCursor::KeepAnchor);

        QTextEdit::ExtraSelection selection;
        selection.cursor = cursor;
        selection.format = format;
        lineSelections.append(selection);
    }
    return lineSelections;
}

QTextCharFormat fullWidthFormatForTextStyle(const TextEditor::FontSettings &fontSettings,
                                            TextEditor::TextStyle textStyle)
{
    QTextCharFormat format = fontSettings.toTextCharFormat(textStyle);
    format.setProperty(QTextFormat::FullWidthSelection, true);
    return format;
}

} // namespace Internal
} // namespace DiffEditor
<commit_msg>Diff Editor: Fix compilation with Qt < 5.2.<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "diffutils.h"
#include "differ.h"
#include <QStringList>
#include "texteditor/fontsettings.h"

namespace DiffEditor {
namespace Internal {

static QList<TextLineData> assemblyRows(const QList<TextLineData> &lines,
                                        const QMap<int, int> &lineSpans)
{
    QList<TextLineData> data;

    const int lineCount = lines.count();
    for (int i = 0; i <= lineCount; i++) {
        for (int j = 0; j < lineSpans.value(i); j++)
            data.append(TextLineData(TextLineData::Separator));
        if (i < lineCount)
            data.append(lines.at(i));
    }
    return data;
}

static bool lastLinesEqual(const QList<TextLineData> &leftLines,
                           const QList<TextLineData> &rightLines)
{
    const bool leftLineEqual = leftLines.count()
            ? leftLines.last().text.isEmpty()
            : true;
    const bool rightLineEqual = rightLines.count()
            ? rightLines.last().text.isEmpty()
            : true;
    return leftLineEqual && rightLineEqual;
}

static void handleLine(const QStringList &newLines,
                       int line,
                       QList<TextLineData> *lines,
                       int *lineNumber)
{
    if (line < newLines.count()) {
        const QString text = newLines.at(line);
        if (lines->isEmpty() || line > 0) {
            if (line > 0)
                ++*lineNumber;
            lines->append(TextLineData(text));
        } else {
            lines->last().text += text;
        }
    }
}

static void handleDifference(const QString &text,
                             QList<TextLineData> *lines,
                             int *lineNumber)
{
    const QStringList newLines = text.split(QLatin1Char('\n'));
    for (int line = 0; line < newLines.count(); ++line) {
        const int startPos = line > 0
                ? -1
                : lines->isEmpty() ? 0 : lines->last().text.count();
        handleLine(newLines, line, lines, lineNumber);
        const int endPos = line < newLines.count() - 1
                ? -1
                : lines->isEmpty() ? 0 : lines->last().text.count();
        if (!lines->isEmpty())
            lines->last().changedPositions.insert(startPos, endPos);
    }
}

/*
 * leftDiffList can contain only deletions and equalities,
 * while rightDiffList can contain only insertions and equalities.
 * The number of equalities on both lists must be the same.
*/
ChunkData calculateOriginalData(const QList<Diff> &leftDiffList,
                                const QList<Diff> &rightDiffList)
{
    ChunkData chunkData;

    int i = 0;
    int j = 0;

    QList<TextLineData> leftLines;
    QList<TextLineData> rightLines;

    // <line number, span count>
    QMap<int, int> leftSpans;
    QMap<int, int> rightSpans;
    // <left line number, right line number>
    QMap<int, int> equalLines;

    int leftLineNumber = 0;
    int rightLineNumber = 0;
    int leftLineAligned = -1;
    int rightLineAligned = -1;
    bool lastLineEqual = true;

    while (i <= leftDiffList.count() && j <= rightDiffList.count()) {
        const Diff leftDiff = i < leftDiffList.count()
                ? leftDiffList.at(i)
                : Diff(Diff::Equal);
        const Diff rightDiff = j < rightDiffList.count()
                ? rightDiffList.at(j)
                : Diff(Diff::Equal);

        if (leftDiff.command == Diff::Delete) {
            // process delete
            handleDifference(leftDiff.text, &leftLines, &leftLineNumber);
            lastLineEqual = lastLinesEqual(leftLines, rightLines);
            i++;
        }
        if (rightDiff.command == Diff::Insert) {
            // process insert
            handleDifference(rightDiff.text, &rightLines, &rightLineNumber);
            lastLineEqual = lastLinesEqual(leftLines, rightLines);
            j++;
        }
        if (leftDiff.command == Diff::Equal && rightDiff.command == Diff::Equal) {
            // process equal
            const QStringList newLeftLines = leftDiff.text.split(QLatin1Char('\n'));
            const QStringList newRightLines = rightDiff.text.split(QLatin1Char('\n'));

            int line = 0;

            while (line < qMax(newLeftLines.count(), newRightLines.count())) {
                handleLine(newLeftLines, line, &leftLines, &leftLineNumber);
                handleLine(newRightLines, line, &rightLines, &rightLineNumber);

                const int commonLineCount = qMin(newLeftLines.count(), newRightLines.count());
                if (line < commonLineCount) {
                    // try to align
                    const int leftDifference = leftLineNumber - leftLineAligned;
                    const int rightDifference = rightLineNumber - rightLineAligned;

                    if (leftDifference && rightDifference) {
                        bool doAlign = true;
                        if (line == 0 // omit alignment when first lines of equalities are empty and last generated lines are not equal
                                && (newLeftLines.at(0).isEmpty() || newRightLines.at(0).isEmpty())
                                && !lastLineEqual) {
                            doAlign = false;
                        }

                        if (line == commonLineCount - 1) {
                            // omit alignment when last lines of equalities are empty
                            if (leftLines.last().text.isEmpty() || rightLines.last().text.isEmpty())
                                doAlign = false;

                            // unless it's the last dummy line (don't omit in that case)
                            if (i == leftDiffList.count() && j == rightDiffList.count())
                                doAlign = true;
                        }

                        if (doAlign) {
                            // align here
                            leftLineAligned = leftLineNumber;
                            rightLineAligned = rightLineNumber;

                            // insert separators if needed
                            if (rightDifference > leftDifference)
                                leftSpans.insert(leftLineNumber, rightDifference - leftDifference);
                            else if (leftDifference > rightDifference)
                                rightSpans.insert(rightLineNumber, leftDifference - rightDifference);
                        }
                    }
                }

                // check if lines are equal
                if ((line < commonLineCount - 1) // before the last common line in equality
                        || (line == commonLineCount - 1 // or the last common line in equality
                            && i == leftDiffList.count() // and it's the last iteration
                            && j == rightDiffList.count())) {
                    if (line > 0 || lastLineEqual)
                        equalLines.insert(leftLineNumber, rightLineNumber);
                }

                if (line > 0)
                    lastLineEqual = true;

                line++;
            }
            i++;
            j++;
        }
    }

    QList<TextLineData> leftData = assemblyRows(leftLines,
                                                leftSpans);
    QList<TextLineData> rightData = assemblyRows(rightLines,
                                                 rightSpans);

    // fill ending separators
    for (int i = leftData.count(); i < rightData.count(); i++)
        leftData.append(TextLineData(TextLineData::Separator));
    for (int i = rightData.count(); i < leftData.count(); i++)
        rightData.append(TextLineData(TextLineData::Separator));

    const int visualLineCount = leftData.count();
    int leftLine = -1;
    int rightLine = -1;
    for (int i = 0; i < visualLineCount; i++) {
        const TextLineData &leftTextLine = leftData.at(i);
        const TextLineData &rightTextLine = rightData.at(i);
        RowData row(leftTextLine, rightTextLine);

        if (leftTextLine.textLineType == TextLineData::TextLine)
            ++leftLine;
        if (rightTextLine.textLineType == TextLineData::TextLine)
            ++rightLine;
        if (equalLines.value(leftLine, -2) == rightLine)
            row.equal = true;

        chunkData.rows.append(row);
    }
    return chunkData;
}

FileData calculateContextData(const ChunkData &originalData, int contextLinesNumber)
{
    if (contextLinesNumber < 0)
        return FileData(originalData);

    const int joinChunkThreshold = 1;

    FileData fileData;
    QMap<int, bool> hiddenRows;
    int i = 0;
    while (i < originalData.rows.count()) {
        const RowData &row = originalData.rows[i];
        if (row.equal) {
            // count how many equal
            int equalRowStart = i;
            i++;
            while (i < originalData.rows.count()) {
                const RowData originalRow = originalData.rows.at(i);
                if (!originalRow.equal)
                    break;
                i++;
            }
            const bool first = equalRowStart == 0; // includes first line?
            const bool last = i == originalData.rows.count(); // includes last line?

            const int firstLine = first ? 0 : equalRowStart + contextLinesNumber;
            const int lastLine = last ? originalData.rows.count() : i - contextLinesNumber;

            if (firstLine < lastLine - joinChunkThreshold) {
                for (int j = firstLine; j < lastLine; j++) {
                    hiddenRows.insert(j, true);
                }
            }
        } else {
            // iterate to the next row
            i++;
        }
    }
    i = 0;
    while (i < originalData.rows.count()) {
        const bool contextChunk = hiddenRows.contains(i);
        ChunkData chunkData;
        chunkData.contextChunk = contextChunk;
        while (i < originalData.rows.count()) {
            if (contextChunk != hiddenRows.contains(i))
                break;
            RowData rowData = originalData.rows.at(i);
            chunkData.rows.append(rowData);
            ++i;
        }
        fileData.chunks.append(chunkData);
    }

    return fileData;
}

void addChangedPositions(int positionOffset, const QMap<int, int> &originalChangedPositions, QMap<int, int> *changedPositions)
{
    QMapIterator<int, int> it(originalChangedPositions);
    while (it.hasNext()) {
        it.next();
        const int startPos = it.key();
        const int endPos = it.value();
        const int newStartPos = startPos < 0 ? -1 : startPos + positionOffset;
        const int newEndPos = endPos < 0 ? -1 : endPos + positionOffset;
        if (startPos < 0 && !changedPositions->isEmpty()) {
           QMap<int, int>::iterator last = changedPositions->end();
           --last;
           last.value() = newEndPos;
        } else
            changedPositions->insert(newStartPos, newEndPos);
    }
}

QList<QTextEdit::ExtraSelection> colorPositions(
        const QTextCharFormat &format,
        QTextCursor &cursor,
        const QMap<int, int> &positions)
{
    QList<QTextEdit::ExtraSelection> lineSelections;

    cursor.setPosition(0);
    QMapIterator<int, int> itPositions(positions);
    while (itPositions.hasNext()) {
        itPositions.next();

        cursor.setPosition(itPositions.key());
        cursor.setPosition(itPositions.value(), QTextCursor::KeepAnchor);

        QTextEdit::ExtraSelection selection;
        selection.cursor = cursor;
        selection.format = format;
        lineSelections.append(selection);
    }
    return lineSelections;
}

QTextCharFormat fullWidthFormatForTextStyle(const TextEditor::FontSettings &fontSettings,
                                            TextEditor::TextStyle textStyle)
{
    QTextCharFormat format = fontSettings.toTextCharFormat(textStyle);
    format.setProperty(QTextFormat::FullWidthSelection, true);
    return format;
}

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


<commit_before>#include <ros/ros.h>
#include <boost/program_options.hpp>
#include "moveit_recorder/InteractiveRobot.h"

inline std::string get_option(const boost::program_options::variables_map& vm, const std::string& option, const std::string& default_str)
{
  return vm.count(option) ? vm[option].as<std::string>() : default_str;
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "start_marker");
  ros::NodeHandle node_handle;
  ros::AsyncSpinner spinner(1);
  spinner.start();

  boost::program_options::options_description desc;
  desc.add_options()
    ("help", "Show help message")
    ("robot_description", boost::program_options::value<std::string>(), "robot description param name")
    ("to_marker_topic", boost::program_options::value<std::string>(), "robot state topic FROM planning scene")
    ("from_marker_topic", boost::program_options::value<std::string>(), "robot state topic TO planning scene")
    ("from_marker_pose_topic", boost::program_options::value<std::string>(), "pose topic for robot end link pose")
    ("display_robot_topic", boost::program_options::value<std::string>(), "display robot state topic")
    ("robot_marker_topic", boost::program_options::value<std::string>(), "topic for robot visual markers")
    ("interactive_marker_topic", boost::program_options::value<std::string>(), "topic for interactive marker");

  boost::program_options::variables_map vm;
  boost::program_options::parsed_options po = boost::program_options::parse_command_line(argc, argv, desc);
  boost::program_options::store(po, vm);
  boost::program_options::notify(vm);

  if (vm.count("help")) // show help if no parameters passed
  {
    std::cout << desc << std::endl;
    return 1;
  }
  try
  {
    std::string robot_description = get_option(vm, "robot_description", "robot_description");
    std::string to_marker_topic = get_option(vm, "to_marker_topic", "to_marker_state");
    std::string from_marker_topic = get_option(vm, "from_marker_topic", "from_marker_state");
    std::string from_marker_pose_topic = get_option(vm, "from_marker_pose_topic", "from_marker_pose");
    std::string display_robot_topic = get_option(vm, "display_robot_topic", "interactive_robot_state");
    std::string robot_marker_topic = get_option(vm, "robot_marker_topic", "interactive_robot_markers");
    std::string interactive_marker_topic = get_option(vm, "interactive_marker_topic", "interactive_robot_imarkers");

    InteractiveRobot robot( robot_description,
                            to_marker_topic,
                            from_marker_topic,
                            from_marker_pose_topic,
                            display_robot_topic,
                            robot_marker_topic,
                            interactive_marker_topic);
    ros::spin();
  }
  catch(...)
  {

  }

  ros::shutdown();
  return 0;
}
<commit_msg>added arg for loading the right arm<commit_after>#include <ros/ros.h>
#include <boost/program_options.hpp>
#include "moveit_recorder/InteractiveRobot.h"

inline std::string get_option(const boost::program_options::variables_map& vm, const std::string& option, const std::string& default_str)
{
  return vm.count(option) ? vm[option].as<std::string>() : default_str;
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "start_marker");
  ros::NodeHandle node_handle;
  ros::AsyncSpinner spinner(1);
  spinner.start();

  sleep(20);

  boost::program_options::options_description desc;
  desc.add_options()
    ("help", "Show help message")
    ("robot_description", boost::program_options::value<std::string>(), "robot description param name")
    ("to_marker_topic", boost::program_options::value<std::string>(), "robot state topic FROM planning scene")
    ("from_marker_topic", boost::program_options::value<std::string>(), "robot state topic TO planning scene")
    ("from_marker_pose_topic", boost::program_options::value<std::string>(), "pose topic for robot end link pose")
    ("display_robot_topic", boost::program_options::value<std::string>(), "display robot state topic")
    ("robot_marker_topic", boost::program_options::value<std::string>(), "topic for robot visual markers")
    ("interactive_marker_topic", boost::program_options::value<std::string>(), "topic for interactive marker");

  boost::program_options::variables_map vm;
  boost::program_options::parsed_options po = boost::program_options::parse_command_line(argc, argv, desc);
  boost::program_options::store(po, vm);
  boost::program_options::notify(vm);

  if (vm.count("help")) // show help if no parameters passed
  {
    std::cout << desc << std::endl;
    return 1;
  }
  try
  {
    std::string robot_description = get_option(vm, "robot_description", "robot_description");
    std::string to_marker_topic = get_option(vm, "to_marker_topic", "to_marker_state");
    std::string from_marker_topic = get_option(vm, "from_marker_topic", "from_marker_state");
    std::string from_marker_pose_topic = get_option(vm, "from_marker_pose_topic", "from_marker_pose");
    std::string display_robot_topic = get_option(vm, "display_robot_topic", "interactive_robot_state");
    std::string robot_marker_topic = get_option(vm, "robot_marker_topic", "interactive_robot_markers");
    std::string interactive_marker_topic = get_option(vm, "interactive_marker_topic", "interactive_robot_imarkers");

    InteractiveRobot robot( robot_description,
                            to_marker_topic,
                            from_marker_topic,
                            from_marker_pose_topic,
                            display_robot_topic,
                            robot_marker_topic,
                            interactive_marker_topic,
                            "right_arm");
    ros::spin();
  }
  catch(...)
  {

  }

  ros::shutdown();
  return 0;
}
<|endoftext|>


<commit_before>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <DefaultFramebuffer.h>
#include <Renderer.h>
#include <MeshTools/Interleave.h>
#include <MeshTools/CompressIndices.h>
#include <Platform/GlutApplication.h>
#include <Primitives/Cube.h>
#include <Shaders/Phong.h>
#include <Trade/MeshData3D.h>

namespace Magnum { namespace Examples {

class PrimitivesExample: public Platform::GlutApplication {
    public:
        explicit PrimitivesExample(const Arguments& arguments);

        void viewportEvent(const Vector2i& size) override;
        void drawEvent() override;
        void mousePressEvent(MouseEvent& event) override;
        void mouseReleaseEvent(MouseEvent& event) override;
        void mouseMoveEvent(MouseMoveEvent& event) override;

    private:
        Buffer indexBuffer, vertexBuffer;
        Mesh mesh;
        Shaders::Phong shader;

        Matrix4 transformation, projection;
        Vector2i previousMousePosition;
        Color3 color;
};

PrimitivesExample::PrimitivesExample(const Arguments& arguments): Platform::GlutApplication(arguments, Configuration().setTitle("Primitives example")) {
    Renderer::setFeature(Renderer::Feature::DepthTest, true);
    Renderer::setFeature(Renderer::Feature::FaceCulling, true);

    Trade::MeshData3D cube = Primitives::Cube::solid();

    MeshTools::compressIndices(mesh, indexBuffer, Buffer::Usage::StaticDraw, cube.indices());

    MeshTools::interleave(mesh, vertexBuffer, Buffer::Usage::StaticDraw,
        cube.positions(0), cube.normals(0));
    mesh.setPrimitive(Mesh::Primitive::Triangles)
        .addInterleavedVertexBuffer(vertexBuffer, 0,
            Shaders::Phong::Position(), Shaders::Phong::Normal());

    transformation = Matrix4::rotationX(Deg(30.0f))*
                     Matrix4::rotationY(Deg(40.0f));
    color = Color3::fromHSV(Deg(35.0f), 1.0f, 1.0f);
}

void PrimitivesExample::viewportEvent(const Vector2i& size) {
    defaultFramebuffer.setViewport({{}, size});

    projection = Matrix4::perspectiveProjection(Deg(35.0f), Float(size.x())/size.y(), 0.01f, 100.0f)*
                 Matrix4::translation(Vector3::zAxis(-10.0f));
}

void PrimitivesExample::drawEvent() {
    defaultFramebuffer.bind(FramebufferTarget::Draw);
    defaultFramebuffer.clear(FramebufferClear::Color|FramebufferClear::Depth);

    shader.setLightPosition({7.0f, 5.0f, 2.5f})
        .setLightColor(Color3(1.0f))
        .setDiffuseColor(color)
        .setAmbientColor(Color3::fromHSV(color.hue(), 1.0f, 0.3f))
        .setTransformationMatrix(transformation)
        .setNormalMatrix(transformation.rotation())
        .setProjectionMatrix(projection)
        .use();
    mesh.draw();

    swapBuffers();
}

void PrimitivesExample::mousePressEvent(MouseEvent& event) {
    if(event.button() != MouseEvent::Button::Left) return;

    previousMousePosition = event.position();
    event.setAccepted();
}

void PrimitivesExample::mouseReleaseEvent(MouseEvent& event) {
    color = Color3::fromHSV(color.hue() + Deg(50.0), 1.0f, 1.0f);

    event.setAccepted();
    redraw();
}

void PrimitivesExample::mouseMoveEvent(MouseMoveEvent& event) {
    Vector2 delta = 3.0f*Vector2(event.position() - previousMousePosition)/defaultFramebuffer.viewport().size();
    transformation =
        Matrix4::rotationX(Rad(delta.y()))*
        transformation*
        Matrix4::rotationY(Rad(delta.x()));

    previousMousePosition = event.position();
    event.setAccepted();
    redraw();
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::PrimitivesExample)
<commit_msg>primitives: use non-asserting accessor.<commit_after>/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.
*/

#include <DefaultFramebuffer.h>
#include <Renderer.h>
#include <MeshTools/Interleave.h>
#include <MeshTools/CompressIndices.h>
#include <Platform/GlutApplication.h>
#include <Primitives/Cube.h>
#include <Shaders/Phong.h>
#include <Trade/MeshData3D.h>

namespace Magnum { namespace Examples {

class PrimitivesExample: public Platform::GlutApplication {
    public:
        explicit PrimitivesExample(const Arguments& arguments);

        void viewportEvent(const Vector2i& size) override;
        void drawEvent() override;
        void mousePressEvent(MouseEvent& event) override;
        void mouseReleaseEvent(MouseEvent& event) override;
        void mouseMoveEvent(MouseMoveEvent& event) override;

    private:
        Buffer indexBuffer, vertexBuffer;
        Mesh mesh;
        Shaders::Phong shader;

        Matrix4 transformation, projection;
        Vector2i previousMousePosition;
        Color3 color;
};

PrimitivesExample::PrimitivesExample(const Arguments& arguments): Platform::GlutApplication(arguments, Configuration().setTitle("Primitives example")) {
    Renderer::setFeature(Renderer::Feature::DepthTest, true);
    Renderer::setFeature(Renderer::Feature::FaceCulling, true);

    Trade::MeshData3D cube = Primitives::Cube::solid();

    MeshTools::compressIndices(mesh, indexBuffer, Buffer::Usage::StaticDraw, cube.indices());

    MeshTools::interleave(mesh, vertexBuffer, Buffer::Usage::StaticDraw,
        cube.positions(0), cube.normals(0));
    mesh.setPrimitive(Mesh::Primitive::Triangles)
        .addInterleavedVertexBuffer(vertexBuffer, 0,
            Shaders::Phong::Position(), Shaders::Phong::Normal());

    transformation = Matrix4::rotationX(Deg(30.0f))*
                     Matrix4::rotationY(Deg(40.0f));
    color = Color3::fromHSV(Deg(35.0f), 1.0f, 1.0f);
}

void PrimitivesExample::viewportEvent(const Vector2i& size) {
    defaultFramebuffer.setViewport({{}, size});

    projection = Matrix4::perspectiveProjection(Deg(35.0f), Float(size.x())/size.y(), 0.01f, 100.0f)*
                 Matrix4::translation(Vector3::zAxis(-10.0f));
}

void PrimitivesExample::drawEvent() {
    defaultFramebuffer.bind(FramebufferTarget::Draw);
    defaultFramebuffer.clear(FramebufferClear::Color|FramebufferClear::Depth);

    shader.setLightPosition({7.0f, 5.0f, 2.5f})
        .setLightColor(Color3(1.0f))
        .setDiffuseColor(color)
        .setAmbientColor(Color3::fromHSV(color.hue(), 1.0f, 0.3f))
        .setTransformationMatrix(transformation)
        .setNormalMatrix(transformation.rotationScaling()) /** @todo better solution? */
        .setProjectionMatrix(projection)
        .use();
    mesh.draw();

    swapBuffers();
}

void PrimitivesExample::mousePressEvent(MouseEvent& event) {
    if(event.button() != MouseEvent::Button::Left) return;

    previousMousePosition = event.position();
    event.setAccepted();
}

void PrimitivesExample::mouseReleaseEvent(MouseEvent& event) {
    color = Color3::fromHSV(color.hue() + Deg(50.0), 1.0f, 1.0f);

    event.setAccepted();
    redraw();
}

void PrimitivesExample::mouseMoveEvent(MouseMoveEvent& event) {
    Vector2 delta = 3.0f*Vector2(event.position() - previousMousePosition)/defaultFramebuffer.viewport().size();
    transformation =
        Matrix4::rotationX(Rad(delta.y()))*
        transformation*
        Matrix4::rotationY(Rad(delta.x()));

    previousMousePosition = event.position();
    event.setAccepted();
    redraw();
}

}}

MAGNUM_APPLICATION_MAIN(Magnum::Examples::PrimitivesExample)
<|endoftext|>


<commit_before>// Copyright (c) 2014-2019 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <consensus/validation.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <privatesend/privatesend-util.h>
#include <script/sign.h>
#include <validation.h>
#include <wallet/fees.h>

inline unsigned int GetSizeOfCompactSizeDiff(uint64_t nSizePrev, uint64_t nSizeNew)
{
    assert(nSizePrev <= nSizeNew);
    return ::GetSizeOfCompactSize(nSizeNew) - ::GetSizeOfCompactSize(nSizePrev);
}

CKeyHolder::CKeyHolder(CWallet* pwallet) :
    reserveKey(pwallet)
{
    reserveKey.GetReservedKey(pubKey, false);
}

void CKeyHolder::KeepKey()
{
    reserveKey.KeepKey();
}

void CKeyHolder::ReturnKey()
{
    reserveKey.ReturnKey();
}

CScript CKeyHolder::GetScriptForDestination() const
{
    return ::GetScriptForDestination(pubKey.GetID());
}

CScript CKeyHolderStorage::AddKey(CWallet* pwallet)
{
    auto keyHolderPtr = std::unique_ptr<CKeyHolder>(new CKeyHolder(pwallet));
    auto script = keyHolderPtr->GetScriptForDestination();

    LOCK(cs_storage);
    storage.emplace_back(std::move(keyHolderPtr));
    LogPrintf("CKeyHolderStorage::%s -- storage size %lld\n", __func__, storage.size());
    return script;
}

void CKeyHolderStorage::KeepAll()
{
    std::vector<std::unique_ptr<CKeyHolder> > tmp;
    {
        // don't hold cs_storage while calling KeepKey(), which might lock cs_wallet
        LOCK(cs_storage);
        std::swap(storage, tmp);
    }

    if (!tmp.empty()) {
        for (auto& key : tmp) {
            key->KeepKey();
        }
        LogPrintf("CKeyHolderStorage::%s -- %lld keys kept\n", __func__, tmp.size());
    }
}

void CKeyHolderStorage::ReturnAll()
{
    std::vector<std::unique_ptr<CKeyHolder> > tmp;
    {
        // don't hold cs_storage while calling ReturnKey(), which might lock cs_wallet
        LOCK(cs_storage);
        std::swap(storage, tmp);
    }

    if (!tmp.empty()) {
        for (auto& key : tmp) {
            key->ReturnKey();
        }
        LogPrintf("CKeyHolderStorage::%s -- %lld keys returned\n", __func__, tmp.size());
    }
}

CTransactionBuilderOutput::CTransactionBuilderOutput(CTransactionBuilder* pTxBuilderIn, CWallet* pwalletIn, CAmount nAmountIn) :
    pTxBuilder(pTxBuilderIn),
    key(pwalletIn),
    nAmount(nAmountIn)
{
    assert(pTxBuilder);
    CPubKey pubKey;
    key.GetReservedKey(pubKey, false);
    script = ::GetScriptForDestination(pubKey.GetID());
}

bool CTransactionBuilderOutput::UpdateAmount(const CAmount nNewAmount)
{
    LOCK(pTxBuilder->cs_outputs);
    if (nNewAmount <= 0 || nNewAmount - nAmount > pTxBuilder->GetAmountLeft()) {
        return false;
    }
    nAmount = nNewAmount;
    return true;
}

CTransactionBuilder::CTransactionBuilder(CWallet* pwalletIn, const CompactTallyItem& tallyItemIn) :
    pwallet(pwalletIn),
    dummyReserveKey(pwalletIn),
    tallyItem(tallyItemIn)
{
    // Generate a feerate which will be used to consider if the remainder is dust and will go into fees or not
    coinControl.m_discard_feerate = ::GetDiscardRate(::feeEstimator);
    // Generate a feerate which will be used by calculations of this class and also by CWallet::CreateTransaction
    coinControl.m_feerate = std::max(::feeEstimator.estimateSmartFee((int)::nTxConfirmTarget, nullptr, true), payTxFee);
    // Change always goes back to origin
    coinControl.destChange = tallyItemIn.txdest;
    // Only allow tallyItems inputs for tx creation
    coinControl.fAllowOtherInputs = false;
    // Select all tallyItem outputs in the coinControl so that CreateTransaction knows what to use
    for (const auto& outpoint : tallyItem.vecOutPoints) {
        coinControl.Select(outpoint);
    }
    // Create dummy tx to calculate the exact required fees upfront for accurate amount and fee calculations
    CMutableTransaction dummyTx;
    // Get a comparable dummy scriptPubKey
    CTransactionBuilderOutput dummyOutput(this, pwallet, 0);
    CScript dummyScript = dummyOutput.GetScript();
    dummyOutput.ReturnKey();
    // And create dummy signatures for all inputs
    SignatureData dummySignature;
    ProduceSignature(DummySignatureCreator(pwallet), dummyScript, dummySignature);
    for (auto out : tallyItem.vecOutPoints) {
        dummyTx.vin.emplace_back(out, dummySignature.scriptSig);
    }
    // Calculate required bytes for the dummy tx with tallyItem's inputs only
    nBytesBase = ::GetSerializeSize(dummyTx, SER_NETWORK, PROTOCOL_VERSION);
    // Calculate the output size
    nBytesOutput = ::GetSerializeSize(CTxOut(0, dummyScript), SER_NETWORK, PROTOCOL_VERSION);
    // Just to make sure..
    Clear();
}

CTransactionBuilder::~CTransactionBuilder()
{
    Clear();
}

void CTransactionBuilder::Clear()
{
    std::vector<std::unique_ptr<CTransactionBuilderOutput>> vecOutputsTmp;
    {
        // Don't hold cs_outputs while clearing the outputs which might indirectly call lock cs_wallet
        LOCK(cs_outputs);
        std::swap(vecOutputs, vecOutputsTmp);
        vecOutputs.clear();
    }

    for (auto& key : vecOutputsTmp) {
        if (fKeepKeys) {
            key->KeepKey();
        } else {
            key->ReturnKey();
        }
    }
    // Always return this key just to make sure..
    dummyReserveKey.ReturnKey();
}

bool CTransactionBuilder::CouldAddOutput(CAmount nAmountOutput) const
{
    if (nAmountOutput < 0) {
        return false;
    }
    // Adding another output can change the serialized size of the vout size hence + GetSizeOfCompactSizeDiff()
    unsigned int nBytes = GetBytesTotal() + nBytesOutput + GetSizeOfCompactSizeDiff(1);
    return GetAmountLeft(GetAmountInitial(), GetAmountUsed() + nAmountOutput, GetFee(nBytes)) >= 0;
}

bool CTransactionBuilder::CouldAddOutputs(const std::vector<CAmount>& vecOutputAmounts) const
{
    CAmount nAmountAdditional{0};
    assert(vecOutputAmounts.size() < INT_MAX);
    int nBytesAdditional = nBytesOutput * (int)vecOutputAmounts.size();
    for (const auto nAmountOutput : vecOutputAmounts) {
        if (nAmountOutput < 0) {
            return false;
        }
        nAmountAdditional += nAmountOutput;
    }
    // Adding other outputs can change the serialized size of the vout size hence + GetSizeOfCompactSizeDiff()
    unsigned int nBytes = GetBytesTotal() + nBytesAdditional + GetSizeOfCompactSizeDiff(vecOutputAmounts.size());
    return GetAmountLeft(GetAmountInitial(), GetAmountUsed() + nAmountAdditional, GetFee(nBytes)) >= 0;
}

CTransactionBuilderOutput* CTransactionBuilder::AddOutput(CAmount nAmountOutput)
{
    LOCK(cs_outputs);
    if (CouldAddOutput(nAmountOutput)) {
        vecOutputs.push_back(std::make_unique<CTransactionBuilderOutput>(this, pwallet, nAmountOutput));
        return vecOutputs.back().get();
    }
    return nullptr;
}

unsigned int CTransactionBuilder::GetBytesTotal() const
{
    // Adding other outputs can change the serialized size of the vout size hence + GetSizeOfCompactSizeDiff()
    return nBytesBase + vecOutputs.size() * nBytesOutput + ::GetSizeOfCompactSizeDiff(0, vecOutputs.size());
}

CAmount CTransactionBuilder::GetAmountLeft(const CAmount nAmountInitial, const CAmount nAmountUsed, const CAmount nFee)
{
    return nAmountInitial - nAmountUsed - nFee;
}

CAmount CTransactionBuilder::GetAmountUsed() const
{
    CAmount nAmountUsed{0};
    for (const auto& out : vecOutputs) {
        nAmountUsed += out->GetAmount();
    }
    return nAmountUsed;
}

CAmount CTransactionBuilder::GetFee(unsigned int nBytes) const
{
    CAmount nFeeCalc = coinControl.m_feerate->GetFee(nBytes);
    CAmount nRequiredFee = GetRequiredFee(nBytes);
    if (nRequiredFee > nFeeCalc) {
        nFeeCalc = nRequiredFee;
    }
    if (nFeeCalc > ::maxTxFee) {
        nFeeCalc = ::maxTxFee;
    }
    return nFeeCalc;
}

int CTransactionBuilder::GetSizeOfCompactSizeDiff(size_t nAdd) const
{
    size_t nSize = vecOutputs.size();
    unsigned int ret = ::GetSizeOfCompactSizeDiff(nSize, nSize + nAdd);
    assert(ret <= INT_MAX);
    return (int)ret;
}

bool CTransactionBuilder::IsDust(CAmount nAmount) const
{
    return ::IsDust(CTxOut(nAmount, ::GetScriptForDestination(tallyItem.txdest)), coinControl.m_discard_feerate.get());
}

bool CTransactionBuilder::Commit(std::string& strResult)
{
    CAmount nFeeRet = 0;
    int nChangePosRet = -1;

    // Transform the outputs to the format CWallet::CreateTransaction requires
    std::vector<CRecipient> vecSend;
    {
        LOCK(cs_outputs);
        vecSend.reserve(vecOutputs.size());
        for (const auto& out : vecOutputs) {
            vecSend.push_back((CRecipient){out->GetScript(), out->GetAmount(), false});
        }
    }

    CTransactionRef tx;
    if (!pwallet->CreateTransaction(vecSend, tx, dummyReserveKey, nFeeRet, nChangePosRet, strResult, coinControl)) {
        return false;
    }

    CAmount nAmountLeft = GetAmountLeft();
    bool fDust = IsDust(nAmountLeft);
    // If there is a either remainder which is considered to be dust (will be added to fee in this case) or no amount left there should be no change output, return if there is a change output.
    if (nChangePosRet != -1 && fDust) {
        strResult = strprintf("Unexpected change output %s at position %d", tx->vout[nChangePosRet].ToString(), nChangePosRet);
        return false;
    }

    // If there is a remainder which is not considered to be dust it should end up in a change output, return if not.
    if (nChangePosRet == -1 && !fDust) {
        strResult = strprintf("Change output missing: %d", nAmountLeft);
        return false;
    }

    CAmount nFeeAdditional{0};
    unsigned int nBytesAdditional{0};

    if (fDust) {
        nFeeAdditional = nAmountLeft;
    } else {
        // Add a change output and GetSizeOfCompactSizeDiff(1) as another output can changes the serialized size of the vout size in CTransaction
        nBytesAdditional = nBytesOutput + GetSizeOfCompactSizeDiff(1);
    }

    // If the calculated fee does not match the fee returned by CreateTransaction aka if this check fails something is wrong!
    CAmount nFeeCalc = GetFee(GetBytesTotal() + nBytesAdditional) + nFeeAdditional;
    if (nFeeRet != nFeeCalc) {
        strResult = strprintf("Fee validation failed -> nFeeRet: %d, nFeeCalc: %d, nFeeAdditional: %d, nBytesAdditional: %d, %s", nFeeRet, nFeeCalc, nFeeAdditional, nBytesAdditional, ToString());
        return false;
    }

    CValidationState state;
    if (!pwallet->CommitTransaction(tx, {}, {}, {}, dummyReserveKey, g_connman.get(), state)) {
        strResult = state.GetRejectReason();
        return false;
    }

    fKeepKeys = true;

    strResult = tx->GetHash().ToString();

    return true;
}

std::string CTransactionBuilder::ToString() const
{
    return strprintf("CTransactionBuilder(Amount initial: %d, Amount left: %d, Bytes base: %d, Bytes output: %d, Bytes total: %d, Amount used: %d, Outputs: %d, Fee rate: %d, Discard fee rate: %d, Fee: %d)",
        GetAmountInitial(),
        GetAmountLeft(),
        nBytesBase,
        nBytesOutput,
        GetBytesTotal(),
        GetAmountUsed(),
        CountOutputs(),
        coinControl.m_feerate->GetFeePerK(),
        coinControl.m_discard_feerate->GetFeePerK(),
        GetFee(GetBytesTotal()));
}
<commit_msg>privatesend: Avoid interacting with keypool in CTransactionBuilder ctor (#3723)<commit_after>// Copyright (c) 2014-2019 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <consensus/validation.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <privatesend/privatesend-util.h>
#include <script/sign.h>
#include <validation.h>
#include <wallet/fees.h>

inline unsigned int GetSizeOfCompactSizeDiff(uint64_t nSizePrev, uint64_t nSizeNew)
{
    assert(nSizePrev <= nSizeNew);
    return ::GetSizeOfCompactSize(nSizeNew) - ::GetSizeOfCompactSize(nSizePrev);
}

CKeyHolder::CKeyHolder(CWallet* pwallet) :
    reserveKey(pwallet)
{
    reserveKey.GetReservedKey(pubKey, false);
}

void CKeyHolder::KeepKey()
{
    reserveKey.KeepKey();
}

void CKeyHolder::ReturnKey()
{
    reserveKey.ReturnKey();
}

CScript CKeyHolder::GetScriptForDestination() const
{
    return ::GetScriptForDestination(pubKey.GetID());
}

CScript CKeyHolderStorage::AddKey(CWallet* pwallet)
{
    auto keyHolderPtr = std::unique_ptr<CKeyHolder>(new CKeyHolder(pwallet));
    auto script = keyHolderPtr->GetScriptForDestination();

    LOCK(cs_storage);
    storage.emplace_back(std::move(keyHolderPtr));
    LogPrintf("CKeyHolderStorage::%s -- storage size %lld\n", __func__, storage.size());
    return script;
}

void CKeyHolderStorage::KeepAll()
{
    std::vector<std::unique_ptr<CKeyHolder> > tmp;
    {
        // don't hold cs_storage while calling KeepKey(), which might lock cs_wallet
        LOCK(cs_storage);
        std::swap(storage, tmp);
    }

    if (!tmp.empty()) {
        for (auto& key : tmp) {
            key->KeepKey();
        }
        LogPrintf("CKeyHolderStorage::%s -- %lld keys kept\n", __func__, tmp.size());
    }
}

void CKeyHolderStorage::ReturnAll()
{
    std::vector<std::unique_ptr<CKeyHolder> > tmp;
    {
        // don't hold cs_storage while calling ReturnKey(), which might lock cs_wallet
        LOCK(cs_storage);
        std::swap(storage, tmp);
    }

    if (!tmp.empty()) {
        for (auto& key : tmp) {
            key->ReturnKey();
        }
        LogPrintf("CKeyHolderStorage::%s -- %lld keys returned\n", __func__, tmp.size());
    }
}

CTransactionBuilderOutput::CTransactionBuilderOutput(CTransactionBuilder* pTxBuilderIn, CWallet* pwalletIn, CAmount nAmountIn) :
    pTxBuilder(pTxBuilderIn),
    key(pwalletIn),
    nAmount(nAmountIn)
{
    assert(pTxBuilder);
    CPubKey pubKey;
    key.GetReservedKey(pubKey, false);
    script = ::GetScriptForDestination(pubKey.GetID());
}

bool CTransactionBuilderOutput::UpdateAmount(const CAmount nNewAmount)
{
    LOCK(pTxBuilder->cs_outputs);
    if (nNewAmount <= 0 || nNewAmount - nAmount > pTxBuilder->GetAmountLeft()) {
        return false;
    }
    nAmount = nNewAmount;
    return true;
}

CTransactionBuilder::CTransactionBuilder(CWallet* pwalletIn, const CompactTallyItem& tallyItemIn) :
    pwallet(pwalletIn),
    dummyReserveKey(pwalletIn),
    tallyItem(tallyItemIn)
{
    // Generate a feerate which will be used to consider if the remainder is dust and will go into fees or not
    coinControl.m_discard_feerate = ::GetDiscardRate(::feeEstimator);
    // Generate a feerate which will be used by calculations of this class and also by CWallet::CreateTransaction
    coinControl.m_feerate = std::max(::feeEstimator.estimateSmartFee((int)::nTxConfirmTarget, nullptr, true), payTxFee);
    // Change always goes back to origin
    coinControl.destChange = tallyItemIn.txdest;
    // Only allow tallyItems inputs for tx creation
    coinControl.fAllowOtherInputs = false;
    // Select all tallyItem outputs in the coinControl so that CreateTransaction knows what to use
    for (const auto& outpoint : tallyItem.vecOutPoints) {
        coinControl.Select(outpoint);
    }
    // Create dummy tx to calculate the exact required fees upfront for accurate amount and fee calculations
    CMutableTransaction dummyTx;
    // Get a comparable dummy scriptPubKey, avoid writting/flushing to the actual wallet db
    CScript dummyScript;
    {
        LOCK(pwallet->cs_wallet);
        WalletBatch dummyBatch(pwallet->GetDBHandle(), "r+", false);
        dummyBatch.TxnBegin();
        CPubKey dummyPubkey = pwallet->GenerateNewKey(dummyBatch, 0, false);
        dummyBatch.TxnAbort();
        dummyScript = ::GetScriptForDestination(dummyPubkey.GetID());
    }
    // Create dummy signatures for all inputs
    SignatureData dummySignature;
    ProduceSignature(DummySignatureCreator(pwallet), dummyScript, dummySignature);
    for (auto out : tallyItem.vecOutPoints) {
        dummyTx.vin.emplace_back(out, dummySignature.scriptSig);
    }
    // Calculate required bytes for the dummy tx with tallyItem's inputs only
    nBytesBase = ::GetSerializeSize(dummyTx, SER_NETWORK, PROTOCOL_VERSION);
    // Calculate the output size
    nBytesOutput = ::GetSerializeSize(CTxOut(0, dummyScript), SER_NETWORK, PROTOCOL_VERSION);
    // Just to make sure..
    Clear();
}

CTransactionBuilder::~CTransactionBuilder()
{
    Clear();
}

void CTransactionBuilder::Clear()
{
    std::vector<std::unique_ptr<CTransactionBuilderOutput>> vecOutputsTmp;
    {
        // Don't hold cs_outputs while clearing the outputs which might indirectly call lock cs_wallet
        LOCK(cs_outputs);
        std::swap(vecOutputs, vecOutputsTmp);
        vecOutputs.clear();
    }

    for (auto& key : vecOutputsTmp) {
        if (fKeepKeys) {
            key->KeepKey();
        } else {
            key->ReturnKey();
        }
    }
    // Always return this key just to make sure..
    dummyReserveKey.ReturnKey();
}

bool CTransactionBuilder::CouldAddOutput(CAmount nAmountOutput) const
{
    if (nAmountOutput < 0) {
        return false;
    }
    // Adding another output can change the serialized size of the vout size hence + GetSizeOfCompactSizeDiff()
    unsigned int nBytes = GetBytesTotal() + nBytesOutput + GetSizeOfCompactSizeDiff(1);
    return GetAmountLeft(GetAmountInitial(), GetAmountUsed() + nAmountOutput, GetFee(nBytes)) >= 0;
}

bool CTransactionBuilder::CouldAddOutputs(const std::vector<CAmount>& vecOutputAmounts) const
{
    CAmount nAmountAdditional{0};
    assert(vecOutputAmounts.size() < INT_MAX);
    int nBytesAdditional = nBytesOutput * (int)vecOutputAmounts.size();
    for (const auto nAmountOutput : vecOutputAmounts) {
        if (nAmountOutput < 0) {
            return false;
        }
        nAmountAdditional += nAmountOutput;
    }
    // Adding other outputs can change the serialized size of the vout size hence + GetSizeOfCompactSizeDiff()
    unsigned int nBytes = GetBytesTotal() + nBytesAdditional + GetSizeOfCompactSizeDiff(vecOutputAmounts.size());
    return GetAmountLeft(GetAmountInitial(), GetAmountUsed() + nAmountAdditional, GetFee(nBytes)) >= 0;
}

CTransactionBuilderOutput* CTransactionBuilder::AddOutput(CAmount nAmountOutput)
{
    LOCK(cs_outputs);
    if (CouldAddOutput(nAmountOutput)) {
        vecOutputs.push_back(std::make_unique<CTransactionBuilderOutput>(this, pwallet, nAmountOutput));
        return vecOutputs.back().get();
    }
    return nullptr;
}

unsigned int CTransactionBuilder::GetBytesTotal() const
{
    // Adding other outputs can change the serialized size of the vout size hence + GetSizeOfCompactSizeDiff()
    return nBytesBase + vecOutputs.size() * nBytesOutput + ::GetSizeOfCompactSizeDiff(0, vecOutputs.size());
}

CAmount CTransactionBuilder::GetAmountLeft(const CAmount nAmountInitial, const CAmount nAmountUsed, const CAmount nFee)
{
    return nAmountInitial - nAmountUsed - nFee;
}

CAmount CTransactionBuilder::GetAmountUsed() const
{
    CAmount nAmountUsed{0};
    for (const auto& out : vecOutputs) {
        nAmountUsed += out->GetAmount();
    }
    return nAmountUsed;
}

CAmount CTransactionBuilder::GetFee(unsigned int nBytes) const
{
    CAmount nFeeCalc = coinControl.m_feerate->GetFee(nBytes);
    CAmount nRequiredFee = GetRequiredFee(nBytes);
    if (nRequiredFee > nFeeCalc) {
        nFeeCalc = nRequiredFee;
    }
    if (nFeeCalc > ::maxTxFee) {
        nFeeCalc = ::maxTxFee;
    }
    return nFeeCalc;
}

int CTransactionBuilder::GetSizeOfCompactSizeDiff(size_t nAdd) const
{
    size_t nSize = vecOutputs.size();
    unsigned int ret = ::GetSizeOfCompactSizeDiff(nSize, nSize + nAdd);
    assert(ret <= INT_MAX);
    return (int)ret;
}

bool CTransactionBuilder::IsDust(CAmount nAmount) const
{
    return ::IsDust(CTxOut(nAmount, ::GetScriptForDestination(tallyItem.txdest)), coinControl.m_discard_feerate.get());
}

bool CTransactionBuilder::Commit(std::string& strResult)
{
    CAmount nFeeRet = 0;
    int nChangePosRet = -1;

    // Transform the outputs to the format CWallet::CreateTransaction requires
    std::vector<CRecipient> vecSend;
    {
        LOCK(cs_outputs);
        vecSend.reserve(vecOutputs.size());
        for (const auto& out : vecOutputs) {
            vecSend.push_back((CRecipient){out->GetScript(), out->GetAmount(), false});
        }
    }

    CTransactionRef tx;
    if (!pwallet->CreateTransaction(vecSend, tx, dummyReserveKey, nFeeRet, nChangePosRet, strResult, coinControl)) {
        return false;
    }

    CAmount nAmountLeft = GetAmountLeft();
    bool fDust = IsDust(nAmountLeft);
    // If there is a either remainder which is considered to be dust (will be added to fee in this case) or no amount left there should be no change output, return if there is a change output.
    if (nChangePosRet != -1 && fDust) {
        strResult = strprintf("Unexpected change output %s at position %d", tx->vout[nChangePosRet].ToString(), nChangePosRet);
        return false;
    }

    // If there is a remainder which is not considered to be dust it should end up in a change output, return if not.
    if (nChangePosRet == -1 && !fDust) {
        strResult = strprintf("Change output missing: %d", nAmountLeft);
        return false;
    }

    CAmount nFeeAdditional{0};
    unsigned int nBytesAdditional{0};

    if (fDust) {
        nFeeAdditional = nAmountLeft;
    } else {
        // Add a change output and GetSizeOfCompactSizeDiff(1) as another output can changes the serialized size of the vout size in CTransaction
        nBytesAdditional = nBytesOutput + GetSizeOfCompactSizeDiff(1);
    }

    // If the calculated fee does not match the fee returned by CreateTransaction aka if this check fails something is wrong!
    CAmount nFeeCalc = GetFee(GetBytesTotal() + nBytesAdditional) + nFeeAdditional;
    if (nFeeRet != nFeeCalc) {
        strResult = strprintf("Fee validation failed -> nFeeRet: %d, nFeeCalc: %d, nFeeAdditional: %d, nBytesAdditional: %d, %s", nFeeRet, nFeeCalc, nFeeAdditional, nBytesAdditional, ToString());
        return false;
    }

    CValidationState state;
    if (!pwallet->CommitTransaction(tx, {}, {}, {}, dummyReserveKey, g_connman.get(), state)) {
        strResult = state.GetRejectReason();
        return false;
    }

    fKeepKeys = true;

    strResult = tx->GetHash().ToString();

    return true;
}

std::string CTransactionBuilder::ToString() const
{
    return strprintf("CTransactionBuilder(Amount initial: %d, Amount left: %d, Bytes base: %d, Bytes output: %d, Bytes total: %d, Amount used: %d, Outputs: %d, Fee rate: %d, Discard fee rate: %d, Fee: %d)",
        GetAmountInitial(),
        GetAmountLeft(),
        nBytesBase,
        nBytesOutput,
        GetBytesTotal(),
        GetAmountUsed(),
        CountOutputs(),
        coinControl.m_feerate->GetFeePerK(),
        coinControl.m_discard_feerate->GetFeePerK(),
        GetFee(GetBytesTotal()));
}
<|endoftext|>


<commit_before>#include <SFML/Graphics.hpp>
#include <SFML/System/Vector2.hpp>
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;

static const string textureNames[]{"spaceship1.png",
                                   "spaceship2.png",
                                   "spaceship3.png",
                                   "Spaceship-Drakir1.png",
                                   "Spaceship-Drakir2.png",
                                   "Spaceship-Drakir3.png",
                                   "Spaceship-Drakir4.png",
                                   "Spaceship-Drakir5.png",
                                   "Spaceship-Drakir6.png",
                                   "Spaceship-Drakir7.png",
                                   "bullet.png"};

static sf::Texture *textures[11];
static sf::Font myfont;
static const string filepath = "..\\res/img/";

#define MAX_ENEMIES 255
static unsigned int currentEnemies = 0;
static sf::Sprite enemies[MAX_ENEMIES];

float playerMoveSpeed = 600.0f;

static sf::Vector2f GetNewEnemyPos() {
  return sf::Vector2f(rand() % 1024, -128.0f);
}

sf::Sprite playerSprite;
sf::Texture *playerTexture;
sf::Sprite bulletsprite;
sf::Texture *bulletTexture;
sf::Text Text;
void Loadcontent() {

	myfont.loadFromFile("..\\res/fonts/AmericanCaptain.ttf");
	Text.setFont(myfont);
	Text.setPosition(900,0);
	Text.setCharacterSize(24);
	Text.setColor(sf::Color::Red);

  for (size_t i = 0; i < 11; i++) {
    textures[i] = new sf::Texture();
    if (!textures[i]->loadFromFile(filepath + textureNames[i])) {
      throw invalid_argument("Loading error!");
    }
  }

  playerSprite.setTexture(*textures[0]);
  playerSprite.setPosition(512, 256);
  bulletsprite.setTexture(*textures[10]);
  bulletsprite.setPosition(0, -128.0f);
  for (size_t i = 0; i < MAX_ENEMIES; i++) {
    enemies[i].setTexture(*textures[(i % 7) + 3]);
    enemies[i].setPosition(GetNewEnemyPos());
  }
}
void Normalize(sf::Vector2f &v) {
  auto length = sqrt(v.x * v.x + v.y * v.y);
  if (length == 0.0f) {
    return;
  }

  // normalize vector
  v.x /= length;
  v.y /= length;
}

static chrono::high_resolution_clock::time_point previous;
static unsigned int score = 0;

void Update(sf::RenderWindow &window) {

  chrono::high_resolution_clock::time_point now =
      chrono::high_resolution_clock::now();
  const unsigned int delta =
      (std::chrono::duration_cast<std::chrono::duration<int, std::nano>>(
           now - previous))
          .count();

  const double deltaPercent =
      (((double)delta) / 1000000000.0); // delta as a percentage of 1 second
  previous = now;
  static float tick = 0.0f;
  tick += deltaPercent;
  currentEnemies = (unsigned int)ceil(tick * 0.6f) + 1;

  //  cout << score << " - " << currentEnemies << " - " << delta << " - " <<
  //  deltaPercent << endl;

  sf::Event e;
  sf::Vector2f moveDirection(0, 0);

  while (window.pollEvent(e)) {

    if (e.type == sf::Event::Closed)
      window.close();

    // keyboard event handling
    if (e.type == sf::Event::KeyPressed) {
      if (e.key.code == sf::Keyboard::Escape) {
        window.close();
      }
      if (e.key.code == sf::Keyboard::W || e.key.code == sf::Keyboard::Up) {
        moveDirection += sf::Vector2f(0, -1);
      }
      if (e.key.code == sf::Keyboard::S || e.key.code == sf::Keyboard::Down) {
        moveDirection += sf::Vector2f(0, 1);
      }
      if (e.key.code == sf::Keyboard::A || e.key.code == sf::Keyboard::Left) {
        moveDirection += sf::Vector2f(-1, 0);
      }
      if (e.key.code == sf::Keyboard::D || e.key.code == sf::Keyboard::Right) {
        moveDirection += sf::Vector2f(1, 0);
      }
	  if (bulletsprite.getPosition().y <= -128.0f && e.key.code == sf::Keyboard::Space)
	  {
		  bulletsprite.setPosition(playerSprite.getPosition().x + 30,
			  playerSprite.getPosition().y - 1);
	  }
    }
    // if the B button is pressed fire a bullet
    if (e.JoystickButtonPressed) {

      if (bulletsprite.getPosition().y <= -128.0f &&
          sf::Joystick::isButtonPressed(0, 1)) {
        bulletsprite.setPosition(playerSprite.getPosition().x + 30,
                                 playerSprite.getPosition().y - 1);
      }
    }
  }

  // joystick input
  if (sf::Joystick::isConnected(0)) {
    float joystickX = sf::Joystick::getAxisPosition(0, sf::Joystick::X);
    float joystickY = sf::Joystick::getAxisPosition(0, sf::Joystick::Y);

    if (abs(joystickX) > 40.0f) {
      moveDirection += sf::Vector2f(((signbit(joystickX)) * -2) + 1, 0);
    }
    if (abs(joystickY) > 40.0f) {
      moveDirection += sf::Vector2f(0, ((signbit(joystickY)) * -2) + 1);
    }
  }

  Normalize(moveDirection);
  moveDirection = (moveDirection * playerMoveSpeed) * (float)deltaPercent;

  playerSprite.setPosition(playerSprite.getPosition() + moveDirection);

  if (bulletsprite.getPosition().y > -128.0f) {
    bulletsprite.setPosition(bulletsprite.getPosition().x,
                             bulletsprite.getPosition().y -
                                 1000.0 * deltaPercent);
  }

  for (size_t i = 0; i < MAX_ENEMIES; i++) {
    if (i < currentEnemies) {
      // if not dead, move
      if (enemies[i].getPosition().y < 700.0) {
        enemies[i].setPosition(
            enemies[i].getPosition() +
            sf::Vector2f(sinf(tick + i) * 100.0 * deltaPercent,
                         100.0 * deltaPercent));
        // collisions
        if (bulletsprite.getGlobalBounds().intersects(
                enemies[i].getGlobalBounds())) {
          enemies[i].setPosition(GetNewEnemyPos());
          score += 100;
        }
      } else {
        // offscreen kill
        enemies[i].setPosition(GetNewEnemyPos());
      }
    } else {
      // if alive
      if (enemies[i].getPosition().y != -128.0f) {
        // kill
        enemies[i].setPosition(GetNewEnemyPos());
      }
    }
  }

  Text.setString("Score =" + to_string(score + ceil(tick)));
}

void Render(sf::RenderWindow &window) {
  window.clear();
  window.draw(playerSprite);
  window.draw(bulletsprite);
  for (size_t i = 0; i < MAX_ENEMIES; i++) {
    window.draw(enemies[i]);
  }

  window.draw(Text);
  window.display();

}

int main() {
  Loadcontent();
  sf::RenderWindow window(sf::VideoMode(1024, 768), "Main Window");
  window.setVerticalSyncEnabled(true);
  previous = chrono::high_resolution_clock::now();
  while (window.isOpen()) {
    Update(window);
    Render(window);
  }
  return 0;
}<commit_msg>tracking enemies killed as they are being hit by the bullet before on screen<commit_after>#include <SFML/Graphics.hpp>
#include <SFML/System/Vector2.hpp>
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;

static const string textureNames[]{"spaceship1.png",
                                   "spaceship2.png",
                                   "spaceship3.png",
                                   "Spaceship-Drakir1.png",
                                   "Spaceship-Drakir2.png",
                                   "Spaceship-Drakir3.png",
                                   "Spaceship-Drakir4.png",
                                   "Spaceship-Drakir5.png",
                                   "Spaceship-Drakir6.png",
                                   "Spaceship-Drakir7.png",
                                   "bullet.png"};

static sf::Texture *textures[11];
static sf::Font myfont;
static const string filepath = "..\\res/img/";

#define MAX_ENEMIES 255
static unsigned int currentEnemies = 0;
static sf::Sprite enemies[MAX_ENEMIES];

float playerMoveSpeed = 600.0f;
 int killedeneimies = 0;
static sf::Vector2f GetNewEnemyPos() {
  return sf::Vector2f(rand() % 1024, -128.0f);
}

sf::Sprite playerSprite;
sf::Texture *playerTexture;
sf::Sprite bulletsprite;
sf::Texture *bulletTexture;
sf::Text Text;
void Loadcontent() {

	myfont.loadFromFile("..\\res/fonts/AmericanCaptain.ttf");
	Text.setFont(myfont);
	Text.setPosition(700,0);
	Text.setCharacterSize(24);
	Text.setColor(sf::Color::Red);

  for (size_t i = 0; i < 11; i++) {
    textures[i] = new sf::Texture();
    if (!textures[i]->loadFromFile(filepath + textureNames[i])) {
      throw invalid_argument("Loading error!");
    }
  }

  playerSprite.setTexture(*textures[0]);
  playerSprite.setPosition(512, 256);
  bulletsprite.setTexture(*textures[10]);
  bulletsprite.setPosition(0, -128.0f);
  for (size_t i = 0; i < MAX_ENEMIES; i++) {
    enemies[i].setTexture(*textures[(i % 7) + 3]);
    enemies[i].setPosition(GetNewEnemyPos());
  }
}
void Normalize(sf::Vector2f &v) {
  auto length = sqrt(v.x * v.x + v.y * v.y);
  if (length == 0.0f) {
    return;
  }

  // normalize vector
  v.x /= length;
  v.y /= length;
}

static chrono::high_resolution_clock::time_point previous;
static unsigned int score = 0;

void Update(sf::RenderWindow &window) {

  chrono::high_resolution_clock::time_point now =
      chrono::high_resolution_clock::now();
  const unsigned int delta =
      (std::chrono::duration_cast<std::chrono::duration<int, std::nano>>(
           now - previous))
          .count();

  const double deltaPercent =
      (((double)delta) / 1000000000.0); // delta as a percentage of 1 second
  previous = now;
  static float tick = 0.0f;
  tick += deltaPercent;
  currentEnemies = (unsigned int)ceil(tick * 0.6f) + 1;

  //  cout << score << " - " << currentEnemies << " - " << delta << " - " <<
  //  deltaPercent << endl;

  sf::Event e;
  sf::Vector2f moveDirection(0, 0);

  while (window.pollEvent(e)) {

    if (e.type == sf::Event::Closed)
      window.close();

    // keyboard event handling
    if (e.type == sf::Event::KeyPressed) {
      if (e.key.code == sf::Keyboard::Escape) {
        window.close();
      }
      if (e.key.code == sf::Keyboard::W || e.key.code == sf::Keyboard::Up) {
        moveDirection += sf::Vector2f(0, -1);
      }
      if (e.key.code == sf::Keyboard::S || e.key.code == sf::Keyboard::Down) {
        moveDirection += sf::Vector2f(0, 1);
      }
      if (e.key.code == sf::Keyboard::A || e.key.code == sf::Keyboard::Left) {
        moveDirection += sf::Vector2f(-1, 0);
      }
      if (e.key.code == sf::Keyboard::D || e.key.code == sf::Keyboard::Right) {
        moveDirection += sf::Vector2f(1, 0);
      }
	  if (bulletsprite.getPosition().y <= -128.0f && e.key.code == sf::Keyboard::Space)
	  {
		  bulletsprite.setPosition(playerSprite.getPosition().x + 30,
			  playerSprite.getPosition().y - 1);
	  }
    }
    // if the B button is pressed fire a bullet
    if (e.JoystickButtonPressed) {

      if (bulletsprite.getPosition().y <= -128.0f &&
          sf::Joystick::isButtonPressed(0, 1)) {
        bulletsprite.setPosition(playerSprite.getPosition().x + 30,
                                 playerSprite.getPosition().y - 1);
      }
    }
  }

  // joystick input
  if (sf::Joystick::isConnected(0)) {
    float joystickX = sf::Joystick::getAxisPosition(0, sf::Joystick::X);
    float joystickY = sf::Joystick::getAxisPosition(0, sf::Joystick::Y);

    if (abs(joystickX) > 40.0f) {
      moveDirection += sf::Vector2f(((signbit(joystickX)) * -2) + 1, 0);
    }
    if (abs(joystickY) > 40.0f) {
      moveDirection += sf::Vector2f(0, ((signbit(joystickY)) * -2) + 1);
    }
  }

  Normalize(moveDirection);
  moveDirection = (moveDirection * playerMoveSpeed) * (float)deltaPercent;

  playerSprite.setPosition(playerSprite.getPosition() + moveDirection);

  if (bulletsprite.getPosition().y > -128.0f) {
    bulletsprite.setPosition(bulletsprite.getPosition().x,
                             bulletsprite.getPosition().y -
                                 1000.0 * deltaPercent);
  }

  for (size_t i = 0; i < MAX_ENEMIES; i++) {
    if (i < currentEnemies) {
      // if not dead, move
      if (enemies[i].getPosition().y < 700.0) {
        enemies[i].setPosition(
            enemies[i].getPosition() +
            sf::Vector2f(sinf(tick + i) * 100.0 * deltaPercent,
                         100.0 * deltaPercent));
        // collisions
        if (bulletsprite.getGlobalBounds().intersects(
                enemies[i].getGlobalBounds())) {
          enemies[i].setPosition(GetNewEnemyPos());
          score += 100;
		  killedeneimies += 1;
        }
      } else {
        // offscreen kill
        enemies[i].setPosition(GetNewEnemyPos());
      }
    } else {
      // if alive
      if (enemies[i].getPosition().y != -128.0f) {
        // kill
        enemies[i].setPosition(GetNewEnemyPos());
      }
    }
  }

  Text.setString("Score =" + to_string(score + ceil(tick)) + "\n"  + "number of enemies destroyed =" + to_string(killedeneimies));
}

void Render(sf::RenderWindow &window) {
  window.clear();
  window.draw(playerSprite);
  window.draw(bulletsprite);
  for (size_t i = 0; i < MAX_ENEMIES; i++) {
    window.draw(enemies[i]);
  }

  window.draw(Text);
  window.display();

}

int main() {
  Loadcontent();
  sf::RenderWindow window(sf::VideoMode(1024, 768), "Main Window");
  window.setVerticalSyncEnabled(true);
  previous = chrono::high_resolution_clock::now();
  while (window.isOpen()) {

	Update(window);
    Render(window);
  }
  return 0;
}<|endoftext|>


<commit_before>#include "MemoryView.h"
#include "ui_MemoryView.h"
#include "Backend/IBackendRequests.h"

#include <QtCore/QDebug>
#include <QtCore/QMetaEnum>

namespace prodbg {

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

template <typename EnumType>
static void enumToCombo(QComboBox* combo, int startValue)
{
    QMetaEnum me = QMetaEnum::fromType<EnumType>();

    for (int i = 0; i < me.keyCount(); ++i) {
        combo->addItem(QString::fromUtf8(me.key(i)));
    }

    combo->setCurrentIndex(startValue);
}

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

MemoryView::MemoryView(QWidget* parent)
    : Base(parent)
    , m_Ui(new Ui_MemoryView)
{
    m_Ui->setupUi(this);

    connect(m_Ui->m_Address, &QLineEdit::returnPressed, this, &MemoryView::jumpAddressChanged);

    enumToCombo<MemoryViewWidget::Endianess>(m_Ui->m_Endianess, m_Ui->m_View->endianess());
    enumToCombo<MemoryViewWidget::DataType>(m_Ui->m_Type, m_Ui->m_View->dataType());

    connect(m_Ui->m_Endianess, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
            &MemoryView::endianChanged);
    connect(m_Ui->m_Type, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
            &MemoryView::dataTypeChanged);

    QIntValidator* countValidator = new QIntValidator(1, 64, this);
    m_Ui->m_Count->setValidator(countValidator);

    connect(m_Ui->m_Count, static_cast<void (QComboBox::*)(const QString&)>(&QComboBox::currentIndexChanged), this,
            &MemoryView::countChanged);
}

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

MemoryView::~MemoryView()
{
    printf("destruct MemoryView\n");
    delete m_Ui;
}

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

void MemoryView::endianChanged(int e)
{
    m_Ui->m_View->setEndianess(static_cast<MemoryViewWidget::Endianess>(e));
}

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

void MemoryView::interfaceSet()
{
    m_Ui->m_View->setBackendInterface(m_interface);

    if (m_interface) {
        connect(m_interface, &IBackendRequests::endResolveAddress, this, &MemoryView::endResolveAddress);
    }
}

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

void MemoryView::dataTypeChanged(int t)
{
    m_Ui->m_View->setDataType(static_cast<MemoryViewWidget::DataType>(t));
}

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

void MemoryView::jumpAddressChanged()
{
    jumpToAddressExpression(m_Ui->m_Address->text());
}

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

void MemoryView::jumpToAddressExpression(const QString& str)
{
    if (m_interface) {
        m_interface->beginResolveAddress(str, &m_evalAddress);
    }
}

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

void MemoryView::endResolveAddress(uint64_t* out)
{
    if (!out) {
        m_Ui->m_View->setExpressionStatus(false);
    } else {
        m_Ui->m_View->setExpressionStatus(true);
        m_Ui->m_Address->setText(QStringLiteral("0x") + QString::number(*out, 16));
        m_Ui->m_View->setAddress(*out);
    }

    m_Ui->m_View->update();
}

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

void MemoryView::countChanged(const QString& text)
{
    bool ok = false;
    int count = text.toInt(&ok, /*base:*/ 0);
    if (ok) {
        m_Ui->m_View->setElementsPerLine(count);
    }
}

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

void MemoryView::readSettings()
{
}

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

void MemoryView::writeSettings()
{
}

}
<commit_msg>Save type and endian<commit_after>#include "MemoryView.h"
#include "ui_MemoryView.h"
#include "Backend/IBackendRequests.h"
#include <QtCore/QDebug>
#include <QtCore/QMetaEnum>
#include <QSettings>

namespace prodbg {

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

template <typename EnumType>
static void enumToCombo(QComboBox* combo, int startValue)
{
    QMetaEnum me = QMetaEnum::fromType<EnumType>();

    for (int i = 0; i < me.keyCount(); ++i) {
        combo->addItem(QString::fromUtf8(me.key(i)));
    }

    combo->setCurrentIndex(startValue);
}

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

MemoryView::MemoryView(QWidget* parent)
    : Base(parent)
    , m_Ui(new Ui_MemoryView)
{
    m_Ui->setupUi(this);

    connect(m_Ui->m_Address, &QLineEdit::returnPressed, this, &MemoryView::jumpAddressChanged);

    enumToCombo<MemoryViewWidget::Endianess>(m_Ui->m_Endianess, m_Ui->m_View->endianess());
    enumToCombo<MemoryViewWidget::DataType>(m_Ui->m_Type, m_Ui->m_View->dataType());

    connect(m_Ui->m_Endianess, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
            &MemoryView::endianChanged);
    connect(m_Ui->m_Type, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
            &MemoryView::dataTypeChanged);

    QIntValidator* countValidator = new QIntValidator(1, 64, this);
    m_Ui->m_Count->setValidator(countValidator);

    connect(m_Ui->m_Count, static_cast<void (QComboBox::*)(const QString&)>(&QComboBox::currentIndexChanged), this,
            &MemoryView::countChanged);

    readSettings();
}

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

MemoryView::~MemoryView()
{
    writeSettings();
    printf("destruct MemoryView\n");
    delete m_Ui;
}

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

void MemoryView::endianChanged(int e)
{
    m_Ui->m_View->setEndianess(static_cast<MemoryViewWidget::Endianess>(e));
}

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

void MemoryView::interfaceSet()
{
    m_Ui->m_View->setBackendInterface(m_interface);

    if (m_interface) {
        connect(m_interface, &IBackendRequests::endResolveAddress, this, &MemoryView::endResolveAddress);
    }
}

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

void MemoryView::dataTypeChanged(int t)
{
    m_Ui->m_View->setDataType(static_cast<MemoryViewWidget::DataType>(t));
}

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

void MemoryView::jumpAddressChanged()
{
    jumpToAddressExpression(m_Ui->m_Address->text());
}

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

void MemoryView::jumpToAddressExpression(const QString& str)
{
    if (m_interface) {
        m_interface->beginResolveAddress(str, &m_evalAddress);
    }
}

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

void MemoryView::endResolveAddress(uint64_t* out)
{
    if (!out) {
        m_Ui->m_View->setExpressionStatus(false);
    } else {
        m_Ui->m_View->setExpressionStatus(true);
        m_Ui->m_Address->setText(QStringLiteral("0x") + QString::number(*out, 16));
        m_Ui->m_View->setAddress(*out);
    }

    m_Ui->m_View->update();
}

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

void MemoryView::countChanged(const QString& text)
{
    bool ok = false;
    int count = text.toInt(&ok, /*base:*/ 0);
    if (ok) {
        m_Ui->m_View->setElementsPerLine(count);
    }
}

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

void MemoryView::readSettings()
{
    QSettings settings(QStringLiteral("TBL"), QStringLiteral("ProDBG"));

    // TODO: Support more than one memory view
    settings.beginGroup(QStringLiteral("MemoryView_0"));
    m_Ui->m_Endianess->setCurrentIndex(settings.value(QStringLiteral("endian")).toInt());
    m_Ui->m_Type->setCurrentIndex(settings.value(QStringLiteral("data_type")).toInt());
    settings.endGroup();
}

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

void MemoryView::writeSettings()
{
    QSettings settings(QStringLiteral("TBL"), QStringLiteral("ProDBG"));

    // TODO: Support more than one memory view
    settings.beginGroup(QStringLiteral("MemoryView_0"));
    settings.setValue(QStringLiteral("endian"), m_Ui->m_Endianess->currentIndex());
    settings.setValue(QStringLiteral("data_type"), m_Ui->m_Type->currentIndex());
    settings.setValue(QStringLiteral("count"), m_Ui->m_Type->currentIndex());
    settings.endGroup();
}

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

}
<|endoftext|>