<commit_before>#include "native/UriTemplate.hpp"

#include "native/UriTemplateFormat.hpp"
#include "native/UriTemplateValue.hpp"
#include "native/helper/trace.hpp"

#if NNATIVE_USE_RE2 == 1
#include <re2/re2.h>
#elif NNATIVE_USE_STDREGEX == 1
#include <regex>
#else

#endif // elif NNATIVE_USE_STDREGEX == 1

#include <set>

using namespace native;

namespace {

#if NNATIVE_USE_RE2 == 1

bool getNextParameter(std::string::const_iterator& iBegin, std::string::const_iterator iEnd, std::string& iText, std::string& Name, std::string& iFormat) {
    // regex is compiled only at the first call
    static const re2::RE2 reParam("\\{([a-zA-Z][a-zA-Z0-9]*):([a-zA-Z][a-zA-Z0-9]*)\\}"); //e.g.: {param:formatName}
    re2::StringPiece text(&(*iBegin), std::distance(iBegin, iEnd));
    re2::StringPiece results[3];

    if(!reParam.Match(text, 0, text.size(), re2::RE2::UNANCHORED, results, 3)) {
        return false;
    }

    iText.assign(text.data(), results[0].begin() - text.begin());
    Name.assign(results[1].data(), results[1].size());
    iFormat.assign(results[2].data(), results[2].size());

    iBegin += results[0].end() - text.begin();

    return true;
}

/**
 * Recursive save extracted data by regex into values
 * @param ioParsedValues parsed values container to be populated
 * @param ioPosition current smatch position
 * @iParams parameters name vector to be added as key values
 * @iFormatNames format name vector to parse child values, if exists
 */
void saveValues(
        UriTemplateValue &ioParsedValues,
        int &ioPosition,
        const re2::StringPiece* iMatchResults,
        const int iMatchResultsSize,
        const std::vector<std::string> &iParams,
        const std::vector<std::string> &iFormatNames) {
    NNATIVE_ASSERT(iParams.size() == iFormatNames.size());
    NNATIVE_ASSERT(iMatchResultsSize - ioPosition >= static_cast<int>(iParams.size()));
    for(std::vector<std::string>::size_type i = 0; i < iParams.size(); ++i)
    {
        const std::string value = iMatchResults[ioPosition++].as_string();
        const std::string &name = iParams[i];
        const std::string &formatName = iFormatNames[i];
        UriTemplateValue &childValue = ioParsedValues.addChild(name, value);
        const UriTemplateFormat &format = UriTemplateFormat::GetGlobalFormat(formatName);

        if(format.isRegExOnly())
        {
            continue;
        }

        // Parse subvalues of format name
        const UriTemplate &uriTemplate = format.getTemplate();
        NNATIVE_DEBUG("Extract child values from \"" << value << "\" with key \"" << name << "\" by using format name \"" << formatName << "\" with pattern \"" << uriTemplate.getPattern(true) << "\"");
        saveValues(childValue, ioPosition, iMatchResults, iMatchResultsSize, uriTemplate.getParams(), uriTemplate.getFormatNames());
    }
}

bool extractAndSaveValues(UriTemplateValue &oValues,
                          const std::string &iUri,
                          const std::string &iExtractPattern,
                          const std::vector<std::string> &iParams,
                          const std::vector<std::string> &iFormatNames,
                          const bool iAnchorEnd = true) {
    const re2::RE2 rePattern(iExtractPattern);
    const int matchResultsSize = 1+rePattern.NumberOfCapturingGroups();
    re2::StringPiece matchResults[matchResultsSize];
    re2::StringPiece uriPiece(iUri);

    if(!rePattern.Match(uriPiece, 0, uriPiece.size(), (iAnchorEnd ? re2::RE2::ANCHOR_BOTH : re2::RE2::ANCHOR_START), matchResults, matchResultsSize)) {
        NNATIVE_DEBUG("No match found");
        return false;
    }

    int position = 0;
    // No name to the first parsed value
    oValues.clear();
    oValues.getString() = matchResults[position++].as_string();
    // save child values
    saveValues(oValues, position, matchResults, matchResultsSize, iParams, iFormatNames);

    return true;
}

bool containCapturingGroup(const std::string &iPattern) {
    // regex is compiled only at the first call
    static const re2::RE2 reCapturingGroup("\\([^?\\)]+\\)"); // true for "(test|other)", but false for non capturing groups (?:test|other)
    re2::StringPiece strPiece(iPattern);

    return reCapturingGroup.Match(strPiece, 0, strPiece.size(), re2::RE2::UNANCHORED, nullptr, 0);
}

#elif NNATIVE_USE_STDREGEX == 1
#include <regex>

bool getNextParameter(std::string::const_iterator& iBegin, std::string::const_iterator iEnd, std::string& iText, std::string& Name, std::string& iFormat) {
    // regex is compiled only at the first call
    static const std::regex reParam("\\{([a-zA-Z][a-zA-Z0-9]*):([a-zA-Z][a-zA-Z0-9]*)\\}"); //e.g.: {param:formatName}
    std::smatch results;

    if(!std::regex_search(iBegin, iEnd, results, reParam)) {
        return false;
    }

    iText.assign(iBegin, iBegin + results.position());
    Name = results.str(1);
    iFormat = results.str(2);

    iBegin += results.position() + results.length();

    return true;
}

/**
 * Recursive save extracted data by regex into values
 * @param ioParsedValues parsed values container to be populated
 * @param ioPosition current smatch position
 * @iParams parameters name vector to be added as key values
 * @iFormatNames format name vector to parse child values, if exists
 */
void saveValues(
        UriTemplateValue &ioParsedValues,
        int &ioPosition,
        const std::smatch &iMatchResults,
        const std::vector<std::string> &iParams,
        const std::vector<std::string> &iFormatNames) {
    NNATIVE_ASSERT(iParams.size() == iFormatNames.size());
    NNATIVE_ASSERT(iMatchResults.size() - ioPosition >= iParams.size());
    for(std::vector<std::string>::size_type i = 0; i < iParams.size(); ++i)
    {
        const std::string value = iMatchResults.str(ioPosition++);
        const std::string &name = iParams[i];
        const std::string &formatName = iFormatNames[i];
        UriTemplateValue &childValue = ioParsedValues.addChild(name, value);
        const UriTemplateFormat &format = UriTemplateFormat::GetGlobalFormat(formatName);

        if(format.isRegExOnly())
        {
            continue;
        }

        // Parse subvalues of format name
        const UriTemplate &uriTemplate = format.getTemplate();
        NNATIVE_DEBUG("Extract child values from \"" << value << "\" with key \"" << name << "\" by using format name \"" << formatName << "\" with pattern \"" << uriTemplate.getPattern(true) << "\"");
        saveValues(childValue, ioPosition, iMatchResults, uriTemplate.getParams(), uriTemplate.getFormatNames());
    }
}

bool extractAndSaveValues(UriTemplateValue &oValues,
                          const std::string &iUri,
                          const std::string &iExtractPattern,
                          const std::vector<std::string> &iParams,
                          const std::vector<std::string> &iFormatNames,
                          const bool iAnchorEnd = true) {
    std::smatch matchResults;
    const std::regex rePattern(iExtractPattern);
    if(iAnchorEnd) {
        if(!std::regex_match(iUri, matchResults, rePattern)) {
            NNATIVE_DEBUG("No match found");
            return false;
        }
    } else {
        if(!std::regex_search(iUri, matchResults, rePattern, std::regex_constants::match_continuous)) {
            NNATIVE_DEBUG("No match found");
            return false;
        }
    }

    int position = 0;
    // No name to the first parsed value
    oValues.clear();
    oValues.getString() = matchResults.str(position++);
    // save child values
    saveValues(oValues, position, matchResults, iParams, iFormatNames);

    return true;
}

bool containCapturingGroup(const std::string &iPattern) {
    // regex is compiled only at the first call
    static const std::regex reCapturingGroup("\\([^?\\)]+\\)"); // true for "(test|other)", but false for non capturing groups (?:test|other)
    std::smatch dummyResults;
    return std::regex_search(iPattern, dummyResults, reCapturingGroup);
}

#endif // elif NNATIVE_USE_STDREGEX == 1

} /* namespace */

UriTemplate::UriTemplate(const std::string &iTemplate) : _template(iTemplate) {
    parse();
}

UriTemplate::UriTemplate(const UriTemplate &iBaseUriTemplate, const std::string &iTemplateSuffix) :
        _template(iBaseUriTemplate.getTemplate() + iTemplateSuffix) {
    parse();
}

UriTemplate::UriTemplate(const UriTemplate &iOther) :
        _template(iOther._template),
        _matchPattern(iOther._matchPattern),
        _extractPattern(iOther._extractPattern),
        _params(iOther._params),
        _formatNames(iOther._formatNames) {
    // Avoid parsing because template string is already parsed
}

void UriTemplate::parse() {
    NNATIVE_DEBUG("New URI Template \"" << _template << "\"");
    // should not contain capturing groups. e.g. "/path/(caputeText)/{param1:format1}"
    NNATIVE_ASSERT_MSG(!ContainCapturingGroup(_template), "URI template \"" << _template << "\" contain capturing groups");

    _matchPattern = "";
    _extractPattern = "";
    std::set<std::string> uniqParams;
    _params.clear();
    _formatNames.clear();

    // extract format names
    std::string::const_iterator begin = _template.begin();
    std::string::const_iterator end = _template.end();
    std::string textStr;
    std::string paramName;
    std::string formatName;

    while (getNextParameter(begin, end, textStr, paramName, formatName)) {
        NNATIVE_DEBUG("paramName:"<<paramName<<", formatName:"<<formatName);
        const UriTemplateFormat& globalFormat = UriTemplateFormat::GetGlobalFormat(formatName);

        // Check if parameter name duplicate. e.g: "/path{sameParamName:anyFormatName}/other/{sameParamName:anyFormatName}"
        if(!uniqParams.insert(paramName).second) {
            NNATIVE_DEBUG("Duplicate parameter name found " << paramName);
            NNATIVE_ASSERT(0);
        }

        _params.push_back(paramName);
        _formatNames.push_back(formatName);

        _matchPattern += textStr + globalFormat.getPattern();
        _extractPattern += textStr + globalFormat.getPattern(true);
    }
    // add the remaing string
    std::string textRemained(begin, end);
    _matchPattern += textRemained;
    // extract pattern may be part of a format name, do net add end of string ("$")
    _extractPattern += textRemained;

    NNATIVE_DEBUG("Pattern for match: \"" << _matchPattern << "\"");
    NNATIVE_DEBUG("Pattern for extraction: \"" << _extractPattern << "\"");
}

bool UriTemplate::extract(UriTemplateValue &oValues, const std::string &iUri, const bool iAnchorEnd) const {
    NNATIVE_DEBUG("Extract values from \"" << iUri << "\" by using URI template \"" << _template << "\", pattern: \"" << _extractPattern << "\")");
    return extractAndSaveValues(oValues, iUri, _extractPattern, getParams(), getFormatNames(), iAnchorEnd);
}

bool UriTemplate::ContainCapturingGroup(const std::string &iPattern) {
    return ::containCapturingGroup(iPattern);
}

<commit_msg>uriTemplate: re2 resolve non-POD element type issue<commit_after>#include "native/UriTemplate.hpp"

#include "native/UriTemplateFormat.hpp"
#include "native/UriTemplateValue.hpp"
#include "native/helper/trace.hpp"

#if NNATIVE_USE_RE2 == 1
#include <re2/re2.h>
#elif NNATIVE_USE_STDREGEX == 1
#include <regex>
#else

#endif // elif NNATIVE_USE_STDREGEX == 1

#include <set>
#include <memory>

using namespace native;

namespace {

#if NNATIVE_USE_RE2 == 1

bool getNextParameter(std::string::const_iterator& iBegin, std::string::const_iterator iEnd, std::string& iText, std::string& Name, std::string& iFormat) {
    // regex is compiled only at the first call
    static const re2::RE2 reParam("\\{([a-zA-Z][a-zA-Z0-9]*):([a-zA-Z][a-zA-Z0-9]*)\\}"); //e.g.: {param:formatName}
    re2::StringPiece text(&(*iBegin), std::distance(iBegin, iEnd));
    re2::StringPiece results[3];

    if(!reParam.Match(text, 0, text.size(), re2::RE2::UNANCHORED, results, 3)) {
        return false;
    }

    iText.assign(text.data(), results[0].begin() - text.begin());
    Name.assign(results[1].data(), results[1].size());
    iFormat.assign(results[2].data(), results[2].size());

    iBegin += results[0].end() - text.begin();

    return true;
}

/**
 * Recursive save extracted data by regex into values
 * @param ioParsedValues parsed values container to be populated
 * @param ioPosition current smatch position
 * @iParams parameters name vector to be added as key values
 * @iFormatNames format name vector to parse child values, if exists
 */
void saveValues(
        UriTemplateValue &ioParsedValues,
        int &ioPosition,
        const re2::StringPiece* iMatchResults,
        const int iMatchResultsSize,
        const std::vector<std::string> &iParams,
        const std::vector<std::string> &iFormatNames) {
    NNATIVE_ASSERT(iParams.size() == iFormatNames.size());
    NNATIVE_ASSERT(iMatchResultsSize - ioPosition >= static_cast<int>(iParams.size()));
    for(std::vector<std::string>::size_type i = 0; i < iParams.size(); ++i)
    {
        const std::string value = iMatchResults[ioPosition++].as_string();
        const std::string &name = iParams[i];
        const std::string &formatName = iFormatNames[i];
        UriTemplateValue &childValue = ioParsedValues.addChild(name, value);
        const UriTemplateFormat &format = UriTemplateFormat::GetGlobalFormat(formatName);

        if(format.isRegExOnly())
        {
            continue;
        }

        // Parse subvalues of format name
        const UriTemplate &uriTemplate = format.getTemplate();
        NNATIVE_DEBUG("Extract child values from \"" << value << "\" with key \"" << name << "\" by using format name \"" << formatName << "\" with pattern \"" << uriTemplate.getPattern(true) << "\"");
        saveValues(childValue, ioPosition, iMatchResults, iMatchResultsSize, uriTemplate.getParams(), uriTemplate.getFormatNames());
    }
}

bool extractAndSaveValues(UriTemplateValue &oValues,
                          const std::string &iUri,
                          const std::string &iExtractPattern,
                          const std::vector<std::string> &iParams,
                          const std::vector<std::string> &iFormatNames,
                          const bool iAnchorEnd = true) {
    const re2::RE2 rePattern(iExtractPattern);
    const int matchResultsSize = 1+rePattern.NumberOfCapturingGroups();
    std::unique_ptr<re2::StringPiece[]> matchResults(new re2::StringPiece[matchResultsSize]);
    re2::StringPiece uriPiece(iUri);

    if(!rePattern.Match(uriPiece, 0, uriPiece.size(), (iAnchorEnd ? re2::RE2::ANCHOR_BOTH : re2::RE2::ANCHOR_START), matchResults.get(), matchResultsSize)) {
        NNATIVE_DEBUG("No match found");
        return false;
    }

    int position = 0;
    // No name to the first parsed value
    oValues.clear();
    oValues.getString() = matchResults[position++].as_string();
    // save child values
    saveValues(oValues, position, matchResults.get(), matchResultsSize, iParams, iFormatNames);

    return true;
}

bool containCapturingGroup(const std::string &iPattern) {
    // regex is compiled only at the first call
    static const re2::RE2 reCapturingGroup("\\([^?\\)]+\\)"); // true for "(test|other)", but false for non capturing groups (?:test|other)
    re2::StringPiece strPiece(iPattern);

    return reCapturingGroup.Match(strPiece, 0, strPiece.size(), re2::RE2::UNANCHORED, nullptr, 0);
}

#elif NNATIVE_USE_STDREGEX == 1
#include <regex>

bool getNextParameter(std::string::const_iterator& iBegin, std::string::const_iterator iEnd, std::string& iText, std::string& Name, std::string& iFormat) {
    // regex is compiled only at the first call
    static const std::regex reParam("\\{([a-zA-Z][a-zA-Z0-9]*):([a-zA-Z][a-zA-Z0-9]*)\\}"); //e.g.: {param:formatName}
    std::smatch results;

    if(!std::regex_search(iBegin, iEnd, results, reParam)) {
        return false;
    }

    iText.assign(iBegin, iBegin + results.position());
    Name = results.str(1);
    iFormat = results.str(2);

    iBegin += results.position() + results.length();

    return true;
}

/**
 * Recursive save extracted data by regex into values
 * @param ioParsedValues parsed values container to be populated
 * @param ioPosition current smatch position
 * @iParams parameters name vector to be added as key values
 * @iFormatNames format name vector to parse child values, if exists
 */
void saveValues(
        UriTemplateValue &ioParsedValues,
        int &ioPosition,
        const std::smatch &iMatchResults,
        const std::vector<std::string> &iParams,
        const std::vector<std::string> &iFormatNames) {
    NNATIVE_ASSERT(iParams.size() == iFormatNames.size());
    NNATIVE_ASSERT(iMatchResults.size() - ioPosition >= iParams.size());
    for(std::vector<std::string>::size_type i = 0; i < iParams.size(); ++i)
    {
        const std::string value = iMatchResults.str(ioPosition++);
        const std::string &name = iParams[i];
        const std::string &formatName = iFormatNames[i];
        UriTemplateValue &childValue = ioParsedValues.addChild(name, value);
        const UriTemplateFormat &format = UriTemplateFormat::GetGlobalFormat(formatName);

        if(format.isRegExOnly())
        {
            continue;
        }

        // Parse subvalues of format name
        const UriTemplate &uriTemplate = format.getTemplate();
        NNATIVE_DEBUG("Extract child values from \"" << value << "\" with key \"" << name << "\" by using format name \"" << formatName << "\" with pattern \"" << uriTemplate.getPattern(true) << "\"");
        saveValues(childValue, ioPosition, iMatchResults, uriTemplate.getParams(), uriTemplate.getFormatNames());
    }
}

bool extractAndSaveValues(UriTemplateValue &oValues,
                          const std::string &iUri,
                          const std::string &iExtractPattern,
                          const std::vector<std::string> &iParams,
                          const std::vector<std::string> &iFormatNames,
                          const bool iAnchorEnd = true) {
    std::smatch matchResults;
    const std::regex rePattern(iExtractPattern);
    if(iAnchorEnd) {
        if(!std::regex_match(iUri, matchResults, rePattern)) {
            NNATIVE_DEBUG("No match found");
            return false;
        }
    } else {
        if(!std::regex_search(iUri, matchResults, rePattern, std::regex_constants::match_continuous)) {
            NNATIVE_DEBUG("No match found");
            return false;
        }
    }

    int position = 0;
    // No name to the first parsed value
    oValues.clear();
    oValues.getString() = matchResults.str(position++);
    // save child values
    saveValues(oValues, position, matchResults, iParams, iFormatNames);

    return true;
}

bool containCapturingGroup(const std::string &iPattern) {
    // regex is compiled only at the first call
    static const std::regex reCapturingGroup("\\([^?\\)]+\\)"); // true for "(test|other)", but false for non capturing groups (?:test|other)
    std::smatch dummyResults;
    return std::regex_search(iPattern, dummyResults, reCapturingGroup);
}

#endif // elif NNATIVE_USE_STDREGEX == 1

} /* namespace */

UriTemplate::UriTemplate(const std::string &iTemplate) : _template(iTemplate) {
    parse();
}

UriTemplate::UriTemplate(const UriTemplate &iBaseUriTemplate, const std::string &iTemplateSuffix) :
        _template(iBaseUriTemplate.getTemplate() + iTemplateSuffix) {
    parse();
}

UriTemplate::UriTemplate(const UriTemplate &iOther) :
        _template(iOther._template),
        _matchPattern(iOther._matchPattern),
        _extractPattern(iOther._extractPattern),
        _params(iOther._params),
        _formatNames(iOther._formatNames) {
    // Avoid parsing because template string is already parsed
}

void UriTemplate::parse() {
    NNATIVE_DEBUG("New URI Template \"" << _template << "\"");
    // should not contain capturing groups. e.g. "/path/(caputeText)/{param1:format1}"
    NNATIVE_ASSERT_MSG(!ContainCapturingGroup(_template), "URI template \"" << _template << "\" contain capturing groups");

    _matchPattern = "";
    _extractPattern = "";
    std::set<std::string> uniqParams;
    _params.clear();
    _formatNames.clear();

    // extract format names
    std::string::const_iterator begin = _template.begin();
    std::string::const_iterator end = _template.end();
    std::string textStr;
    std::string paramName;
    std::string formatName;

    while (getNextParameter(begin, end, textStr, paramName, formatName)) {
        NNATIVE_DEBUG("paramName:"<<paramName<<", formatName:"<<formatName);
        const UriTemplateFormat& globalFormat = UriTemplateFormat::GetGlobalFormat(formatName);

        // Check if parameter name duplicate. e.g: "/path{sameParamName:anyFormatName}/other/{sameParamName:anyFormatName}"
        if(!uniqParams.insert(paramName).second) {
            NNATIVE_DEBUG("Duplicate parameter name found " << paramName);
            NNATIVE_ASSERT(0);
        }

        _params.push_back(paramName);
        _formatNames.push_back(formatName);

        _matchPattern += textStr + globalFormat.getPattern();
        _extractPattern += textStr + globalFormat.getPattern(true);
    }
    // add the remaing string
    std::string textRemained(begin, end);
    _matchPattern += textRemained;
    // extract pattern may be part of a format name, do net add end of string ("$")
    _extractPattern += textRemained;

    NNATIVE_DEBUG("Pattern for match: \"" << _matchPattern << "\"");
    NNATIVE_DEBUG("Pattern for extraction: \"" << _extractPattern << "\"");
}

bool UriTemplate::extract(UriTemplateValue &oValues, const std::string &iUri, const bool iAnchorEnd) const {
    NNATIVE_DEBUG("Extract values from \"" << iUri << "\" by using URI template \"" << _template << "\", pattern: \"" << _extractPattern << "\")");
    return extractAndSaveValues(oValues, iUri, _extractPattern, getParams(), getFormatNames(), iAnchorEnd);
}

bool UriTemplate::ContainCapturingGroup(const std::string &iPattern) {
    return ::containCapturingGroup(iPattern);
}

<|endoftext|>


<commit_before>#include "ValidSudoku.hpp"

bool ValidSudoku::isValidSudoku(vector<vector<char>>& board)
{
  bool used1[9][9] = {false}, used2[9][9] = {false}, used3[9][9] = {false};

  for(int i = 0; i < board.size(); i++)
    for(int j = 0; j < board[i].size(); j++)
      if (board[i][j] != '.') {
        int num = board[i][j] - '0' - 1;
        int k = i / 3 * 3 + j / 3;

        if (used1[i][num] || used2[j][num] || used3[k][num])
          return false;

        used1[i][num] = used2[j][num] = used3[k][num] = true;
      }

  return true;
}
<commit_msg>Refine Problem 36. Valid Sudoku<commit_after>#include "ValidSudoku.hpp"

bool ValidSudoku::isValidSudoku(vector<vector<char>>& board)
{
  bool used1[9][9] = {false}, used2[9][9] = {false}, used3[9][9] = {false};

  for (int i = 0; i < board.size(); i++)
    for (int j = 0; j < board[i].size(); j++)
      if (board[i][j] != '.') {
        int num = board[i][j] - '0' - 1;
        int k = i / 3 * 3 + j / 3;

        if (used1[i][num] || used2[j][num] || used3[k][num])
          return false;

        used1[i][num] = used2[j][num] = used3[k][num] = true;
      }

  return true;
}
<|endoftext|>


<commit_before>/*
 * A wrapper for an async_operation which unrefs the pool on abort.
 *
 * This solves a problem of many libraries which reference a pool, but
 * pass the async_ref object to another library.  When the caller
 * aborts the operation, the "middle" library never gets a chance to
 * unref the pool; plugging this wrapper solves this problem.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "abort_unref.hxx"
#include "async.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

struct UnrefOnAbort {
    struct pool &pool;
    struct async_operation operation;
    struct async_operation_ref ref;

#ifdef TRACE
    const char *const file;
    unsigned line;
#endif

    UnrefOnAbort(struct pool &_pool,
                 struct async_operation_ref &async_ref
                 TRACE_ARGS_DECL_)
        :pool(_pool)
         TRACE_ARGS_INIT {
        operation.Init2<UnrefOnAbort>();
        async_ref.Set(operation);
    }

    void Abort() {
        ref.Abort();
        pool_unref_fwd(&pool);
    }
};

/*
 * constructor
 *
 */

struct async_operation_ref &
async_unref_on_abort_impl(struct pool &pool,
                          struct async_operation_ref &async_ref
                          TRACE_ARGS_DECL)
{
    auto uoa = NewFromPool<UnrefOnAbort>(pool, pool, async_ref
                                         TRACE_ARGS_FWD);
    return uoa->ref;
}
<commit_msg>abort_unref: migrate to class Cancellable<commit_after>/*
 * A wrapper for an async_operation which unrefs the pool on abort.
 *
 * This solves a problem of many libraries which reference a pool, but
 * pass the async_ref object to another library.  When the caller
 * aborts the operation, the "middle" library never gets a chance to
 * unref the pool; plugging this wrapper solves this problem.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "abort_unref.hxx"
#include "async.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

struct UnrefOnAbort final : Cancellable {
    struct pool &pool;
    struct async_operation_ref ref;

#ifdef TRACE
    const char *const file;
    unsigned line;
#endif

    UnrefOnAbort(struct pool &_pool,
                 struct async_operation_ref &async_ref
                 TRACE_ARGS_DECL_)
        :pool(_pool)
         TRACE_ARGS_INIT {
        async_ref = *this;
    }

    /* virtual methods from class Cancellable */
    void Cancel() override {
        ref.Abort();
        pool_unref_fwd(&pool);
    }
};

/*
 * constructor
 *
 */

struct async_operation_ref &
async_unref_on_abort_impl(struct pool &pool,
                          struct async_operation_ref &async_ref
                          TRACE_ARGS_DECL)
{
    auto uoa = NewFromPool<UnrefOnAbort>(pool, pool, async_ref
                                         TRACE_ARGS_FWD);
    return uoa->ref;
}
<|endoftext|>


<commit_before>#include "accumulator.h"
#include "thread/loopi.h"

using namespace nano;

accumulator_t::accumulator_t(const model_t& model, const loss_t& loss) :
        m_type(type::value), m_loss(loss)
{
        const auto size = thread_pool_t::instance().workers();
        for (size_t i = 0; i < size; ++ i)
        {
                m_tcaches.emplace_back(model);
        }
}

void accumulator_t::clear()
{
        for (auto& tcache : m_tcaches)
        {
                tcache.m_vstats.clear();
                tcache.m_estats.clear();
                if (m_type == type::vgrad)
                {
                        tcache.m_vgrad.setZero();
                }
        }
}

void accumulator_t::random()
{
        origin().m_model->random();
        params(origin().m_model->params());
}

void accumulator_t::params(const vector_t& params)
{
        for (auto& tcache : m_tcaches)
        {
                tcache.m_model->params(params);
        }
        clear();
}

void accumulator_t::mode(const accumulator_t::type t)
{
        m_type = t;
        clear();
}

void accumulator_t::lambda(const scalar_t lambda)
{
        m_lambda = lambda;
        clear();
}

void accumulator_t::minibatch(const size_t minibatch_size)
{
        m_batch = minibatch_size;
}

void accumulator_t::update(const task_t& task, const fold_t& fold)
{
        update(task, fold, 0, task.size(fold));
}

void accumulator_t::update(const task_t& task, const fold_t& fold, const size_t begin, const size_t end)
{
        assert(begin <= end);
        const auto old_count = vstats().count();
        loopit(end - begin, m_batch, [&] (const size_t ibegin, const size_t iend, const size_t thread)
        {
                assert(thread < m_tcaches.size());
                assert(ibegin < iend && iend + begin <= end);
                update(m_tcaches[thread], task.get(fold, begin + ibegin, begin + iend));
        });
        NANO_UNUSED1_RELEASE(old_count);
        assert(old_count + end == begin + vstats().count());
}

void accumulator_t::update(tcache_t& tcache, const minibatch_t& minibatch)
{
        update(tcache, minibatch.odata(), minibatch.idata());
}

void accumulator_t::update(tcache_t& tcache, const tensor4d_t& targets, const tensor4d_t& inputs)
{
        const auto& outputs = tcache.m_model->output(inputs);

        const auto values = m_loss.value(targets, outputs);
        const auto errors = m_loss.error(targets, outputs);

        assert(outputs.size<0>() == values.size<0>());
        assert(outputs.size<0>() == errors.size<0>());

        tcache.m_vstats(values.data(), values.data() + values.size());
        tcache.m_estats(errors.data(), errors.data() + errors.size());

        if (m_type == type::vgrad)
        {
                tcache.m_vgrad += tcache.m_model->gparam(m_loss.vgrad(targets, outputs));
        }
}

void accumulator_t::accumulate()
{
        auto& origin = this->origin();
        for (const auto& tcache : m_tcaches)
        {
                if (&tcache != &origin)
                {
                        origin.m_vstats(tcache.m_vstats);
                        origin.m_estats(tcache.m_estats);
                        if (m_type == type::vgrad)
                        {
                                origin.m_vgrad += tcache.m_vgrad;
                        }
                }
        }
}

accumulator_t::tcache_t& accumulator_t::origin()
{
        return *m_tcaches.begin();
}

const accumulator_t::tcache_t& accumulator_t::origin() const
{
        return *m_tcaches.cbegin();
}

const stats_t<scalar_t>& accumulator_t::vstats() const
{
        return origin().m_vstats;
}

const stats_t<scalar_t>& accumulator_t::estats() const
{
        return origin().m_estats;
}

scalar_t accumulator_t::value() const
{
        assert(vstats().count() > 0);
        return vstats().avg() + (m_lambda / 2) * params().squaredNorm();
}

vector_t accumulator_t::vgrad() const
{
        assert(vstats().count() > 0);
        assert(m_type == type::vgrad);
        return origin().m_vgrad / vstats().count() + m_lambda * params();
}

tensor_size_t accumulator_t::psize() const
{
        return origin().m_model->psize();
}

const vector_t& accumulator_t::params() const
{
        return origin().m_model->params();
}

probes_t accumulator_t::probes() const
{
        return origin().m_model->probes();
}
<commit_msg>fix accumulator<commit_after>#include "accumulator.h"
#include "thread/loopi.h"

using namespace nano;

accumulator_t::accumulator_t(const model_t& model, const loss_t& loss) :
        m_type(type::value), m_loss(loss)
{
        const auto size = thread_pool_t::instance().workers();
        for (size_t i = 0; i < size; ++ i)
        {
                m_tcaches.emplace_back(model);
        }
}

void accumulator_t::clear()
{
        for (auto& tcache : m_tcaches)
        {
                tcache.m_vstats.clear();
                tcache.m_estats.clear();
                if (m_type == type::vgrad)
                {
                        tcache.m_vgrad.setZero();
                }
        }
}

void accumulator_t::random()
{
        origin().m_model->random();
        params(origin().m_model->params());
}

void accumulator_t::params(const vector_t& params)
{
        for (auto& tcache : m_tcaches)
        {
                tcache.m_model->params(params);
        }
        clear();
}

void accumulator_t::mode(const accumulator_t::type t)
{
        m_type = t;
        clear();
}

void accumulator_t::lambda(const scalar_t lambda)
{
        m_lambda = lambda;
        clear();
}

void accumulator_t::minibatch(const size_t minibatch_size)
{
        m_batch = minibatch_size;
}

void accumulator_t::update(const task_t& task, const fold_t& fold)
{
        update(task, fold, 0, task.size(fold));
}

void accumulator_t::update(const task_t& task, const fold_t& fold, const size_t begin, const size_t end)
{
        assert(begin <= end);
        const auto old_count = vstats().count();
        loopit(end - begin, m_batch, [&] (const size_t ibegin, const size_t iend, const size_t thread)
        {
                assert(thread < m_tcaches.size());
                assert(ibegin < iend && iend + begin <= end);
                update(m_tcaches[thread], task.get(fold, begin + ibegin, begin + iend));
        });
        accumulate();
        NANO_UNUSED1_RELEASE(old_count);
        assert(old_count + end == begin + vstats().count());
}

void accumulator_t::update(tcache_t& tcache, const minibatch_t& minibatch)
{
        update(tcache, minibatch.odata(), minibatch.idata());
}

void accumulator_t::update(tcache_t& tcache, const tensor4d_t& targets, const tensor4d_t& inputs)
{
        const auto& outputs = tcache.m_model->output(inputs);

        const auto values = m_loss.value(targets, outputs);
        const auto errors = m_loss.error(targets, outputs);

        assert(outputs.size<0>() == values.size<0>());
        assert(outputs.size<0>() == errors.size<0>());

        tcache.m_vstats(values.data(), values.data() + values.size());
        tcache.m_estats(errors.data(), errors.data() + errors.size());

        if (m_type == type::vgrad)
        {
                tcache.m_vgrad += tcache.m_model->gparam(m_loss.vgrad(targets, outputs));
        }
}

void accumulator_t::accumulate()
{
        auto& origin = this->origin();
        for (const auto& tcache : m_tcaches)
        {
                if (&tcache != &origin)
                {
                        origin.m_vstats(tcache.m_vstats);
                        origin.m_estats(tcache.m_estats);
                        if (m_type == type::vgrad)
                        {
                                origin.m_vgrad += tcache.m_vgrad;
                        }
                }
        }
}

accumulator_t::tcache_t& accumulator_t::origin()
{
        return *m_tcaches.begin();
}

const accumulator_t::tcache_t& accumulator_t::origin() const
{
        return *m_tcaches.cbegin();
}

const stats_t<scalar_t>& accumulator_t::vstats() const
{
        return origin().m_vstats;
}

const stats_t<scalar_t>& accumulator_t::estats() const
{
        return origin().m_estats;
}

scalar_t accumulator_t::value() const
{
        assert(vstats().count() > 0);
        return vstats().avg() + (m_lambda / 2) * params().squaredNorm();
}

vector_t accumulator_t::vgrad() const
{
        assert(vstats().count() > 0);
        assert(m_type == type::vgrad);
        return origin().m_vgrad / vstats().count() + m_lambda * params();
}

tensor_size_t accumulator_t::psize() const
{
        return origin().m_model->psize();
}

const vector_t& accumulator_t::params() const
{
        return origin().m_model->params();
}

probes_t accumulator_t::probes() const
{
        return origin().m_model->probes();
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2022 Patrizio Bekerle -- <patrizio@bekerle.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 */

#include "qplaintexteditsearchwidget.h"

#include <QDebug>
#include <QEvent>
#include <QKeyEvent>

#include "ui_qplaintexteditsearchwidget.h"

QPlainTextEditSearchWidget::QPlainTextEditSearchWidget(QPlainTextEdit *parent)
    : QWidget(parent),
      ui(new Ui::QPlainTextEditSearchWidget),
      selectionColor(0, 180, 0, 100) {
    ui->setupUi(this);
    _textEdit = parent;
    _darkMode = false;
    hide();
    ui->searchCountLabel->setStyleSheet(QStringLiteral("* {color: grey}"));
    // hiding will leave a open space in the horizontal layout
    ui->searchCountLabel->setEnabled(false);
    _currentSearchResult = 0;
    _searchResultCount = 0;

    connect(ui->closeButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::deactivate);
    connect(ui->searchLineEdit, &QLineEdit::textChanged, this,
            &QPlainTextEditSearchWidget::searchLineEditTextChanged);
    connect(ui->searchDownButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::doSearchDown);
    connect(ui->searchUpButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::doSearchUp);
    connect(ui->replaceToggleButton, &QPushButton::toggled, this,
            &QPlainTextEditSearchWidget::setReplaceMode);
    connect(ui->replaceButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::doReplace);
    connect(ui->replaceAllButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::doReplaceAll);

    connect(&_debounceTimer, &QTimer::timeout,
            this, &QPlainTextEditSearchWidget::performSearch);

    installEventFilter(this);
    ui->searchLineEdit->installEventFilter(this);
    ui->replaceLineEdit->installEventFilter(this);

#ifdef Q_OS_MAC
    // set the spacing to 8 for OS X
    layout()->setSpacing(8);
    ui->buttonFrame->layout()->setSpacing(9);

    // set the margin to 0 for the top buttons for OS X
    QString buttonStyle = "QPushButton {margin: 0}";
    ui->closeButton->setStyleSheet(buttonStyle);
    ui->searchDownButton->setStyleSheet(buttonStyle);
    ui->searchUpButton->setStyleSheet(buttonStyle);
    ui->replaceToggleButton->setStyleSheet(buttonStyle);
    ui->matchCaseSensitiveButton->setStyleSheet(buttonStyle);
#endif
}

QPlainTextEditSearchWidget::~QPlainTextEditSearchWidget() { delete ui; }

void QPlainTextEditSearchWidget::activate() { activate(true); }

void QPlainTextEditSearchWidget::activateReplace() {
    // replacing is prohibited if the text edit is readonly
    if (_textEdit->isReadOnly()) {
        return;
    }

    ui->searchLineEdit->setText(_textEdit->textCursor().selectedText());
    ui->searchLineEdit->selectAll();
    activate();
    setReplaceMode(true);
}

void QPlainTextEditSearchWidget::deactivate() {
    stopDebounce();

    hide();

    // Clear the search extra selections when closing the search bar
    clearSearchExtraSelections();

    _textEdit->setFocus();
}

void QPlainTextEditSearchWidget::setReplaceMode(bool enabled) {
    ui->replaceToggleButton->setChecked(enabled);
    ui->replaceLabel->setVisible(enabled);
    ui->replaceLineEdit->setVisible(enabled);
    ui->modeLabel->setVisible(enabled);
    ui->buttonFrame->setVisible(enabled);
    ui->matchCaseSensitiveButton->setVisible(enabled);
}

bool QPlainTextEditSearchWidget::eventFilter(QObject *obj, QEvent *event) {
    if (event->type() == QEvent::KeyPress) {
        auto *keyEvent = static_cast<QKeyEvent *>(event);

        if (keyEvent->key() == Qt::Key_Escape) {
            deactivate();
            return true;
        } else if ((!_debounceTimer.isActive() &&
                    keyEvent->modifiers().testFlag(Qt::ShiftModifier) &&
                    (keyEvent->key() == Qt::Key_Return)) ||
                    (keyEvent->key() == Qt::Key_Up)) {
            doSearchUp();
            return true;
        } else if (!_debounceTimer.isActive() &&
                    ((keyEvent->key() == Qt::Key_Return) ||
                     (keyEvent->key() == Qt::Key_Down))) {
            doSearchDown();
            return true;
        } else if (!_debounceTimer.isActive() && keyEvent->key() == Qt::Key_F3) {
            doSearch(!keyEvent->modifiers().testFlag(Qt::ShiftModifier));
            return true;
        }

        //        if ((obj == ui->replaceLineEdit) && (keyEvent->key() ==
        //        Qt::Key_Tab)
        //                && ui->replaceToggleButton->isChecked()) {
        //            ui->replaceLineEdit->setFocus();
        //        }

        return false;
    }

    return QWidget::eventFilter(obj, event);
}

void QPlainTextEditSearchWidget::searchLineEditTextChanged(
    const QString &arg1) {
    _searchTerm = arg1;

    if (_debounceTimer.interval() != 0 && !_searchTerm.isEmpty()) {
        _debounceTimer.start();
        ui->searchDownButton->setEnabled(false);
        ui->searchUpButton->setEnabled(false);
    } else {
        performSearch();
    }
}

void QPlainTextEditSearchWidget::performSearch()
{
    const int searchMode = ui->modeComboBox->currentIndex();

    if (searchMode == RegularExpressionMode) {
        // Prevent stuck application when the user enters just start or end markers
        static const QRegularExpression regExp(R"(^[\^\$]+$)");
        if (regExp.match(_searchTerm).hasMatch()) {
            clearSearchExtraSelections();

            if (_debounceTimer.isActive()) {
                stopDebounce();
            }
            return;
        }
    }

    doSearchCount();
    updateSearchExtraSelections();
    doSearchDown();
}

void QPlainTextEditSearchWidget::clearSearchExtraSelections() {
    _searchExtraSelections.clear();
    setSearchExtraSelections();
}

void QPlainTextEditSearchWidget::updateSearchExtraSelections() {
    _searchExtraSelections.clear();
    const auto textCursor = _textEdit->textCursor();
    _textEdit->moveCursor(QTextCursor::Start);
    const QColor color = selectionColor;
    QTextCharFormat extraFmt;
    extraFmt.setBackground(color);

    while (doSearch(true, false, false)) {
        QTextEdit::ExtraSelection extra = QTextEdit::ExtraSelection();
        extra.format = extraFmt;

        extra.cursor = _textEdit->textCursor();
        _searchExtraSelections.append(extra);
    }

    _textEdit->setTextCursor(textCursor);
    this->setSearchExtraSelections();
}

void QPlainTextEditSearchWidget::setSearchExtraSelections() const {
    this->_textEdit->setExtraSelections(this->_searchExtraSelections);
}

void QPlainTextEditSearchWidget::stopDebounce()
{
    _debounceTimer.stop();
    ui->searchDownButton->setEnabled(true);
    ui->searchUpButton->setEnabled(true);
}

void QPlainTextEditSearchWidget::doSearchUp() { doSearch(false); }

void QPlainTextEditSearchWidget::doSearchDown() { doSearch(true); }

bool QPlainTextEditSearchWidget::doReplace(bool forAll) {
    if (_textEdit->isReadOnly()) {
        return false;
    }

    QTextCursor cursor = _textEdit->textCursor();

    if (!forAll && cursor.selectedText().isEmpty()) {
        return false;
    }

    const int searchMode = ui->modeComboBox->currentIndex();
    if (searchMode == RegularExpressionMode) {
        QString text = cursor.selectedText();
        text.replace(QRegularExpression(ui->searchLineEdit->text()),
                     ui->replaceLineEdit->text());
        cursor.insertText(text);
    } else {
        cursor.insertText(ui->replaceLineEdit->text());
    }

    if (!forAll) {
        const int position = cursor.position();

        if (!doSearch(true)) {
            // restore the last cursor position if text wasn't found any more
            cursor.setPosition(position);
            _textEdit->setTextCursor(cursor);
        }
    }

    return true;
}

void QPlainTextEditSearchWidget::doReplaceAll() {
    if (_textEdit->isReadOnly()) {
        return;
    }

    // start at the top
    _textEdit->moveCursor(QTextCursor::Start);

    // replace until everything to the bottom is replaced
    while (doSearch(true, false) && doReplace(true)) {
    }
}

/**
 * @brief Searches for text in the text edit
 * @returns true if found
 */
bool QPlainTextEditSearchWidget::doSearch(bool searchDown,
                                          bool allowRestartAtTop,
                                          bool updateUI) {
    if (_debounceTimer.isActive()) {
        stopDebounce();
    }

    const QString text = ui->searchLineEdit->text();

    if (text.isEmpty()) {
        if (updateUI) {
            ui->searchLineEdit->setStyleSheet(QLatin1String(""));
        }

        return false;
    }

    const int searchMode = ui->modeComboBox->currentIndex();
    const bool caseSensitive = ui->matchCaseSensitiveButton->isChecked();

    QFlags<QTextDocument::FindFlag> options =
        searchDown ? QTextDocument::FindFlag(0) : QTextDocument::FindBackward;
    if (searchMode == WholeWordsMode) {
        options |= QTextDocument::FindWholeWords;
    }

    if (caseSensitive) {
        options |= QTextDocument::FindCaseSensitively;
    }

    // block signal to reduce too many signals being fired and too many updates
    _textEdit->blockSignals(true);

    bool found =
        searchMode == RegularExpressionMode
            ?
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
            _textEdit->find(
                QRegularExpression(
                    text, caseSensitive
                              ? QRegularExpression::NoPatternOption
                              : QRegularExpression::CaseInsensitiveOption),
                options)
            :
#else
            _textEdit->find(QRegExp(text, caseSensitive ? Qt::CaseSensitive
                                                        : Qt::CaseInsensitive),
                            options)
            :
#endif
            _textEdit->find(text, options);

    _textEdit->blockSignals(false);

    if (found) {
        const int result =
            searchDown ? ++_currentSearchResult : --_currentSearchResult;
        _currentSearchResult = std::min(result, _searchResultCount);

        updateSearchCountLabelText();
    }

    // start at the top (or bottom) if not found
    if (!found && allowRestartAtTop) {
        _textEdit->moveCursor(searchDown ? QTextCursor::Start
                                         : QTextCursor::End);
        found =
            searchMode == RegularExpressionMode
                ?
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
                _textEdit->find(
                    QRegularExpression(
                        text, caseSensitive
                                  ? QRegularExpression::NoPatternOption
                                  : QRegularExpression::CaseInsensitiveOption),
                    options)
                :
#else
                _textEdit->find(
                    QRegExp(text, caseSensitive ? Qt::CaseSensitive
                                                : Qt::CaseInsensitive),
                    options)
                :
#endif
                _textEdit->find(text, options);

        if (found && updateUI) {
            _currentSearchResult = searchDown ? 1 : _searchResultCount;
            updateSearchCountLabelText();
        }
    }

    if (updateUI) {
        const QRect rect = _textEdit->cursorRect();
        QMargins margins = _textEdit->layout()->contentsMargins();
        const int searchWidgetHotArea = _textEdit->height() - this->height();
        const int marginBottom =
            (rect.y() > searchWidgetHotArea) ? (this->height() + 10) : 0;

        // move the search box a bit up if we would block the search result
        if (margins.bottom() != marginBottom) {
            margins.setBottom(marginBottom);
            _textEdit->layout()->setContentsMargins(margins);
        }

        // add a background color according if we found the text or not
        const QString bgColorCode =
            _darkMode
                ? (found ? QStringLiteral("#135a13")
                         : QStringLiteral("#8d2b36"))
                : found ? QStringLiteral("#D5FAE2") : QStringLiteral("#FAE9EB");
        const QString fgColorCode =
            _darkMode ? QStringLiteral("#cccccc") : QStringLiteral("#404040");

        ui->searchLineEdit->setStyleSheet(
            QStringLiteral("* { background: ") + bgColorCode +
            QStringLiteral("; color: ") + fgColorCode + QStringLiteral("; }"));

        // restore the search extra selections after the find command
        this->setSearchExtraSelections();
    }

    return found;
}

/**
 * @brief Counts the search results
 */
void QPlainTextEditSearchWidget::doSearchCount() {
    // Note that we are moving the anchor, so the search will start from the top
    // again! Alternative: Restore cursor position afterwards, but then we will
    // not know
    //              at what _currentSearchResult we currently are
    _textEdit->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor);

    bool found;
    _searchResultCount = 0;
    _currentSearchResult = 0;

    do {
        found = doSearch(true, false, false);
        if (found) {
            _searchResultCount++;
        }
    } while (found);

    updateSearchCountLabelText();
}

void QPlainTextEditSearchWidget::setDarkMode(bool enabled) {
    _darkMode = enabled;
}

void QPlainTextEditSearchWidget::setSearchText(const QString &searchText) {
    ui->searchLineEdit->setText(searchText);
}

void QPlainTextEditSearchWidget::setSearchMode(SearchMode searchMode) {
    ui->modeComboBox->setCurrentIndex(searchMode);
}

void QPlainTextEditSearchWidget::setDebounceDelay(uint debounceDelay)
{
    _debounceTimer.setInterval(static_cast<int>(debounceDelay));
}

void QPlainTextEditSearchWidget::activate(bool focus) {
    setReplaceMode(ui->modeComboBox->currentIndex() !=
                   SearchMode::PlainTextMode);
    show();

    // preset the selected text as search text if there is any and there is no
    // other search text
    const QString selectedText = _textEdit->textCursor().selectedText();
    if (!selectedText.isEmpty() && ui->searchLineEdit->text().isEmpty()) {
        ui->searchLineEdit->setText(selectedText);
    }

    if (focus) {
        ui->searchLineEdit->setFocus();
    }

    ui->searchLineEdit->selectAll();
    updateSearchExtraSelections();
    doSearchDown();
}

void QPlainTextEditSearchWidget::reset() {
    ui->searchLineEdit->clear();
    setSearchMode(SearchMode::PlainTextMode);
    setReplaceMode(false);
    ui->searchCountLabel->setEnabled(false);
}

void QPlainTextEditSearchWidget::updateSearchCountLabelText() {
    ui->searchCountLabel->setEnabled(true);
    ui->searchCountLabel->setText(QString("%1/%2").arg(
        _currentSearchResult == 0 ? QChar('-')
                                  : QString::number(_currentSearchResult),
        _searchResultCount == 0 ? QChar('-')
                                : QString::number(_searchResultCount)));
}

void QPlainTextEditSearchWidget::setSearchSelectionColor(const QColor &color) {
    selectionColor = color;
}

void QPlainTextEditSearchWidget::on_modeComboBox_currentIndexChanged(
    int index) {
    Q_UNUSED(index)
    doSearchCount();
    doSearchDown();
}

void QPlainTextEditSearchWidget::on_matchCaseSensitiveButton_toggled(
    bool checked) {
    Q_UNUSED(checked)
    doSearchCount();
    doSearchDown();
}
<commit_msg>Improve stuck regular expression detection while searching (pbek/QOwnNotes#2302)<commit_after>/*
 * Copyright (c) 2014-2022 Patrizio Bekerle -- <patrizio@bekerle.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 */

#include "qplaintexteditsearchwidget.h"

#include <QDebug>
#include <QEvent>
#include <QKeyEvent>

#include "ui_qplaintexteditsearchwidget.h"

QPlainTextEditSearchWidget::QPlainTextEditSearchWidget(QPlainTextEdit *parent)
    : QWidget(parent),
      ui(new Ui::QPlainTextEditSearchWidget),
      selectionColor(0, 180, 0, 100) {
    ui->setupUi(this);
    _textEdit = parent;
    _darkMode = false;
    hide();
    ui->searchCountLabel->setStyleSheet(QStringLiteral("* {color: grey}"));
    // hiding will leave a open space in the horizontal layout
    ui->searchCountLabel->setEnabled(false);
    _currentSearchResult = 0;
    _searchResultCount = 0;

    connect(ui->closeButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::deactivate);
    connect(ui->searchLineEdit, &QLineEdit::textChanged, this,
            &QPlainTextEditSearchWidget::searchLineEditTextChanged);
    connect(ui->searchDownButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::doSearchDown);
    connect(ui->searchUpButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::doSearchUp);
    connect(ui->replaceToggleButton, &QPushButton::toggled, this,
            &QPlainTextEditSearchWidget::setReplaceMode);
    connect(ui->replaceButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::doReplace);
    connect(ui->replaceAllButton, &QPushButton::clicked, this,
            &QPlainTextEditSearchWidget::doReplaceAll);

    connect(&_debounceTimer, &QTimer::timeout,
            this, &QPlainTextEditSearchWidget::performSearch);

    installEventFilter(this);
    ui->searchLineEdit->installEventFilter(this);
    ui->replaceLineEdit->installEventFilter(this);

#ifdef Q_OS_MAC
    // set the spacing to 8 for OS X
    layout()->setSpacing(8);
    ui->buttonFrame->layout()->setSpacing(9);

    // set the margin to 0 for the top buttons for OS X
    QString buttonStyle = "QPushButton {margin: 0}";
    ui->closeButton->setStyleSheet(buttonStyle);
    ui->searchDownButton->setStyleSheet(buttonStyle);
    ui->searchUpButton->setStyleSheet(buttonStyle);
    ui->replaceToggleButton->setStyleSheet(buttonStyle);
    ui->matchCaseSensitiveButton->setStyleSheet(buttonStyle);
#endif
}

QPlainTextEditSearchWidget::~QPlainTextEditSearchWidget() { delete ui; }

void QPlainTextEditSearchWidget::activate() { activate(true); }

void QPlainTextEditSearchWidget::activateReplace() {
    // replacing is prohibited if the text edit is readonly
    if (_textEdit->isReadOnly()) {
        return;
    }

    ui->searchLineEdit->setText(_textEdit->textCursor().selectedText());
    ui->searchLineEdit->selectAll();
    activate();
    setReplaceMode(true);
}

void QPlainTextEditSearchWidget::deactivate() {
    stopDebounce();

    hide();

    // Clear the search extra selections when closing the search bar
    clearSearchExtraSelections();

    _textEdit->setFocus();
}

void QPlainTextEditSearchWidget::setReplaceMode(bool enabled) {
    ui->replaceToggleButton->setChecked(enabled);
    ui->replaceLabel->setVisible(enabled);
    ui->replaceLineEdit->setVisible(enabled);
    ui->modeLabel->setVisible(enabled);
    ui->buttonFrame->setVisible(enabled);
    ui->matchCaseSensitiveButton->setVisible(enabled);
}

bool QPlainTextEditSearchWidget::eventFilter(QObject *obj, QEvent *event) {
    if (event->type() == QEvent::KeyPress) {
        auto *keyEvent = static_cast<QKeyEvent *>(event);

        if (keyEvent->key() == Qt::Key_Escape) {
            deactivate();
            return true;
        } else if ((!_debounceTimer.isActive() &&
                    keyEvent->modifiers().testFlag(Qt::ShiftModifier) &&
                    (keyEvent->key() == Qt::Key_Return)) ||
                    (keyEvent->key() == Qt::Key_Up)) {
            doSearchUp();
            return true;
        } else if (!_debounceTimer.isActive() &&
                    ((keyEvent->key() == Qt::Key_Return) ||
                     (keyEvent->key() == Qt::Key_Down))) {
            doSearchDown();
            return true;
        } else if (!_debounceTimer.isActive() && keyEvent->key() == Qt::Key_F3) {
            doSearch(!keyEvent->modifiers().testFlag(Qt::ShiftModifier));
            return true;
        }

        //        if ((obj == ui->replaceLineEdit) && (keyEvent->key() ==
        //        Qt::Key_Tab)
        //                && ui->replaceToggleButton->isChecked()) {
        //            ui->replaceLineEdit->setFocus();
        //        }

        return false;
    }

    return QWidget::eventFilter(obj, event);
}

void QPlainTextEditSearchWidget::searchLineEditTextChanged(
    const QString &arg1) {
    _searchTerm = arg1;

    if (_debounceTimer.interval() != 0 && !_searchTerm.isEmpty()) {
        _debounceTimer.start();
        ui->searchDownButton->setEnabled(false);
        ui->searchUpButton->setEnabled(false);
    } else {
        performSearch();
    }
}

void QPlainTextEditSearchWidget::performSearch()
{
    doSearchCount();
    updateSearchExtraSelections();
    doSearchDown();
}

void QPlainTextEditSearchWidget::clearSearchExtraSelections() {
    _searchExtraSelections.clear();
    setSearchExtraSelections();
}

void QPlainTextEditSearchWidget::updateSearchExtraSelections() {
    _searchExtraSelections.clear();
    const auto textCursor = _textEdit->textCursor();
    _textEdit->moveCursor(QTextCursor::Start);
    const QColor color = selectionColor;
    QTextCharFormat extraFmt;
    extraFmt.setBackground(color);

    while (doSearch(true, false, false)) {
        QTextEdit::ExtraSelection extra = QTextEdit::ExtraSelection();
        extra.format = extraFmt;

        extra.cursor = _textEdit->textCursor();
        _searchExtraSelections.append(extra);
    }

    _textEdit->setTextCursor(textCursor);
    this->setSearchExtraSelections();
}

void QPlainTextEditSearchWidget::setSearchExtraSelections() const {
    this->_textEdit->setExtraSelections(this->_searchExtraSelections);
}

void QPlainTextEditSearchWidget::stopDebounce()
{
    _debounceTimer.stop();
    ui->searchDownButton->setEnabled(true);
    ui->searchUpButton->setEnabled(true);
}

void QPlainTextEditSearchWidget::doSearchUp() { doSearch(false); }

void QPlainTextEditSearchWidget::doSearchDown() { doSearch(true); }

bool QPlainTextEditSearchWidget::doReplace(bool forAll) {
    if (_textEdit->isReadOnly()) {
        return false;
    }

    QTextCursor cursor = _textEdit->textCursor();

    if (!forAll && cursor.selectedText().isEmpty()) {
        return false;
    }

    const int searchMode = ui->modeComboBox->currentIndex();
    if (searchMode == RegularExpressionMode) {
        QString text = cursor.selectedText();
        text.replace(QRegularExpression(ui->searchLineEdit->text()),
                     ui->replaceLineEdit->text());
        cursor.insertText(text);
    } else {
        cursor.insertText(ui->replaceLineEdit->text());
    }

    if (!forAll) {
        const int position = cursor.position();

        if (!doSearch(true)) {
            // restore the last cursor position if text wasn't found any more
            cursor.setPosition(position);
            _textEdit->setTextCursor(cursor);
        }
    }

    return true;
}

void QPlainTextEditSearchWidget::doReplaceAll() {
    if (_textEdit->isReadOnly()) {
        return;
    }

    // start at the top
    _textEdit->moveCursor(QTextCursor::Start);

    // replace until everything to the bottom is replaced
    while (doSearch(true, false) && doReplace(true)) {
    }
}

/**
 * @brief Searches for text in the text edit
 * @returns true if found
 */
bool QPlainTextEditSearchWidget::doSearch(bool searchDown,
                                          bool allowRestartAtTop,
                                          bool updateUI) {
    if (_debounceTimer.isActive()) {
        stopDebounce();
    }

    const QString text = ui->searchLineEdit->text();

    if (text.isEmpty()) {
        if (updateUI) {
            ui->searchLineEdit->setStyleSheet(QLatin1String(""));
        }

        return false;
    }

    const int searchMode = ui->modeComboBox->currentIndex();

    if (searchMode == RegularExpressionMode) {
        // Prevent stuck application when the user enters just start or end markers
        static const QRegularExpression regExp(R"(^[\^\$]+$)");
        if (regExp.match(text).hasMatch()) {
            clearSearchExtraSelections();

            if (_debounceTimer.isActive()) {
                stopDebounce();
            }
            return false;
        }
    }

    const bool caseSensitive = ui->matchCaseSensitiveButton->isChecked();

    QFlags<QTextDocument::FindFlag> options =
        searchDown ? QTextDocument::FindFlag(0) : QTextDocument::FindBackward;
    if (searchMode == WholeWordsMode) {
        options |= QTextDocument::FindWholeWords;
    }

    if (caseSensitive) {
        options |= QTextDocument::FindCaseSensitively;
    }

    // block signal to reduce too many signals being fired and too many updates
    _textEdit->blockSignals(true);

    bool found =
        searchMode == RegularExpressionMode
            ?
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
            _textEdit->find(
                QRegularExpression(
                    text, caseSensitive
                              ? QRegularExpression::NoPatternOption
                              : QRegularExpression::CaseInsensitiveOption),
                options)
            :
#else
            _textEdit->find(QRegExp(text, caseSensitive ? Qt::CaseSensitive
                                                        : Qt::CaseInsensitive),
                            options)
            :
#endif
            _textEdit->find(text, options);

    _textEdit->blockSignals(false);

    if (found) {
        const int result =
            searchDown ? ++_currentSearchResult : --_currentSearchResult;
        _currentSearchResult = std::min(result, _searchResultCount);

        updateSearchCountLabelText();
    }

    // start at the top (or bottom) if not found
    if (!found && allowRestartAtTop) {
        _textEdit->moveCursor(searchDown ? QTextCursor::Start
                                         : QTextCursor::End);
        found =
            searchMode == RegularExpressionMode
                ?
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
                _textEdit->find(
                    QRegularExpression(
                        text, caseSensitive
                                  ? QRegularExpression::NoPatternOption
                                  : QRegularExpression::CaseInsensitiveOption),
                    options)
                :
#else
                _textEdit->find(
                    QRegExp(text, caseSensitive ? Qt::CaseSensitive
                                                : Qt::CaseInsensitive),
                    options)
                :
#endif
                _textEdit->find(text, options);

        if (found && updateUI) {
            _currentSearchResult = searchDown ? 1 : _searchResultCount;
            updateSearchCountLabelText();
        }
    }

    if (updateUI) {
        const QRect rect = _textEdit->cursorRect();
        QMargins margins = _textEdit->layout()->contentsMargins();
        const int searchWidgetHotArea = _textEdit->height() - this->height();
        const int marginBottom =
            (rect.y() > searchWidgetHotArea) ? (this->height() + 10) : 0;

        // move the search box a bit up if we would block the search result
        if (margins.bottom() != marginBottom) {
            margins.setBottom(marginBottom);
            _textEdit->layout()->setContentsMargins(margins);
        }

        // add a background color according if we found the text or not
        const QString bgColorCode =
            _darkMode
                ? (found ? QStringLiteral("#135a13")
                         : QStringLiteral("#8d2b36"))
                : found ? QStringLiteral("#D5FAE2") : QStringLiteral("#FAE9EB");
        const QString fgColorCode =
            _darkMode ? QStringLiteral("#cccccc") : QStringLiteral("#404040");

        ui->searchLineEdit->setStyleSheet(
            QStringLiteral("* { background: ") + bgColorCode +
            QStringLiteral("; color: ") + fgColorCode + QStringLiteral("; }"));

        // restore the search extra selections after the find command
        this->setSearchExtraSelections();
    }

    return found;
}

/**
 * @brief Counts the search results
 */
void QPlainTextEditSearchWidget::doSearchCount() {
    // Note that we are moving the anchor, so the search will start from the top
    // again! Alternative: Restore cursor position afterwards, but then we will
    // not know
    //              at what _currentSearchResult we currently are
    _textEdit->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor);

    bool found;
    _searchResultCount = 0;
    _currentSearchResult = 0;

    do {
        found = doSearch(true, false, false);
        if (found) {
            _searchResultCount++;
        }
    } while (found);

    updateSearchCountLabelText();
}

void QPlainTextEditSearchWidget::setDarkMode(bool enabled) {
    _darkMode = enabled;
}

void QPlainTextEditSearchWidget::setSearchText(const QString &searchText) {
    ui->searchLineEdit->setText(searchText);
}

void QPlainTextEditSearchWidget::setSearchMode(SearchMode searchMode) {
    ui->modeComboBox->setCurrentIndex(searchMode);
}

void QPlainTextEditSearchWidget::setDebounceDelay(uint debounceDelay)
{
    _debounceTimer.setInterval(static_cast<int>(debounceDelay));
}

void QPlainTextEditSearchWidget::activate(bool focus) {
    setReplaceMode(ui->modeComboBox->currentIndex() !=
                   SearchMode::PlainTextMode);
    show();

    // preset the selected text as search text if there is any and there is no
    // other search text
    const QString selectedText = _textEdit->textCursor().selectedText();
    if (!selectedText.isEmpty() && ui->searchLineEdit->text().isEmpty()) {
        ui->searchLineEdit->setText(selectedText);
    }

    if (focus) {
        ui->searchLineEdit->setFocus();
    }

    ui->searchLineEdit->selectAll();
    updateSearchExtraSelections();
    doSearchDown();
}

void QPlainTextEditSearchWidget::reset() {
    ui->searchLineEdit->clear();
    setSearchMode(SearchMode::PlainTextMode);
    setReplaceMode(false);
    ui->searchCountLabel->setEnabled(false);
}

void QPlainTextEditSearchWidget::updateSearchCountLabelText() {
    ui->searchCountLabel->setEnabled(true);
    ui->searchCountLabel->setText(QString("%1/%2").arg(
        _currentSearchResult == 0 ? QChar('-')
                                  : QString::number(_currentSearchResult),
        _searchResultCount == 0 ? QChar('-')
                                : QString::number(_searchResultCount)));
}

void QPlainTextEditSearchWidget::setSearchSelectionColor(const QColor &color) {
    selectionColor = color;
}

void QPlainTextEditSearchWidget::on_modeComboBox_currentIndexChanged(
    int index) {
    Q_UNUSED(index)
    doSearchCount();
    doSearchDown();
}

void QPlainTextEditSearchWidget::on_matchCaseSensitiveButton_toggled(
    bool checked) {
    Q_UNUSED(checked)
    doSearchCount();
    doSearchDown();
}
<|endoftext|>


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

#include "tflite.h"

#include <cstdint>

#include "perf.h"
#include "playground_util/random.h"
#include "proj_tflite.h"
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/micro_profiler.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tflite_unit_tests.h"

#ifdef TF_LITE_SHOW_MEMORY_USE
#include "tensorflow/lite/micro/recording_micro_interpreter.h"
#define INTERPRETER_TYPE RecordingMicroInterpreter
#else
#define INTERPRETER_TYPE MicroInterpreter
#endif

// For C++ exceptions
void* __dso_handle = &__dso_handle;

//
// TfLM global objects
namespace {

// A profiler that prints a "." for each profile event begun
class ProgressProfiler : public tflite::MicroProfiler {
 public:
  virtual uint32_t BeginEvent(const char* tag) {
    printf(".");
    return tflite::MicroProfiler::BeginEvent(tag);
  }

 private:
  TF_LITE_REMOVE_VIRTUAL_DELETE;
};

tflite::ErrorReporter* error_reporter = nullptr;
tflite::MicroOpResolver* op_resolver = nullptr;
tflite::MicroProfiler* profiler = nullptr;

const tflite::Model* model = nullptr;
tflite::INTERPRETER_TYPE* interpreter = nullptr;

// C++ 11 does not have a constexpr std::max.
// For this reason, a small implementation is written.
template <typename T>
constexpr T const& const_max(const T& x) {
  return x;
}

template <typename T, typename... Args>
constexpr T const& const_max(const T& x, const T& y, const Args&... rest) {
  return const_max(x > y ? x : y, rest...);
}

// Get the smallest kTensorArenaSize possible.
constexpr int kTensorArenaSize = const_max<int>(
#ifdef INCLUDE_MODEL_PDTI8
    81 * 1024,
#endif
#ifdef INCLUDE_MODEL_MICRO_SPEECH
    7 * 1024,
#endif
#ifdef INCLUDE_MODEL_MAGIC_WAND
    5 * 1024,
#endif
#ifdef INCLUDE_MODEL_MNV2
    800 * 1024,
#endif
#ifdef INCLUDE_MODEL_HPS
    1024 * 1024,
#endif
#ifdef INLCUDE_MODEL_MLCOMMONS_TINY_V01_ANOMD
    3 * 1024,
#endif
#ifdef INLCUDE_MODEL_MLCOMMONS_TINY_V01_IMGC
    53 * 1024,
#endif
#ifdef INLCUDE_MODEL_MLCOMMONS_TINY_V01_KWS
    23 * 1024,
#endif
#ifdef INLCUDE_MODEL_MLCOMMONS_TINY_V01_VWW
    99 * 1024,
#endif
    0 /* When no models defined, we don't need a tensor arena. */
);

static uint8_t tensor_arena[kTensorArenaSize];
}  // anonymous namespace

static void tflite_init() {
  static bool initialized = false;
  if (initialized) {
    return;
  }
  initialized = true;

  // Sets up error reporting etc
  static tflite::MicroErrorReporter micro_error_reporter;
  error_reporter = &micro_error_reporter;
  TF_LITE_REPORT_ERROR(error_reporter, "Error_reporter OK!");

  // Pull in only the operation implementations we need.
  // This relies on a complete list of all the ops needed by this graph.
  // An easier approach is to just use the AllOpsResolver, but this will
  // incur some penalty in code space for op implementations that are not
  // needed by this graph.
  //
  static tflite::AllOpsResolver resolver;
  op_resolver = &resolver;
  // // NOLINTNEXTLINE(runtime-global-variables)
  // static tflite::MicroMutableOpResolver<8> micro_op_resolver;
  // micro_op_resolver.AddAveragePool2D();
  // micro_op_resolver.AddConv2D();
  // micro_op_resolver.AddDepthwiseConv2D();
  // micro_op_resolver.AddReshape();
  // micro_op_resolver.AddSoftmax();

  // // needed for jon's model conv2d/relu, maxpool2d, reshape, fullyconnected,
  // logistic micro_op_resolver.AddMaxPool2D();
  // micro_op_resolver.AddFullyConnected();
  // micro_op_resolver.AddLogistic();

  // // needed for MODEL=magic_wand_full_i8
  // // micro_op_resolver.AddQuantize();
  // op_resolver = &micro_op_resolver;

  // profiler
  static ProgressProfiler micro_profiler;
  profiler = &micro_profiler;
}

void tflite_load_model(const unsigned char* model_data,
                       unsigned int model_length) {
  tflite_init();
  tflite_preload(model_data, model_length);
  if (interpreter) {
    interpreter->~INTERPRETER_TYPE();
    interpreter = nullptr;
  }

  // Map the model into a usable data structure. This doesn't involve any
  // copying or parsing, it's a very lightweight operation.
  model = tflite::GetModel(model_data);

  // Build an interpreter to run the model with.
  // NOLINTNEXTLINE(runtime-global-variables)
  alignas(tflite::INTERPRETER_TYPE) static unsigned char
      buf[sizeof(tflite::INTERPRETER_TYPE)];
  interpreter = new (buf)
      tflite::INTERPRETER_TYPE(model, *op_resolver, tensor_arena,
                               kTensorArenaSize, error_reporter, profiler);

  // Allocate memory from the tensor_arena for the model's tensors.
  TfLiteStatus allocate_status = interpreter->AllocateTensors();
  if (allocate_status != kTfLiteOk) {
    TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
    return;
  }

#ifdef TF_LITE_SHOW_MEMORY_USE
  interpreter->GetMicroAllocator().PrintAllocations();
#endif

  // Get information about the memory area to use for the model's input.
  auto input = interpreter->input(0);
  auto dims = input->dims;
  printf("Input: %d bytes, %d dims:", input->bytes, dims->size);
  for (int ii = 0; ii < dims->size; ++ii) {
    printf(" %d", dims->data[ii]);
  }
  puts("\n");

  tflite_postload();
}

void tflite_set_input_zeros(void) {
  auto input = interpreter->input(0);
  memset(input->data.int8, 0, input->bytes);
  printf("Zeroed %d bytes at %p\n", input->bytes, input->data.int8);
}

void tflite_set_input_zeros_float() {
  auto input = interpreter->input(0);
  memset(input->data.f, 0, input->bytes);
  printf("Zeroed %d bytes at %p\n", input->bytes, input->data.f);
}

void tflite_set_input(const void* data) {
  auto input = interpreter->input(0);
  memcpy(input->data.int8, data, input->bytes);
  printf("Copied %d bytes at %p\n", input->bytes, input->data.int8);
}

void tflite_set_input_unsigned(const unsigned char* data) {
  auto input = interpreter->input(0);
  for (size_t i = 0; i < input->bytes; i++) {
    input->data.int8[i] = static_cast<int>(data[i]) - 128;
  }
  printf("Set %d bytes at %p\n", input->bytes, input->data.int8);
}

void tflite_set_input_float(const float* data) {
  auto input = interpreter->input(0);
  memcpy(input->data.f, data, input->bytes);
  printf("Copied %d bytes at %p\n", input->bytes, input->data.f);
}

void tflite_randomize_input(int64_t seed) {
  int64_t r = seed;
  auto input = interpreter->input(0);
  for (size_t i = 0; i < input->bytes; i++) {
    input->data.int8[i] = static_cast<int8_t>(next_pseudo_random(&r));
  }
  printf("Set %d bytes at %p\n", input->bytes, input->data.int8);
}

void tflite_set_grid_input(void) {
  auto input = interpreter->input(0);
  size_t height = input->dims->data[1];
  size_t width = input->dims->data[2];
  for (size_t y = 0; y < height; y++) {
    for (size_t x = 0; x < width; x++) {
      int8_t val = (y & 0x20) & (x & 0x20) ? -128 : 127;
      input->data.int8[x + y * width] = val;
    }
  }
  printf("Set %d bytes at %p\n", input->bytes, input->data.int8);
}

int8_t* tflite_get_output() { return interpreter->output(0)->data.int8; }

float* tflite_get_output_float() { return interpreter->output(0)->data.f; }

void tflite_classify() {
  // Run the model on this input and make sure it succeeds.
  profiler->ClearEvents();
  perf_reset_all_counters();

  // perf_set_mcycle is a no-op for some boards, start and end used instead.
  uint32_t start = perf_get_mcycle();
  if (kTfLiteOk != interpreter->Invoke()) {
    puts("Invoke failed.");
  }
  uint32_t end = perf_get_mcycle();
#ifndef NPROFILE
  profiler->LogCsv();
  perf_print_all_counters();
#endif
  perf_print_value(end - start); // Possible overflow is intentional here.
  printf(" cycles total\n");
}

int8_t* get_input() { return interpreter->input(0)->data.int8; }
<commit_msg>tflite.cc: fix LogCsv format<commit_after>// Copyright 2021 The CFU-Playground Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "tflite.h"

#include <cstdint>

#include "perf.h"
#include "playground_util/random.h"
#include "proj_tflite.h"
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/micro_profiler.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tflite_unit_tests.h"

#ifdef TF_LITE_SHOW_MEMORY_USE
#include "tensorflow/lite/micro/recording_micro_interpreter.h"
#define INTERPRETER_TYPE RecordingMicroInterpreter
#else
#define INTERPRETER_TYPE MicroInterpreter
#endif

// For C++ exceptions
void* __dso_handle = &__dso_handle;

//
// TfLM global objects
namespace {

// A profiler that prints a "." for each profile event begun
class ProgressProfiler : public tflite::MicroProfiler {
 public:
  virtual uint32_t BeginEvent(const char* tag) {
    printf(".");
    return tflite::MicroProfiler::BeginEvent(tag);
  }

 private:
  TF_LITE_REMOVE_VIRTUAL_DELETE;
};

tflite::ErrorReporter* error_reporter = nullptr;
tflite::MicroOpResolver* op_resolver = nullptr;
tflite::MicroProfiler* profiler = nullptr;

const tflite::Model* model = nullptr;
tflite::INTERPRETER_TYPE* interpreter = nullptr;

// C++ 11 does not have a constexpr std::max.
// For this reason, a small implementation is written.
template <typename T>
constexpr T const& const_max(const T& x) {
  return x;
}

template <typename T, typename... Args>
constexpr T const& const_max(const T& x, const T& y, const Args&... rest) {
  return const_max(x > y ? x : y, rest...);
}

// Get the smallest kTensorArenaSize possible.
constexpr int kTensorArenaSize = const_max<int>(
#ifdef INCLUDE_MODEL_PDTI8
    81 * 1024,
#endif
#ifdef INCLUDE_MODEL_MICRO_SPEECH
    7 * 1024,
#endif
#ifdef INCLUDE_MODEL_MAGIC_WAND
    5 * 1024,
#endif
#ifdef INCLUDE_MODEL_MNV2
    800 * 1024,
#endif
#ifdef INCLUDE_MODEL_HPS
    1024 * 1024,
#endif
#ifdef INLCUDE_MODEL_MLCOMMONS_TINY_V01_ANOMD
    3 * 1024,
#endif
#ifdef INLCUDE_MODEL_MLCOMMONS_TINY_V01_IMGC
    53 * 1024,
#endif
#ifdef INLCUDE_MODEL_MLCOMMONS_TINY_V01_KWS
    23 * 1024,
#endif
#ifdef INLCUDE_MODEL_MLCOMMONS_TINY_V01_VWW
    99 * 1024,
#endif
    0 /* When no models defined, we don't need a tensor arena. */
);

static uint8_t tensor_arena[kTensorArenaSize];
}  // anonymous namespace

static void tflite_init() {
  static bool initialized = false;
  if (initialized) {
    return;
  }
  initialized = true;

  // Sets up error reporting etc
  static tflite::MicroErrorReporter micro_error_reporter;
  error_reporter = &micro_error_reporter;
  TF_LITE_REPORT_ERROR(error_reporter, "Error_reporter OK!");

  // Pull in only the operation implementations we need.
  // This relies on a complete list of all the ops needed by this graph.
  // An easier approach is to just use the AllOpsResolver, but this will
  // incur some penalty in code space for op implementations that are not
  // needed by this graph.
  //
  static tflite::AllOpsResolver resolver;
  op_resolver = &resolver;
  // // NOLINTNEXTLINE(runtime-global-variables)
  // static tflite::MicroMutableOpResolver<8> micro_op_resolver;
  // micro_op_resolver.AddAveragePool2D();
  // micro_op_resolver.AddConv2D();
  // micro_op_resolver.AddDepthwiseConv2D();
  // micro_op_resolver.AddReshape();
  // micro_op_resolver.AddSoftmax();

  // // needed for jon's model conv2d/relu, maxpool2d, reshape, fullyconnected,
  // logistic micro_op_resolver.AddMaxPool2D();
  // micro_op_resolver.AddFullyConnected();
  // micro_op_resolver.AddLogistic();

  // // needed for MODEL=magic_wand_full_i8
  // // micro_op_resolver.AddQuantize();
  // op_resolver = &micro_op_resolver;

  // profiler
  static ProgressProfiler micro_profiler;
  profiler = &micro_profiler;
}

void tflite_load_model(const unsigned char* model_data,
                       unsigned int model_length) {
  tflite_init();
  tflite_preload(model_data, model_length);
  if (interpreter) {
    interpreter->~INTERPRETER_TYPE();
    interpreter = nullptr;
  }

  // Map the model into a usable data structure. This doesn't involve any
  // copying or parsing, it's a very lightweight operation.
  model = tflite::GetModel(model_data);

  // Build an interpreter to run the model with.
  // NOLINTNEXTLINE(runtime-global-variables)
  alignas(tflite::INTERPRETER_TYPE) static unsigned char
      buf[sizeof(tflite::INTERPRETER_TYPE)];
  interpreter = new (buf)
      tflite::INTERPRETER_TYPE(model, *op_resolver, tensor_arena,
                               kTensorArenaSize, error_reporter, profiler);

  // Allocate memory from the tensor_arena for the model's tensors.
  TfLiteStatus allocate_status = interpreter->AllocateTensors();
  if (allocate_status != kTfLiteOk) {
    TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
    return;
  }

#ifdef TF_LITE_SHOW_MEMORY_USE
  interpreter->GetMicroAllocator().PrintAllocations();
#endif

  // Get information about the memory area to use for the model's input.
  auto input = interpreter->input(0);
  auto dims = input->dims;
  printf("Input: %d bytes, %d dims:", input->bytes, dims->size);
  for (int ii = 0; ii < dims->size; ++ii) {
    printf(" %d", dims->data[ii]);
  }
  puts("\n");

  tflite_postload();
}

void tflite_set_input_zeros(void) {
  auto input = interpreter->input(0);
  memset(input->data.int8, 0, input->bytes);
  printf("Zeroed %d bytes at %p\n", input->bytes, input->data.int8);
}

void tflite_set_input_zeros_float() {
  auto input = interpreter->input(0);
  memset(input->data.f, 0, input->bytes);
  printf("Zeroed %d bytes at %p\n", input->bytes, input->data.f);
}

void tflite_set_input(const void* data) {
  auto input = interpreter->input(0);
  memcpy(input->data.int8, data, input->bytes);
  printf("Copied %d bytes at %p\n", input->bytes, input->data.int8);
}

void tflite_set_input_unsigned(const unsigned char* data) {
  auto input = interpreter->input(0);
  for (size_t i = 0; i < input->bytes; i++) {
    input->data.int8[i] = static_cast<int>(data[i]) - 128;
  }
  printf("Set %d bytes at %p\n", input->bytes, input->data.int8);
}

void tflite_set_input_float(const float* data) {
  auto input = interpreter->input(0);
  memcpy(input->data.f, data, input->bytes);
  printf("Copied %d bytes at %p\n", input->bytes, input->data.f);
}

void tflite_randomize_input(int64_t seed) {
  int64_t r = seed;
  auto input = interpreter->input(0);
  for (size_t i = 0; i < input->bytes; i++) {
    input->data.int8[i] = static_cast<int8_t>(next_pseudo_random(&r));
  }
  printf("Set %d bytes at %p\n", input->bytes, input->data.int8);
}

void tflite_set_grid_input(void) {
  auto input = interpreter->input(0);
  size_t height = input->dims->data[1];
  size_t width = input->dims->data[2];
  for (size_t y = 0; y < height; y++) {
    for (size_t x = 0; x < width; x++) {
      int8_t val = (y & 0x20) & (x & 0x20) ? -128 : 127;
      input->data.int8[x + y * width] = val;
    }
  }
  printf("Set %d bytes at %p\n", input->bytes, input->data.int8);
}

int8_t* tflite_get_output() { return interpreter->output(0)->data.int8; }

float* tflite_get_output_float() { return interpreter->output(0)->data.f; }

void tflite_classify() {
  // Run the model on this input and make sure it succeeds.
  profiler->ClearEvents();
  perf_reset_all_counters();

  // perf_set_mcycle is a no-op for some boards, start and end used instead.
  uint32_t start = perf_get_mcycle();
  if (kTfLiteOk != interpreter->Invoke()) {
    puts("Invoke failed.");
  }
  uint32_t end = perf_get_mcycle();
#ifndef NPROFILE
  printf("\n");
  profiler->LogCsv();
  perf_print_all_counters();
#endif
  perf_print_value(end - start);  // Possible overflow is intentional here.
  printf(" cycles total\n");
}

int8_t* get_input() { return interpreter->input(0)->data.int8; }
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkIdList.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkIdList.h"
#include "vtkObjectFactory.h"

vtkIdList* vtkIdList::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkIdList");
  if(ret)
    {
    return (vtkIdList*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkIdList;
}

vtkIdList::vtkIdList()
{
  this->NumberOfIds = 0;
  this->Size = 0;
  this->Ids = NULL;
}

vtkIdList::~vtkIdList()
{
  if ( this->Ids != NULL )
    {
    delete [] this->Ids;
    }
}

void vtkIdList::Initialize()
{
  if ( this->Ids != NULL )
    {
    delete [] this->Ids;
    this->Ids = NULL;
    }
  this->NumberOfIds = 0;
  this->Size = 0;
}

int vtkIdList::Allocate(const int sz, const int vtkNotUsed(strategy))
{
  if ( sz > this->Size)
    {
    this->Initialize();
    this->Size = ( sz > 0 ? sz : 1);
    if ( (this->Ids = new int[this->Size]) == NULL )
      {
      return 0;
      }
    }

  this->NumberOfIds = 0;
  return 1;
}

void vtkIdList::SetNumberOfIds(const int number)
{
  this->Allocate(number,0);
  this->NumberOfIds = number;
}

void vtkIdList::InsertId(const int i, const int id)
{
  if ( i >= this->Size )
    {
    this->Resize(i+1);
    }
  this->Ids[i] = id;
  if ( i >= this->NumberOfIds )
    {
    this->NumberOfIds = i + 1;
    }
}

int vtkIdList::InsertNextId(const int id)
{
  if ( this->NumberOfIds >= this->Size )
    {
    this->Resize(this->NumberOfIds+1);
    }
  this->Ids[this->NumberOfIds++] = id;
  return this->NumberOfIds-1;
}

int vtkIdList::InsertUniqueId(const int id)
{
  for (int i=0; i < this->NumberOfIds; i++)
    {
    if ( id == this->Ids[i] )
      {
      return i;
      }
    }

  return this->InsertNextId(id);
}

int *vtkIdList::WritePointer(const int i, const int number)
{
  int newSize=i+number;
  if ( newSize > this->Size )
    {
    this->Resize(newSize);
    }
  if ( newSize > this->NumberOfIds )
    {
    this->NumberOfIds = newSize;
    }
  return this->Ids + i;
}

void vtkIdList::DeleteId(int id)
{
  int i=0;

  // while loop is necessary to delete all occurences of id
  while ( i < this->NumberOfIds )
    {
    for ( ; i < this->NumberOfIds; i++)
      {
      if ( this->Ids[i] == id )
        {
        break;
        }
      }

    // if found; replace current id with last
    if ( i < this->NumberOfIds )
      {
      this->SetId(i,this->Ids[this->NumberOfIds-1]);
      this->NumberOfIds--;
      }
    }
}

void vtkIdList::DeepCopy(vtkIdList *ids)
{
  ids->Initialize();
  ids->NumberOfIds = this->NumberOfIds;
  ids->Size = this->Size;
  ids->Ids = new int [this->Size];
  for (int i=0; i < this->NumberOfIds; i++)
    {
    ids->Ids[i] = this->Ids[i];
    }
}

int *vtkIdList::Resize(const int sz)
{
  int *newIds;
  int newSize;

  if ( sz > this->Size )
    {
    newSize = this->Size + sz;
    }
  else if (sz == this->Size)
    {
    return this->Ids;
    }
  else
    {
    newSize = sz;
    }

  if (newSize <= 0)
    {
    this->Initialize();
    return 0;
    }

  if ( (newIds = new int[newSize]) == NULL )
    {
    vtkErrorMacro(<< "Cannot allocate memory\n");
    return 0;
    }

  if (this->Ids)
    {
    memcpy(newIds, this->Ids,
           (sz < this->Size ? sz : this->Size) * sizeof(int));
    delete [] this->Ids;
    }

  this->Size = newSize;
  this->Ids = newIds;
  return this->Ids;
}

#define VTK_TMP_ARRAY_SIZE 500
// Intersect this list with another vtkIdList. Updates current list according
// to result of intersection operation.
void vtkIdList::IntersectWith(vtkIdList& otherIds)
{
  // Fast method due to Dr. Andreas Mueller of ISE Integrated Systems
  // Engineering (CH).
  int thisNumIds = this->GetNumberOfIds();

  if (thisNumIds <= VTK_TMP_ARRAY_SIZE)
    {//Use fast method if we can fit in temporary storage
    int  thisIds[VTK_TMP_ARRAY_SIZE];
    int  i, id;

    for (i=0; i < thisNumIds; i++)
      {
      thisIds[i] = this->GetId(i);
      }
    for (this->Reset(), i=0; i < thisNumIds; i++)
      {
      id = thisIds[i];
      if ( otherIds.IsId(id) != (-1) )
        {
        this->InsertNextId(id);
        }
      }
    }
  else
    {//use slower method for extreme cases
    int  *thisIds = new int [thisNumIds];
    int  i, id;

    for (i=0; i < thisNumIds; i++)
      {
      *(thisIds + i) = this->GetId(i);
      }
    for (this->Reset(), i=0; i < thisNumIds; i++)
      {
      id = *(thisIds + i);
      if ( otherIds.IsId(id) != (-1) )
        {
        this->InsertNextId(id);
        }
      }
    delete [] thisIds;
    }
}
#undef VTK_TMP_ARRAY_SIZE

void vtkIdList::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkObject::PrintSelf(os,indent);

  os << indent << "Number of Ids: " << this->NumberOfIds << "\n";
}
<commit_msg>ERR: DeepCopy had from and to reversed.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkIdList.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkIdList.h"
#include "vtkObjectFactory.h"

vtkIdList* vtkIdList::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkObjectFactory::CreateInstance("vtkIdList");
  if(ret)
    {
    return (vtkIdList*)ret;
    }
  // If the factory was unable to create the object, then create it here.
  return new vtkIdList;
}

vtkIdList::vtkIdList()
{
  this->NumberOfIds = 0;
  this->Size = 0;
  this->Ids = NULL;
}

vtkIdList::~vtkIdList()
{
  if ( this->Ids != NULL )
    {
    delete [] this->Ids;
    }
}

void vtkIdList::Initialize()
{
  if ( this->Ids != NULL )
    {
    delete [] this->Ids;
    this->Ids = NULL;
    }
  this->NumberOfIds = 0;
  this->Size = 0;
}

int vtkIdList::Allocate(const int sz, const int vtkNotUsed(strategy))
{
  if ( sz > this->Size)
    {
    this->Initialize();
    this->Size = ( sz > 0 ? sz : 1);
    if ( (this->Ids = new int[this->Size]) == NULL )
      {
      return 0;
      }
    }
  this->NumberOfIds = 0;
  return 1;
}

void vtkIdList::SetNumberOfIds(const int number)
{
  this->Allocate(number,0);
  this->NumberOfIds = number;
}

void vtkIdList::InsertId(const int i, const int id)
{
  if ( i >= this->Size )
    {
    this->Resize(i+1);
    }
  this->Ids[i] = id;
  if ( i >= this->NumberOfIds )
    {
    this->NumberOfIds = i + 1;
    }
}

int vtkIdList::InsertNextId(const int id)
{
  if ( this->NumberOfIds >= this->Size )
    {
    this->Resize(this->NumberOfIds+1);
    }
  this->Ids[this->NumberOfIds++] = id;
  return this->NumberOfIds-1;
}

int vtkIdList::InsertUniqueId(const int id)
{
  for (int i=0; i < this->NumberOfIds; i++)
    {
    if ( id == this->Ids[i] )
      {
      return i;
      }
    }

  return this->InsertNextId(id);
}

int *vtkIdList::WritePointer(const int i, const int number)
{
  int newSize=i+number;
  if ( newSize > this->Size )
    {
    this->Resize(newSize);
    }
  if ( newSize > this->NumberOfIds )
    {
    this->NumberOfIds = newSize;
    }
  return this->Ids + i;
}

void vtkIdList::DeleteId(int id)
{
  int i=0;

  // while loop is necessary to delete all occurences of id
  while ( i < this->NumberOfIds )
    {
    for ( ; i < this->NumberOfIds; i++)
      {
      if ( this->Ids[i] == id )
        {
        break;
        }
      }

    // if found; replace current id with last
    if ( i < this->NumberOfIds )
      {
      this->SetId(i,this->Ids[this->NumberOfIds-1]);
      this->NumberOfIds--;
      }
    }
}

void vtkIdList::DeepCopy(vtkIdList *ids)
{
  this->Initialize();
  this->NumberOfIds = ids->NumberOfIds;
  this->Size = ids->Size;
  this->Ids = new int [ids->Size];
  for (int i=0; i < ids->NumberOfIds; i++)
    {
    this->Ids[i] = ids->Ids[i];
    }
}

int *vtkIdList::Resize(const int sz)
{
  int *newIds;
  int newSize;

  if ( sz > this->Size )
    {
    newSize = this->Size + sz;
    }
  else if (sz == this->Size)
    {
    return this->Ids;
    }
  else
    {
    newSize = sz;
    }

  if (newSize <= 0)
    {
    this->Initialize();
    return 0;
    }

  if ( (newIds = new int[newSize]) == NULL )
    {
    vtkErrorMacro(<< "Cannot allocate memory\n");
    return 0;
    }

  if (this->Ids)
    {
    memcpy(newIds, this->Ids,
           (sz < this->Size ? sz : this->Size) * sizeof(int));
    delete [] this->Ids;
    }

  this->Size = newSize;
  this->Ids = newIds;
  return this->Ids;
}

#define VTK_TMP_ARRAY_SIZE 500
// Intersect this list with another vtkIdList. Updates current list according
// to result of intersection operation.
void vtkIdList::IntersectWith(vtkIdList& otherIds)
{
  // Fast method due to Dr. Andreas Mueller of ISE Integrated Systems
  // Engineering (CH).
  int thisNumIds = this->GetNumberOfIds();

  if (thisNumIds <= VTK_TMP_ARRAY_SIZE)
    {//Use fast method if we can fit in temporary storage
    int  thisIds[VTK_TMP_ARRAY_SIZE];
    int  i, id;

    for (i=0; i < thisNumIds; i++)
      {
      thisIds[i] = this->GetId(i);
      }
    for (this->Reset(), i=0; i < thisNumIds; i++)
      {
      id = thisIds[i];
      if ( otherIds.IsId(id) != (-1) )
        {
        this->InsertNextId(id);
        }
      }
    }
  else
    {//use slower method for extreme cases
    int  *thisIds = new int [thisNumIds];
    int  i, id;

    for (i=0; i < thisNumIds; i++)
      {
      *(thisIds + i) = this->GetId(i);
      }
    for (this->Reset(), i=0; i < thisNumIds; i++)
      {
      id = *(thisIds + i);
      if ( otherIds.IsId(id) != (-1) )
        {
        this->InsertNextId(id);
        }
      }
    delete [] thisIds;
    }
}
#undef VTK_TMP_ARRAY_SIZE

void vtkIdList::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkObject::PrintSelf(os,indent);

  os << indent << "Number of Ids: " << this->NumberOfIds << "\n";
}
<|endoftext|>