<commit_before>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/testing.h>
#include <xzero/Flags.h>
#include <xzero/logging/Logger.h>
#include <xzero/Application.h>
#include <xzero/AnsiColor.h>
#include <xzero/StringUtil.h>
#include <xzero/logging.h>
#include <algorithm>
#include <random>
#include <chrono>
#include <cstdlib>
#include <fnmatch.h>

namespace xzero {
namespace testing {

int main(int argc, const char* argv[]) {
  return UnitTest::instance()->main(argc, argv);
}

// ############################################################################

class BailOutException {
 public:
  BailOutException() {}
};

// ############################################################################

Environment::~Environment() {
}

void Environment::SetUp() {
}

void Environment::TearDown() {
}

// ############################################################################

Test::~Test() {
}

void Test::SetUp() {
}

void Test::TearDown() {
}

void Test::log(const std::string& message) {
  UnitTest::instance()->log(message);
}

// ############################################################################

TestInfo::TestInfo(const std::string& testCaseName,
    const std::string& testName,
    bool enabled,
    std::unique_ptr<TestFactory>&& testFactory)
  : testCaseName_(testCaseName),
    testName_(testName),
    enabled_(enabled),
    testFactory_(std::move(testFactory)) {
}

// ############################################################################

static std::string colorsReset = AnsiColor::make(AnsiColor::Reset);
static std::string colorsTestCaseHeader = AnsiColor::make(AnsiColor::Cyan);
static std::string colorsError = AnsiColor::make(AnsiColor::Red | AnsiColor::Bold);
static std::string colorsOk = AnsiColor::make(AnsiColor::Green);

UnitTest::UnitTest()
  : environments_(),
    testCases_(),
    activeTests_(),
    filter_("*"),
    repeats_(1),
    printProgress_(false),
    printSummaryDetails_(true),
    currentTestCase_(nullptr),
    currentCount_(0),
    successCount_(0),
    failCount_(0) {
}

UnitTest::~UnitTest() {
}

UnitTest* UnitTest::instance() {
  static UnitTest unitTest;
  return &unitTest;
}

void UnitTest::randomizeTestOrder() {
  unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();

  std::shuffle(activeTests_.begin(), activeTests_.end(),
      std::default_random_engine(seed));
}

void UnitTest::sortTestsAlphabetically() {
  std::sort(
      activeTests_.begin(),
      activeTests_.end(),
      [this](size_t a, size_t b) -> bool {
        TestInfo* left = testCases_[a].get();
        TestInfo* right = testCases_[b].get();

        if (left->testCaseName() < right->testCaseName())
          return true;

        if (left->testCaseName() == right->testCaseName())
          return left->testName() < right->testName();

        return false;
      });
}

int UnitTest::main(int argc, const char* argv[]) {
  // TODO: add CLI parameters (preferably gtest compatible)
  //
  // --no-color | --color   explicitely enable/disable color output
  // --filter=REGEX         filter tests by regular expression
  // --randomize            randomize test order
  // --repeats=NUMBER        repeats tests given number of times
  // --list[-tests]         Just list the tests and exit.

  Application::init();

  Flags flags;
  flags.defineBool("help", 'h', "Prints this help and terminates.")
       .defineBool("verbose", 'v', "Prints to console in debug log level.")
       .defineString("log-level", 'L', "ENUM", "Defines the minimum log level.", "info")
       .defineString("log-target", 0, "ENUM", "Specifies logging target. One of syslog, file, systemd, console.", "")
       .defineString("filter", 'f', "GLOB", "Filters tests by given glob.", "*")
       .defineBool("list", 'l', "Prints all tests and exits.")
       .defineBool("randomize", 'R', "Randomizes test order.")
       .defineBool("sort", 's', "Sorts tests alphabetically ascending.")
       .defineBool("no-progress", 0, "Avoids printing progress.")
       .defineNumber("repeat", 'r', "COUNT", "Repeat tests given number of times.", 1)
       ;

  std::error_code ec = flags.parse(argc, argv);
  if (ec) {
    fprintf(stderr, "Failed to parse flags. %s\n", ec.message().c_str());
    return 1;
  }

  if (flags.getBool("help")) {
    printf("%s\n", flags.helpText().c_str());
    return 0;
  }

  if (flags.getBool("verbose")) {
    Application::logToStderr(LogLevel::Debug);
  }

  Logger::get()->setMinimumLogLevel(make_loglevel(flags.getString("log-level")));

  if (flags.isSet("log-target")) {
    std::string logTargetStr = flags.getString("log-target");
    // TODO: log-target
  }

  filter_ = flags.getString("filter");
  repeats_ = flags.getNumber("repeat");
  printProgress_ = !flags.getBool("no-progress");

  if (flags.getBool("randomize"))
    randomizeTestOrder();
  else if (flags.getBool("sort"))
    sortTestsAlphabetically();

  { // if (filter_ != "*") {
    std::vector<size_t> filtered;
    for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
      TestInfo* testInfo = testCases_[activeTests_[i]].get();
      std::string matchName = StringUtil::format("$0.$1",
          testInfo->testCaseName(), testInfo->testName());
      const int flags = 0;

      if (fnmatch(filter_.c_str(), matchName.c_str(), flags) == 0) {
        filtered.push_back(activeTests_[i]);
      }
    }
    activeTests_ = std::move(filtered);
  }

  if (flags.getBool("list")) {
    printTestList();
    return 0;
  }

  for (auto& env: environments_) {
    env->SetUp();
  }

  for (auto& init: initializers_) {
    init->invoke();
  }

  for (int i = 0; i < repeats_; i++) {
    runAllTestsOnce();
  }

  for (auto& env: environments_) {
    env->TearDown();
  }

  printSummary();

  return failCount_ == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

void UnitTest::printTestList() {
  for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
    TestInfo* testCase = testCases_[activeTests_[i]].get();
    printf("%4zu. %s.%s\n",
        i + 1,
        testCase->testCaseName().c_str(),
        testCase->testName().c_str());
  }
}

void UnitTest::printSummary() {
  // print summary
  printf("%sFinished running %d repeats, %zu tests. %zu success, %d failed, %zu disabled.%s\n",
      failCount_ ? colorsError.c_str()
                : colorsOk.c_str(),
      repeats_,
      activeTests_.size(),
      successCount_,
      failCount_,
      disabledCount(),
      colorsReset.c_str());

  if (printSummaryDetails_ && !failures_.empty()) {
    printf("================================\n");
    printf(" Summary:\n");
    printf("================================\n");

    for (size_t i = 0, e = failures_.size(); i != e; ++i) {
      const auto& failure = failures_[i];
      printf("%s%s%s\n",
          colorsError.c_str(),
          failure.c_str(),
          colorsReset.c_str());
    }
  }
}

size_t UnitTest::enabledCount() const {
  size_t count = 0;

  for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
    if (testCases_[activeTests_[i]]->isEnabled()) {
      count++;
    }
  }

  return count;
}

size_t UnitTest::disabledCount() const {
  size_t count = 0;

  for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
    if (!testCases_[activeTests_[i]]->isEnabled()) {
      count++;
    }
  }

  return count;
}

void UnitTest::runAllTestsOnce() {
  const int totalCount = repeats_ * enabledCount();

  for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
    TestInfo* testCase = testCases_[activeTests_[i]].get();
    std::unique_ptr<Test> test = testCase->createTest();

    if (!testCase->isEnabled())
      continue;

    currentTestCase_ = testCase;
    currentCount_++;
    int percentage = currentCount_ * 100 / totalCount;

    if (printProgress_) {
      printf("%s%3d%% Running test: %s.%s%s\n",
          colorsTestCaseHeader.c_str(),
          percentage,
          testCase->testCaseName().c_str(),
          testCase->testName().c_str(),
          colorsReset.c_str());
    }

    int failed = 0;

    try {
      test->SetUp();
    } catch (const BailOutException&) {
      // SHOULD NOT HAPPEND: complain about it
      failed++;
    } catch (...) {
      // TODO: report failure upon set-up phase, hence skipping actual test
      failed++;
    }

    if (!failed) {
      try {
        test->TestBody();
      } catch (const BailOutException&) {
        // no-op
        failed++;
      } catch (const RuntimeError& ex) {
        reportMessage(
            StringUtil::format(
              "Unhandled exception caught in test. $0 ($1:$2 $3)",
              ex.what(),
              ex.sourceFile(),
              ex.sourceLine(),
              ex.functionName()),
            false);
        failed++;
      } catch (const std::exception& ex) {
        reportMessage(
            StringUtil::format("Unhandled exception caught in test. $0", ex.what()),
            false);
        failed++;
      } catch (...) {
        reportMessage("Unhandled exception caught in test.", false);
        failed++;
      }

      try {
        test->TearDown();
      } catch (const BailOutException&) {
        // SHOULD NOT HAPPEND: complain about it
        failed++;
      } catch (...) {
        // TODO: report failure in tear-down
        failed++;
      }

      if (!failed) {
        successCount_++;
      }
    }
  }
}

void UnitTest::reportBinary(const char* fileName,
                            int lineNo,
                            bool fatal,
                            const char* expected,
                            const char* actual,
                            const std::string& actualEvaluated,
                            const char* op) {
  std::string message = StringUtil::format(
      "$0:$1: Failure\n"
      "  Value of: $2\n"
      "  Expected: $3 $4\n"
      "    Actual: $5\n",
      fileName, lineNo,
      actual,
      expected, op,
      actualEvaluated);

  reportMessage(message, fatal);
}

void UnitTest::reportEH(const char* fileName,
                        int lineNo,
                        bool fatal,
                        const char* program,
                        const char* expected,
                        const char* actual) {
  std::string message = StringUtil::format(
      "$0:$1: $2\n"
      "  Value of: $3\n"
      "  Expected: $4\n"
      "    Actual: $5\n",
      fileName, lineNo,
      actual ? "Unexpected exception caught"
             : "No exception caught",
      program,
      expected,
      actual);

  reportMessage(message, fatal);
}

void UnitTest::reportMessage(const std::string& message, bool fatal) {
  printf("%s%s%s\n",
      colorsError.c_str(),
      message.c_str(),
      colorsReset.c_str());

  failCount_++;
  failures_.emplace_back(message);

  if (fatal) {
    throw BailOutException();
  }
}

void UnitTest::addEnvironment(std::unique_ptr<Environment>&& env) {
  environments_.emplace_back(std::move(env));
}

Callback* UnitTest::addInitializer(std::unique_ptr<Callback>&& cb) {
  initializers_.emplace_back(std::move(cb));
  return initializers_.back().get();
}

TestInfo* UnitTest::addTest(const char* testCaseName,
                            const char* testName,
                            std::unique_ptr<TestFactory>&& testFactory) {
  testCases_.emplace_back(
      new TestInfo(
          testCaseName,
          testName,
          !StringUtil::beginsWith(testCaseName, "DISABLED_")
              && !StringUtil::beginsWith(testName, "DISABLED_"),
          std::move(testFactory)));

  activeTests_.emplace_back(activeTests_.size());

  return testCases_.back().get();
}

void UnitTest::log(const std::string& message) {
  std::string component = StringUtil::format("$0.$1",
      currentTestCase_->testCaseName(),
      currentTestCase_->testName());
  logDebug(component, "$0", message);
}

} // namespace testing
} // namespace xzero
<commit_msg>[xzero] UnitTest: improves readability of printSummary()'s output<commit_after>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/testing.h>
#include <xzero/Flags.h>
#include <xzero/logging/Logger.h>
#include <xzero/Application.h>
#include <xzero/AnsiColor.h>
#include <xzero/StringUtil.h>
#include <xzero/logging.h>
#include <algorithm>
#include <random>
#include <chrono>
#include <cstdlib>
#include <fnmatch.h>

namespace xzero {
namespace testing {

int main(int argc, const char* argv[]) {
  return UnitTest::instance()->main(argc, argv);
}

// ############################################################################

class BailOutException {
 public:
  BailOutException() {}
};

// ############################################################################

Environment::~Environment() {
}

void Environment::SetUp() {
}

void Environment::TearDown() {
}

// ############################################################################

Test::~Test() {
}

void Test::SetUp() {
}

void Test::TearDown() {
}

void Test::log(const std::string& message) {
  UnitTest::instance()->log(message);
}

// ############################################################################

TestInfo::TestInfo(const std::string& testCaseName,
    const std::string& testName,
    bool enabled,
    std::unique_ptr<TestFactory>&& testFactory)
  : testCaseName_(testCaseName),
    testName_(testName),
    enabled_(enabled),
    testFactory_(std::move(testFactory)) {
}

// ############################################################################

static std::string colorsReset = AnsiColor::make(AnsiColor::Reset);
static std::string colorsTestCaseHeader = AnsiColor::make(AnsiColor::Cyan);
static std::string colorsError = AnsiColor::make(AnsiColor::Red | AnsiColor::Bold);
static std::string colorsOk = AnsiColor::make(AnsiColor::Green);

UnitTest::UnitTest()
  : environments_(),
    testCases_(),
    activeTests_(),
    filter_("*"),
    repeats_(1),
    printProgress_(false),
    printSummaryDetails_(true),
    currentTestCase_(nullptr),
    currentCount_(0),
    successCount_(0),
    failCount_(0) {
}

UnitTest::~UnitTest() {
}

UnitTest* UnitTest::instance() {
  static UnitTest unitTest;
  return &unitTest;
}

void UnitTest::randomizeTestOrder() {
  unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();

  std::shuffle(activeTests_.begin(), activeTests_.end(),
      std::default_random_engine(seed));
}

void UnitTest::sortTestsAlphabetically() {
  std::sort(
      activeTests_.begin(),
      activeTests_.end(),
      [this](size_t a, size_t b) -> bool {
        TestInfo* left = testCases_[a].get();
        TestInfo* right = testCases_[b].get();

        if (left->testCaseName() < right->testCaseName())
          return true;

        if (left->testCaseName() == right->testCaseName())
          return left->testName() < right->testName();

        return false;
      });
}

int UnitTest::main(int argc, const char* argv[]) {
  // TODO: add CLI parameters (preferably gtest compatible)
  //
  // --no-color | --color   explicitely enable/disable color output
  // --filter=REGEX         filter tests by regular expression
  // --randomize            randomize test order
  // --repeats=NUMBER        repeats tests given number of times
  // --list[-tests]         Just list the tests and exit.

  Application::init();

  Flags flags;
  flags.defineBool("help", 'h', "Prints this help and terminates.")
       .defineBool("verbose", 'v', "Prints to console in debug log level.")
       .defineString("log-level", 'L', "ENUM", "Defines the minimum log level.", "info")
       .defineString("log-target", 0, "ENUM", "Specifies logging target. One of syslog, file, systemd, console.", "")
       .defineString("filter", 'f', "GLOB", "Filters tests by given glob.", "*")
       .defineBool("list", 'l', "Prints all tests and exits.")
       .defineBool("randomize", 'R', "Randomizes test order.")
       .defineBool("sort", 's', "Sorts tests alphabetically ascending.")
       .defineBool("no-progress", 0, "Avoids printing progress.")
       .defineNumber("repeat", 'r', "COUNT", "Repeat tests given number of times.", 1)
       ;

  std::error_code ec = flags.parse(argc, argv);
  if (ec) {
    fprintf(stderr, "Failed to parse flags. %s\n", ec.message().c_str());
    return 1;
  }

  if (flags.getBool("help")) {
    printf("%s\n", flags.helpText().c_str());
    return 0;
  }

  if (flags.getBool("verbose")) {
    Application::logToStderr(LogLevel::Debug);
  }

  Logger::get()->setMinimumLogLevel(make_loglevel(flags.getString("log-level")));

  if (flags.isSet("log-target")) {
    std::string logTargetStr = flags.getString("log-target");
    // TODO: log-target
  }

  filter_ = flags.getString("filter");
  repeats_ = flags.getNumber("repeat");
  printProgress_ = !flags.getBool("no-progress");

  if (flags.getBool("randomize"))
    randomizeTestOrder();
  else if (flags.getBool("sort"))
    sortTestsAlphabetically();

  { // if (filter_ != "*") {
    std::vector<size_t> filtered;
    for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
      TestInfo* testInfo = testCases_[activeTests_[i]].get();
      std::string matchName = StringUtil::format("$0.$1",
          testInfo->testCaseName(), testInfo->testName());
      const int flags = 0;

      if (fnmatch(filter_.c_str(), matchName.c_str(), flags) == 0) {
        filtered.push_back(activeTests_[i]);
      }
    }
    activeTests_ = std::move(filtered);
  }

  if (flags.getBool("list")) {
    printTestList();
    return 0;
  }

  for (auto& env: environments_) {
    env->SetUp();
  }

  for (auto& init: initializers_) {
    init->invoke();
  }

  for (int i = 0; i < repeats_; i++) {
    runAllTestsOnce();
  }

  for (auto& env: environments_) {
    env->TearDown();
  }

  printSummary();

  return failCount_ == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

void UnitTest::printTestList() {
  for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
    TestInfo* testCase = testCases_[activeTests_[i]].get();
    printf("%4zu. %s.%s\n",
        i + 1,
        testCase->testCaseName().c_str(),
        testCase->testName().c_str());
  }
}

void UnitTest::printSummary() {
  // print summary
  printf("%sFinished running %zu tests (%d repeats). %zu success, %d failed, %zu disabled.%s\n",
      failCount_ ? colorsError.c_str()
                : colorsOk.c_str(),
      repeats_ * activeTests_.size(),
      repeats_,
      successCount_,
      failCount_,
      disabledCount(),
      colorsReset.c_str());

  if (printSummaryDetails_ && !failures_.empty()) {
    printf("================================\n");
    printf(" Summary:\n");
    printf("================================\n");

    for (size_t i = 0, e = failures_.size(); i != e; ++i) {
      const auto& failure = failures_[i];
      printf("%s%s%s\n",
          colorsError.c_str(),
          failure.c_str(),
          colorsReset.c_str());
    }
  }
}

size_t UnitTest::enabledCount() const {
  size_t count = 0;

  for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
    if (testCases_[activeTests_[i]]->isEnabled()) {
      count++;
    }
  }

  return count;
}

size_t UnitTest::disabledCount() const {
  size_t count = 0;

  for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
    if (!testCases_[activeTests_[i]]->isEnabled()) {
      count++;
    }
  }

  return count;
}

void UnitTest::runAllTestsOnce() {
  const int totalCount = repeats_ * enabledCount();

  for (size_t i = 0, e = activeTests_.size(); i != e; ++i) {
    TestInfo* testCase = testCases_[activeTests_[i]].get();
    std::unique_ptr<Test> test = testCase->createTest();

    if (!testCase->isEnabled())
      continue;

    currentTestCase_ = testCase;
    currentCount_++;
    int percentage = currentCount_ * 100 / totalCount;

    if (printProgress_) {
      printf("%s%3d%% Running test: %s.%s%s\n",
          colorsTestCaseHeader.c_str(),
          percentage,
          testCase->testCaseName().c_str(),
          testCase->testName().c_str(),
          colorsReset.c_str());
    }

    int failed = 0;

    try {
      test->SetUp();
    } catch (const BailOutException&) {
      // SHOULD NOT HAPPEND: complain about it
      failed++;
    } catch (...) {
      // TODO: report failure upon set-up phase, hence skipping actual test
      failed++;
    }

    if (!failed) {
      try {
        test->TestBody();
      } catch (const BailOutException&) {
        // no-op
        failed++;
      } catch (const RuntimeError& ex) {
        reportMessage(
            StringUtil::format(
              "Unhandled exception caught in test. $0 ($1:$2 $3)",
              ex.what(),
              ex.sourceFile(),
              ex.sourceLine(),
              ex.functionName()),
            false);
        failed++;
      } catch (const std::exception& ex) {
        reportMessage(
            StringUtil::format("Unhandled exception caught in test. $0", ex.what()),
            false);
        failed++;
      } catch (...) {
        reportMessage("Unhandled exception caught in test.", false);
        failed++;
      }

      try {
        test->TearDown();
      } catch (const BailOutException&) {
        // SHOULD NOT HAPPEND: complain about it
        failed++;
      } catch (...) {
        // TODO: report failure in tear-down
        failed++;
      }

      if (!failed) {
        successCount_++;
      }
    }
  }
}

void UnitTest::reportBinary(const char* fileName,
                            int lineNo,
                            bool fatal,
                            const char* expected,
                            const char* actual,
                            const std::string& actualEvaluated,
                            const char* op) {
  std::string message = StringUtil::format(
      "$0:$1: Failure\n"
      "  Value of: $2\n"
      "  Expected: $3 $4\n"
      "    Actual: $5\n",
      fileName, lineNo,
      actual,
      expected, op,
      actualEvaluated);

  reportMessage(message, fatal);
}

void UnitTest::reportEH(const char* fileName,
                        int lineNo,
                        bool fatal,
                        const char* program,
                        const char* expected,
                        const char* actual) {
  std::string message = StringUtil::format(
      "$0:$1: $2\n"
      "  Value of: $3\n"
      "  Expected: $4\n"
      "    Actual: $5\n",
      fileName, lineNo,
      actual ? "Unexpected exception caught"
             : "No exception caught",
      program,
      expected,
      actual);

  reportMessage(message, fatal);
}

void UnitTest::reportMessage(const std::string& message, bool fatal) {
  printf("%s%s%s\n",
      colorsError.c_str(),
      message.c_str(),
      colorsReset.c_str());

  failCount_++;
  failures_.emplace_back(message);

  if (fatal) {
    throw BailOutException();
  }
}

void UnitTest::addEnvironment(std::unique_ptr<Environment>&& env) {
  environments_.emplace_back(std::move(env));
}

Callback* UnitTest::addInitializer(std::unique_ptr<Callback>&& cb) {
  initializers_.emplace_back(std::move(cb));
  return initializers_.back().get();
}

TestInfo* UnitTest::addTest(const char* testCaseName,
                            const char* testName,
                            std::unique_ptr<TestFactory>&& testFactory) {
  testCases_.emplace_back(
      new TestInfo(
          testCaseName,
          testName,
          !StringUtil::beginsWith(testCaseName, "DISABLED_")
              && !StringUtil::beginsWith(testName, "DISABLED_"),
          std::move(testFactory)));

  activeTests_.emplace_back(activeTests_.size());

  return testCases_.back().get();
}

void UnitTest::log(const std::string& message) {
  std::string component = StringUtil::format("$0.$1",
      currentTestCase_->testCaseName(),
      currentTestCase_->testName());
  logDebug(component, "$0", message);
}

} // namespace testing
} // namespace xzero
<|endoftext|>


<commit_before>/** @file

  This file produces Unicorns and Rainbows for the ATS community

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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 <cmath>

#include "ts/ink_defs.h"
#include "ts/ink_assert.h"
#include "ts/ink_sys_control.h"

rlim_t
ink_max_out_rlimit(int which, bool max_it, bool unlim_it)
{
  struct rlimit rl;

#if defined(__GLIBC__)
#define MAGIC_CAST(x) (enum __rlimit_resource)(x)
#else
#define MAGIC_CAST(x) x
#endif

  if (max_it) {
    ink_release_assert(getrlimit(MAGIC_CAST(which), &rl) >= 0);
    if (rl.rlim_cur != rl.rlim_max) {
#if defined(darwin)
      if (which == RLIMIT_NOFILE)
        rl.rlim_cur = (OPEN_MAX < rl.rlim_max) ? OPEN_MAX : rl.rlim_max;
      else
        rl.rlim_cur = rl.rlim_max;
#else
      rl.rlim_cur = rl.rlim_max;
#endif
      ink_release_assert(setrlimit(MAGIC_CAST(which), &rl) >= 0);
    }
  }

#if !(defined(darwin) || defined(freebsd))
  if (unlim_it) {
    ink_release_assert(getrlimit(MAGIC_CAST(which), &rl) >= 0);
    if (rl.rlim_cur != (rlim_t)RLIM_INFINITY) {
      rl.rlim_cur = (rl.rlim_max = RLIM_INFINITY);
      ink_release_assert(setrlimit(MAGIC_CAST(which), &rl) >= 0);
    }
  }
#endif
  ink_release_assert(getrlimit(MAGIC_CAST(which), &rl) >= 0);
  return rl.rlim_cur;
}

rlim_t
ink_get_max_files()
{
  FILE *fd;
  struct rlimit lim;

  // Linux-only ...
  if ((fd = fopen("/proc/sys/fs/file-max", "r"))) {
    uint64_t fmax;
    if (fscanf(fd, "%" PRIu64 "", &fmax) == 1) {
      fclose(fd);
      return static_cast<rlim_t>(fmax);
    }

    fclose(fd);
  }

  if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {
    return lim.rlim_max;
  }

  return RLIM_INFINITY;
}
<commit_msg>use warning instead of assert for setrlimit()<commit_after>/** @file

  This file produces Unicorns and Rainbows for the ATS community

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you 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 <cmath>

#include "ts/ink_defs.h"
#include "ts/ink_assert.h"
#include "ts/ink_sys_control.h"
#include "ts/Diags.h"

rlim_t
ink_max_out_rlimit(int which, bool max_it, bool unlim_it)
{
  struct rlimit rl;

#if defined(__GLIBC__)
#define MAGIC_CAST(x) (enum __rlimit_resource)(x)
#else
#define MAGIC_CAST(x) x
#endif

  if (max_it) {
    ink_release_assert(getrlimit(MAGIC_CAST(which), &rl) >= 0);
    if (rl.rlim_cur != rl.rlim_max) {
#if defined(darwin)
      if (which == RLIMIT_NOFILE)
        rl.rlim_cur = (OPEN_MAX < rl.rlim_max) ? OPEN_MAX : rl.rlim_max;
      else
        rl.rlim_cur = rl.rlim_max;
#else
      rl.rlim_cur = rl.rlim_max;
#endif
      if (setrlimit(MAGIC_CAST(which), &rl) != 0) {
        Warning("Failed to set Limit : %s", strerror(errno));
      }
    }
  }

#if !(defined(darwin) || defined(freebsd))
  if (unlim_it) {
    ink_release_assert(getrlimit(MAGIC_CAST(which), &rl) >= 0);
    if (rl.rlim_cur != (rlim_t)RLIM_INFINITY) {
      rl.rlim_cur = (rl.rlim_max = RLIM_INFINITY);
      if (setrlimit(MAGIC_CAST(which), &rl) != 0) {
        Warning("Failed to set Limit : %s", strerror(errno));
      }
    }
  }
#endif
  ink_release_assert(getrlimit(MAGIC_CAST(which), &rl) >= 0);
  return rl.rlim_cur;
}

rlim_t
ink_get_max_files()
{
  FILE *fd;
  struct rlimit lim;

  // Linux-only ...
  if ((fd = fopen("/proc/sys/fs/file-max", "r"))) {
    uint64_t fmax;
    if (fscanf(fd, "%" PRIu64 "", &fmax) == 1) {
      fclose(fd);
      return static_cast<rlim_t>(fmax);
    }

    fclose(fd);
  }

  if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {
    return lim.rlim_max;
  }

  return RLIM_INFINITY;
}
<|endoftext|>


<commit_before>//===-- tsan_sync.cc ------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_placement_new.h"
#include "tsan_sync.h"
#include "tsan_rtl.h"
#include "tsan_mman.h"

namespace __tsan {

void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s);

SyncVar::SyncVar()
    : mtx(MutexTypeSyncVar, StatMtxSyncVar) {
  Reset(0);
}

void SyncVar::Init(ThreadState *thr, uptr pc, uptr addr, u64 uid) {
  this->addr = addr;
  this->uid = uid;
  this->next = 0;

  creation_stack_id = 0;
  if (kCppMode)  // Go does not use them
    creation_stack_id = CurrentStackId(thr, pc);
  if (common_flags()->detect_deadlocks)
    DDMutexInit(thr, pc, this);
}

void SyncVar::Reset(ThreadState *thr) {
  uid = 0;
  creation_stack_id = 0;
  owner_tid = kInvalidTid;
  last_lock = 0;
  recursion = 0;
  is_rw = 0;
  is_recursive = 0;
  is_broken = 0;
  is_linker_init = 0;

  if (thr == 0) {
    CHECK_EQ(clock.size(), 0);
    CHECK_EQ(read_clock.size(), 0);
  } else {
    clock.Reset(&thr->clock_cache);
    read_clock.Reset(&thr->clock_cache);
  }
}

MetaMap::MetaMap() {
  atomic_store(&uid_gen_, 0, memory_order_relaxed);
}

void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) {
  u32 idx = block_alloc_.Alloc(&thr->block_cache);
  MBlock *b = block_alloc_.Map(idx);
  b->siz = sz;
  b->tid = thr->tid;
  b->stk = CurrentStackId(thr, pc);
  u32 *meta = MemToMeta(p);
  DCHECK_EQ(*meta, 0);
  *meta = idx | kFlagBlock;
}

uptr MetaMap::FreeBlock(ThreadState *thr, uptr pc, uptr p) {
  MBlock* b = GetBlock(p);
  if (b == 0)
    return 0;
  uptr sz = RoundUpTo(b->siz, kMetaShadowCell);
  FreeRange(thr, pc, p, sz);
  return sz;
}

bool MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
  bool has_something = false;
  u32 *meta = MemToMeta(p);
  u32 *end = MemToMeta(p + sz);
  if (end == meta)
    end++;
  for (; meta < end; meta++) {
    u32 idx = *meta;
    *meta = 0;
    for (;;) {
      if (idx == 0)
        break;
      has_something = true;
      if (idx & kFlagBlock) {
        block_alloc_.Free(&thr->block_cache, idx & ~kFlagMask);
        break;
      } else if (idx & kFlagSync) {
        DCHECK(idx & kFlagSync);
        SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
        u32 next = s->next;
        s->Reset(thr);
        sync_alloc_.Free(&thr->sync_cache, idx & ~kFlagMask);
        idx = next;
      } else {
        CHECK(0);
      }
    }
  }
  return has_something;
}

// ResetRange removes all meta objects from the range.
// It is called for large mmap-ed regions. The function is best-effort wrt
// freeing of meta objects, because we don't want to page in the whole range
// which can be huge. The function probes pages one-by-one until it finds a page
// without meta objects, at this point it stops freeing meta objects. Because
// thread stacks grow top-down, we do the same starting from end as well.
void MetaMap::ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
  const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize;
  const uptr kPageSize = GetPageSizeCached() * kMetaRatio;
  if (sz <= 4 * kPageSize) {
    // If the range is small, just do the normal free procedure.
    FreeRange(thr, pc, p, sz);
    return;
  }
  // First, round both ends of the range to page size.
  uptr diff = RoundUp(p, kPageSize) - p;
  if (diff != 0) {
    FreeRange(thr, pc, p, diff);
    p += diff;
    sz -= diff;
  }
  diff = p + sz - RoundDown(p + sz, kPageSize);
  if (diff != 0) {
    FreeRange(thr, pc, p + sz - diff, diff);
    sz -= diff;
  }
  // Now we must have a non-empty page-aligned range.
  CHECK_GT(sz, 0);
  CHECK_EQ(p, RoundUp(p, kPageSize));
  CHECK_EQ(sz, RoundUp(sz, kPageSize));
  const uptr p0 = p;
  const uptr sz0 = sz;
  // Probe start of the range.
  while (sz > 0) {
    bool has_something = FreeRange(thr, pc, p, kPageSize);
    p += kPageSize;
    sz -= kPageSize;
    if (!has_something)
      break;
  }
  // Probe end of the range.
  while (sz > 0) {
    bool has_something = FreeRange(thr, pc, p - kPageSize, kPageSize);
    sz -= kPageSize;
    if (!has_something)
      break;
  }
  // Finally, page out the whole range (including the parts that we've just
  // freed). Note: we can't simply madvise, because we need to leave a zeroed
  // range (otherwise __tsan_java_move can crash if it encounters a left-over
  // meta objects in java heap).
  uptr metap = (uptr)MemToMeta(p0);
  uptr metasz = sz0 / kMetaRatio;
  UnmapOrDie((void*)metap, metasz);
  MmapFixedNoReserve(metap, metasz);
}

MBlock* MetaMap::GetBlock(uptr p) {
  u32 *meta = MemToMeta(p);
  u32 idx = *meta;
  for (;;) {
    if (idx == 0)
      return 0;
    if (idx & kFlagBlock)
      return block_alloc_.Map(idx & ~kFlagMask);
    DCHECK(idx & kFlagSync);
    SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
    idx = s->next;
  }
}

SyncVar* MetaMap::GetOrCreateAndLock(ThreadState *thr, uptr pc,
                              uptr addr, bool write_lock) {
  return GetAndLock(thr, pc, addr, write_lock, true);
}

SyncVar* MetaMap::GetIfExistsAndLock(uptr addr) {
  return GetAndLock(0, 0, addr, true, false);
}

SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc,
                             uptr addr, bool write_lock, bool create) {
  u32 *meta = MemToMeta(addr);
  u32 idx0 = *meta;
  u32 myidx = 0;
  SyncVar *mys = 0;
  for (;;) {
    u32 idx = idx0;
    for (;;) {
      if (idx == 0)
        break;
      if (idx & kFlagBlock)
        break;
      DCHECK(idx & kFlagSync);
      SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
      if (s->addr == addr) {
        if (myidx != 0) {
          mys->Reset(thr);
          sync_alloc_.Free(&thr->sync_cache, myidx);
        }
        if (write_lock)
          s->mtx.Lock();
        else
          s->mtx.ReadLock();
        return s;
      }
      idx = s->next;
    }
    if (!create)
      return 0;
    if (*meta != idx0) {
      idx0 = *meta;
      continue;
    }

    if (myidx == 0) {
      const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed);
      myidx = sync_alloc_.Alloc(&thr->sync_cache);
      mys = sync_alloc_.Map(myidx);
      mys->Init(thr, pc, addr, uid);
    }
    mys->next = idx0;
    if (atomic_compare_exchange_strong((atomic_uint32_t*)meta, &idx0,
        myidx | kFlagSync, memory_order_release)) {
      if (write_lock)
        mys->mtx.Lock();
      else
        mys->mtx.ReadLock();
      return mys;
    }
  }
}

void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) {
  // src and dst can overlap,
  // there are no concurrent accesses to the regions (e.g. stop-the-world).
  CHECK_NE(src, dst);
  CHECK_NE(sz, 0);
  uptr diff = dst - src;
  u32 *src_meta = MemToMeta(src);
  u32 *dst_meta = MemToMeta(dst);
  u32 *src_meta_end = MemToMeta(src + sz);
  uptr inc = 1;
  if (dst > src) {
    src_meta = MemToMeta(src + sz) - 1;
    dst_meta = MemToMeta(dst + sz) - 1;
    src_meta_end = MemToMeta(src) - 1;
    inc = -1;
  }
  for (; src_meta != src_meta_end; src_meta += inc, dst_meta += inc) {
    CHECK_EQ(*dst_meta, 0);
    u32 idx = *src_meta;
    *src_meta = 0;
    *dst_meta = idx;
    // Patch the addresses in sync objects.
    while (idx != 0) {
      if (idx & kFlagBlock)
        break;
      CHECK(idx & kFlagSync);
      SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
      s->addr += diff;
      idx = s->next;
    }
  }
}

void MetaMap::OnThreadIdle(ThreadState *thr) {
  block_alloc_.FlushCache(&thr->block_cache);
  sync_alloc_.FlushCache(&thr->sync_cache);
}

}  // namespace __tsan
<commit_msg>tsan: don't write to meta shadow unnecessarily<commit_after>//===-- tsan_sync.cc ------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_placement_new.h"
#include "tsan_sync.h"
#include "tsan_rtl.h"
#include "tsan_mman.h"

namespace __tsan {

void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s);

SyncVar::SyncVar()
    : mtx(MutexTypeSyncVar, StatMtxSyncVar) {
  Reset(0);
}

void SyncVar::Init(ThreadState *thr, uptr pc, uptr addr, u64 uid) {
  this->addr = addr;
  this->uid = uid;
  this->next = 0;

  creation_stack_id = 0;
  if (kCppMode)  // Go does not use them
    creation_stack_id = CurrentStackId(thr, pc);
  if (common_flags()->detect_deadlocks)
    DDMutexInit(thr, pc, this);
}

void SyncVar::Reset(ThreadState *thr) {
  uid = 0;
  creation_stack_id = 0;
  owner_tid = kInvalidTid;
  last_lock = 0;
  recursion = 0;
  is_rw = 0;
  is_recursive = 0;
  is_broken = 0;
  is_linker_init = 0;

  if (thr == 0) {
    CHECK_EQ(clock.size(), 0);
    CHECK_EQ(read_clock.size(), 0);
  } else {
    clock.Reset(&thr->clock_cache);
    read_clock.Reset(&thr->clock_cache);
  }
}

MetaMap::MetaMap() {
  atomic_store(&uid_gen_, 0, memory_order_relaxed);
}

void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) {
  u32 idx = block_alloc_.Alloc(&thr->block_cache);
  MBlock *b = block_alloc_.Map(idx);
  b->siz = sz;
  b->tid = thr->tid;
  b->stk = CurrentStackId(thr, pc);
  u32 *meta = MemToMeta(p);
  DCHECK_EQ(*meta, 0);
  *meta = idx | kFlagBlock;
}

uptr MetaMap::FreeBlock(ThreadState *thr, uptr pc, uptr p) {
  MBlock* b = GetBlock(p);
  if (b == 0)
    return 0;
  uptr sz = RoundUpTo(b->siz, kMetaShadowCell);
  FreeRange(thr, pc, p, sz);
  return sz;
}

bool MetaMap::FreeRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
  bool has_something = false;
  u32 *meta = MemToMeta(p);
  u32 *end = MemToMeta(p + sz);
  if (end == meta)
    end++;
  for (; meta < end; meta++) {
    u32 idx = *meta;
    if (idx == 0) {
      // Note: don't write to meta in this case -- the block can be huge.
      continue;
    }
    *meta = 0;
    has_something = true;
    while (idx != 0) {
      if (idx & kFlagBlock) {
        block_alloc_.Free(&thr->block_cache, idx & ~kFlagMask);
        break;
      } else if (idx & kFlagSync) {
        DCHECK(idx & kFlagSync);
        SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
        u32 next = s->next;
        s->Reset(thr);
        sync_alloc_.Free(&thr->sync_cache, idx & ~kFlagMask);
        idx = next;
      } else {
        CHECK(0);
      }
    }
  }
  return has_something;
}

// ResetRange removes all meta objects from the range.
// It is called for large mmap-ed regions. The function is best-effort wrt
// freeing of meta objects, because we don't want to page in the whole range
// which can be huge. The function probes pages one-by-one until it finds a page
// without meta objects, at this point it stops freeing meta objects. Because
// thread stacks grow top-down, we do the same starting from end as well.
void MetaMap::ResetRange(ThreadState *thr, uptr pc, uptr p, uptr sz) {
  const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize;
  const uptr kPageSize = GetPageSizeCached() * kMetaRatio;
  if (sz <= 4 * kPageSize) {
    // If the range is small, just do the normal free procedure.
    FreeRange(thr, pc, p, sz);
    return;
  }
  // First, round both ends of the range to page size.
  uptr diff = RoundUp(p, kPageSize) - p;
  if (diff != 0) {
    FreeRange(thr, pc, p, diff);
    p += diff;
    sz -= diff;
  }
  diff = p + sz - RoundDown(p + sz, kPageSize);
  if (diff != 0) {
    FreeRange(thr, pc, p + sz - diff, diff);
    sz -= diff;
  }
  // Now we must have a non-empty page-aligned range.
  CHECK_GT(sz, 0);
  CHECK_EQ(p, RoundUp(p, kPageSize));
  CHECK_EQ(sz, RoundUp(sz, kPageSize));
  const uptr p0 = p;
  const uptr sz0 = sz;
  // Probe start of the range.
  while (sz > 0) {
    bool has_something = FreeRange(thr, pc, p, kPageSize);
    p += kPageSize;
    sz -= kPageSize;
    if (!has_something)
      break;
  }
  // Probe end of the range.
  while (sz > 0) {
    bool has_something = FreeRange(thr, pc, p - kPageSize, kPageSize);
    sz -= kPageSize;
    if (!has_something)
      break;
  }
  // Finally, page out the whole range (including the parts that we've just
  // freed). Note: we can't simply madvise, because we need to leave a zeroed
  // range (otherwise __tsan_java_move can crash if it encounters a left-over
  // meta objects in java heap).
  uptr metap = (uptr)MemToMeta(p0);
  uptr metasz = sz0 / kMetaRatio;
  UnmapOrDie((void*)metap, metasz);
  MmapFixedNoReserve(metap, metasz);
}

MBlock* MetaMap::GetBlock(uptr p) {
  u32 *meta = MemToMeta(p);
  u32 idx = *meta;
  for (;;) {
    if (idx == 0)
      return 0;
    if (idx & kFlagBlock)
      return block_alloc_.Map(idx & ~kFlagMask);
    DCHECK(idx & kFlagSync);
    SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
    idx = s->next;
  }
}

SyncVar* MetaMap::GetOrCreateAndLock(ThreadState *thr, uptr pc,
                              uptr addr, bool write_lock) {
  return GetAndLock(thr, pc, addr, write_lock, true);
}

SyncVar* MetaMap::GetIfExistsAndLock(uptr addr) {
  return GetAndLock(0, 0, addr, true, false);
}

SyncVar* MetaMap::GetAndLock(ThreadState *thr, uptr pc,
                             uptr addr, bool write_lock, bool create) {
  u32 *meta = MemToMeta(addr);
  u32 idx0 = *meta;
  u32 myidx = 0;
  SyncVar *mys = 0;
  for (;;) {
    u32 idx = idx0;
    for (;;) {
      if (idx == 0)
        break;
      if (idx & kFlagBlock)
        break;
      DCHECK(idx & kFlagSync);
      SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
      if (s->addr == addr) {
        if (myidx != 0) {
          mys->Reset(thr);
          sync_alloc_.Free(&thr->sync_cache, myidx);
        }
        if (write_lock)
          s->mtx.Lock();
        else
          s->mtx.ReadLock();
        return s;
      }
      idx = s->next;
    }
    if (!create)
      return 0;
    if (*meta != idx0) {
      idx0 = *meta;
      continue;
    }

    if (myidx == 0) {
      const u64 uid = atomic_fetch_add(&uid_gen_, 1, memory_order_relaxed);
      myidx = sync_alloc_.Alloc(&thr->sync_cache);
      mys = sync_alloc_.Map(myidx);
      mys->Init(thr, pc, addr, uid);
    }
    mys->next = idx0;
    if (atomic_compare_exchange_strong((atomic_uint32_t*)meta, &idx0,
        myidx | kFlagSync, memory_order_release)) {
      if (write_lock)
        mys->mtx.Lock();
      else
        mys->mtx.ReadLock();
      return mys;
    }
  }
}

void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) {
  // src and dst can overlap,
  // there are no concurrent accesses to the regions (e.g. stop-the-world).
  CHECK_NE(src, dst);
  CHECK_NE(sz, 0);
  uptr diff = dst - src;
  u32 *src_meta = MemToMeta(src);
  u32 *dst_meta = MemToMeta(dst);
  u32 *src_meta_end = MemToMeta(src + sz);
  uptr inc = 1;
  if (dst > src) {
    src_meta = MemToMeta(src + sz) - 1;
    dst_meta = MemToMeta(dst + sz) - 1;
    src_meta_end = MemToMeta(src) - 1;
    inc = -1;
  }
  for (; src_meta != src_meta_end; src_meta += inc, dst_meta += inc) {
    CHECK_EQ(*dst_meta, 0);
    u32 idx = *src_meta;
    *src_meta = 0;
    *dst_meta = idx;
    // Patch the addresses in sync objects.
    while (idx != 0) {
      if (idx & kFlagBlock)
        break;
      CHECK(idx & kFlagSync);
      SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
      s->addr += diff;
      idx = s->next;
    }
  }
}

void MetaMap::OnThreadIdle(ThreadState *thr) {
  block_alloc_.FlushCache(&thr->block_cache);
  sync_alloc_.FlushCache(&thr->sync_cache);
}

}  // namespace __tsan
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: scitems.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 17:54:24 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SC_ITEMS_HXX
#define SC_ITEMS_HXX

#ifndef _SVX_SVXIDS_HRC
#include <svx/svxids.hrc>
#endif

//  EditEngine darf nicht ihre eigenen ITEMID's definieren
#define _EEITEMID_HXX

//--------------------------
// Item-IDs fuer UI-MsgPool:
//--------------------------

//! sollten auch nach unter 1000 verschoben werden!

#define MSGPOOL_START               1100
//--------------------------------------
#define SCITEM_STRING               1100
#define SCITEM_SEARCHDATA           1101
#define SCITEM_SORTDATA             1102
#define SCITEM_QUERYDATA            1103
#define SCITEM_SUBTDATA             1104
#define SCITEM_CONSOLIDATEDATA      1105
#define SCITEM_PIVOTDATA            1106
#define SCITEM_SOLVEDATA            1107
#define SCITEM_USERLIST             1108
#define SCITEM_PRINTWARN            1109
//--------------------------------------
#define MSGPOOL_END                 1109

//-------------------------
// Item-IDs fuer Attribute:
//-------------------------
#define ATTR_STARTINDEX         100     // Anfang Attribute

#define ATTR_PATTERN_START      100     // Anfang Zellattribut-Pattern

#define ATTR_FONT               100     // Anfang Zellattribute
#define ATTR_FONT_HEIGHT        101
#define ATTR_FONT_WEIGHT        102
#define ATTR_FONT_POSTURE       103
#define ATTR_FONT_UNDERLINE     104
#define ATTR_FONT_CROSSEDOUT    105
#define ATTR_FONT_CONTOUR       106
#define ATTR_FONT_SHADOWED      107
#define ATTR_FONT_COLOR         108
#define ATTR_FONT_LANGUAGE      109
#define ATTR_CJK_FONT           110
#define ATTR_CJK_FONT_HEIGHT    111
#define ATTR_CJK_FONT_WEIGHT    112
#define ATTR_CJK_FONT_POSTURE   113
#define ATTR_CJK_FONT_LANGUAGE  114
#define ATTR_CTL_FONT           115
#define ATTR_CTL_FONT_HEIGHT    116
#define ATTR_CTL_FONT_WEIGHT    117
#define ATTR_CTL_FONT_POSTURE   118
#define ATTR_CTL_FONT_LANGUAGE  119
#define ATTR_FONT_EMPHASISMARK  120
#define ATTR_USERDEF            121     // not saved in binary files
#define ATTR_FONT_WORDLINE      122
#define ATTR_FONT_RELIEF        123
#define ATTR_HYPHENATE          124
#define ATTR_SCRIPTSPACE        125
#define ATTR_HANGPUNCTUATION    126
#define ATTR_FORBIDDEN_RULES    127
#define ATTR_HOR_JUSTIFY        128
#define ATTR_INDENT             129
#define ATTR_VER_JUSTIFY        130
#define ATTR_STACKED            131
#define ATTR_ROTATE_VALUE       132
#define ATTR_ROTATE_MODE        133
#define ATTR_VERTICAL_ASIAN     134
#define ATTR_WRITINGDIR         135
#define ATTR_LINEBREAK          136
#define ATTR_SHRINKTOFIT        137
#define ATTR_BORDER_TLBR        138
#define ATTR_BORDER_BLTR        139
#define ATTR_MARGIN             140
#define ATTR_MERGE              141
#define ATTR_MERGE_FLAG         142
#define ATTR_VALUE_FORMAT       143
#define ATTR_LANGUAGE_FORMAT    144
#define ATTR_BACKGROUND         145
#define ATTR_PROTECTION         146
#define ATTR_BORDER             147
#define ATTR_BORDER_INNER       148     // innen, wg. Vorlagen-EditDialog
#define ATTR_SHADOW             149
#define ATTR_VALIDDATA          150
#define ATTR_CONDITIONAL        151

#define ATTR_PATTERN_END        151     // Ende Zellattribut-Pattern

#define ATTR_PATTERN            152
                                        // Seitenattribute
#define ATTR_LRSPACE            153     // Editor: PageDesc-TabPage
#define ATTR_ULSPACE            154
#define ATTR_PAGE               155
#define ATTR_PAGE_PAPERTRAY     156
#define ATTR_PAGE_PAPERBIN      157
#define ATTR_PAGE_SIZE          158
#define ATTR_PAGE_MAXSIZE       159
#define ATTR_PAGE_HORCENTER     160
#define ATTR_PAGE_VERCENTER     161

#define ATTR_PAGE_ON            162     // Editor: Header/Footer-Page
#define ATTR_PAGE_DYNAMIC       163
#define ATTR_PAGE_SHARED        164

#define ATTR_PAGE_NOTES         165     // Editor: Tabelle
#define ATTR_PAGE_GRID          166
#define ATTR_PAGE_HEADERS       167
#define ATTR_PAGE_CHARTS        168
#define ATTR_PAGE_OBJECTS       169
#define ATTR_PAGE_DRAWINGS      170
#define ATTR_PAGE_TOPDOWN       171
#define ATTR_PAGE_SCALE         172
#define ATTR_PAGE_SCALETOPAGES  173
#define ATTR_PAGE_FIRSTPAGENO   174

#define ATTR_PAGE_PRINTAREA     175     // Editor: Druckbereiche
#define ATTR_PAGE_REPEATROW     176
#define ATTR_PAGE_REPEATCOL     177
#define ATTR_PAGE_PRINTTABLES   178

#define ATTR_PAGE_HEADERLEFT    179     // Inhalte der Kopf-/
#define ATTR_PAGE_FOOTERLEFT    180     // Fusszeilen (links)
#define ATTR_PAGE_HEADERRIGHT   181     // Inhalte der Kopf-/
#define ATTR_PAGE_FOOTERRIGHT   182     // Fusszeilen (rechts)
#define ATTR_PAGE_HEADERSET     183     // die Sets dazu...
#define ATTR_PAGE_FOOTERSET     184

#define ATTR_PAGE_FORMULAS      185
#define ATTR_PAGE_NULLVALS      186

#define ATTR_PAGE_SCALETO       187     // #i8868# scale printout to with/height

#define ATTR_ENDINDEX           ATTR_PAGE_SCALETO        // Ende Pool-Range

//--------------------------------
// Dummy Slot-IDs fuer Dialoge
//--------------------------------
#define SID_SCATTR_PAGE_NOTES           ATTR_PAGE_NOTES
#define SID_SCATTR_PAGE_GRID            ATTR_PAGE_GRID
#define SID_SCATTR_PAGE_HEADERS         ATTR_PAGE_HEADERS
#define SID_SCATTR_PAGE_CHARTS          ATTR_PAGE_CHARTS
#define SID_SCATTR_PAGE_OBJECTS         ATTR_PAGE_OBJECTS
#define SID_SCATTR_PAGE_DRAWINGS        ATTR_PAGE_DRAWINGS
#define SID_SCATTR_PAGE_TOPDOWN         ATTR_PAGE_TOPDOWN
#define SID_SCATTR_PAGE_SCALE           ATTR_PAGE_SCALE
#define SID_SCATTR_PAGE_SCALETOPAGES    ATTR_PAGE_SCALETOPAGES
#define SID_SCATTR_PAGE_FIRSTPAGENO     ATTR_PAGE_FIRSTPAGENO
#define SID_SCATTR_PAGE_PRINTAREA       ATTR_PAGE_PRINTAREA
#define SID_SCATTR_PAGE_REPEATROW       ATTR_PAGE_REPEATROW
#define SID_SCATTR_PAGE_REPEATCOL       ATTR_PAGE_REPEATCOL
#define SID_SCATTR_PAGE_PRINTTABLES     ATTR_PAGE_PRINTTABLES
#define SID_SCATTR_PAGE_HEADERLEFT      ATTR_PAGE_HEADERLEFT
#define SID_SCATTR_PAGE_FOOTERLEFT      ATTR_PAGE_FOOTERLEFT
#define SID_SCATTR_PAGE_HEADERRIGHT     ATTR_PAGE_HEADERRIGHT
#define SID_SCATTR_PAGE_FOOTERRIGHT     ATTR_PAGE_FOOTERRIGHT
#define SID_SCATTR_PAGE_FORMULAS        ATTR_PAGE_FORMULAS
#define SID_SCATTR_PAGE_NULLVALS        ATTR_PAGE_NULLVALS
#define SID_SCATTR_PAGE_SCALETO         ATTR_PAGE_SCALETO

//--------------------------------
// IDs fuer Svx-Items:
//--------------------------------
#define ITEMID_LINE             SID_FRAME_LINESTYLE
#define ITEMID_BOX              ATTR_BORDER
#define ITEMID_BOXINFO          ATTR_BORDER_INNER
#define ITEMID_SHADOW           ATTR_SHADOW
#define ITEMID_BRUSH            ATTR_BACKGROUND
#define ITEMID_FONT             ATTR_FONT
#define ITEMID_FONTHEIGHT       ATTR_FONT_HEIGHT
#define ITEMID_WEIGHT           ATTR_FONT_WEIGHT
#define ITEMID_POSTURE          ATTR_FONT_POSTURE
#define ITEMID_UNDERLINE        ATTR_FONT_UNDERLINE
#define ITEMID_CROSSEDOUT       ATTR_FONT_CROSSEDOUT
#define ITEMID_CONTOUR          ATTR_FONT_CONTOUR
#define ITEMID_SHADOWED         ATTR_FONT_SHADOWED
#define ITEMID_COLOR            ATTR_FONT_COLOR
#define ITEMID_LANGUAGE         ATTR_FONT_LANGUAGE
#define ITEMID_EMPHASISMARK     ATTR_FONT_EMPHASISMARK
#define ITEMID_WORDLINEMODE     ATTR_FONT_WORDLINE
#define ITEMID_CHARRELIEF       ATTR_FONT_RELIEF
#define ITEMID_SCRIPTSPACE      ATTR_SCRIPTSPACE
#define ITEMID_HANGINGPUNCTUATION   ATTR_HANGPUNCTUATION
#define ITEMID_FORBIDDENRULE    ATTR_FORBIDDEN_RULES
#define ITEMID_HORJUSTIFY       ATTR_HOR_JUSTIFY
#define ITEMID_VERJUSTIFY       ATTR_VER_JUSTIFY
/*  SvxOrientationItem not used anymore in Calc core. Define ITEMID_ORIENTATION
    here anyway to be able to use this item in TableAutoFormat to keep the file
    format unchanged. */
#define ITEMID_ORIENTATION      0 /*ATTR_ORIENTATION*/
#define ITEMID_FRAMEDIR         ATTR_WRITINGDIR
#define ITEMID_LINEBREAK        ATTR_LINEBREAK
#define ITEMID_MARGIN           ATTR_MARGIN
#define ITEMID_ESCAPEMENT       0
#define ITEMID_CASEMAP          0
#define ITEMID_NUMBERINFO       0
#define ITEMID_FONTLIST         0
#define ITEMID_SEARCH           SCITEM_SEARCHDATA
#define ITEMID_ADJUST           0
#define ITEMID_LRSPACE          0
#define ITEMID_ULSPACE          0
#define ITEMID_PAPERBIN         0
#define ITEMID_SIZE             0
#define ITEMID_PAGE             0
#define ITEMID_SETITEM          0
#define ITEMID_COLOR_TABLE      SID_COLOR_TABLE
#define ITEMID_GRADIENT_LIST    SID_GRADIENT_LIST
#define ITEMID_HATCH_LIST       SID_HATCH_LIST
#define ITEMID_BITMAP_LIST      SID_BITMAP_LIST
#define ITEMID_COLOR_TABLE      SID_COLOR_TABLE
#define ITEMID_DASH_LIST        SID_DASH_LIST
#define ITEMID_LINEEND_LIST     SID_LINEEND_LIST
#define ITEMID_AUTHOR           0
#define ITEMID_DATE             0
#define ITEMID_TEXT             0

#endif

<commit_msg>INTEGRATION: CWS pchfix04 (1.10.318); FILE MERGED 2007/02/05 08:35:15 os 1.10.318.1: #i73604# usage of ITEMID_* removed<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: scitems.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: kz $ $Date: 2007-05-10 16:42:33 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SC_ITEMS_HXX
#define SC_ITEMS_HXX

#ifndef _SVX_SVXIDS_HRC
#include <svx/svxids.hrc>
#endif

//  EditEngine darf nicht ihre eigenen ITEMID's definieren
#define _EEITEMID_HXX

//--------------------------
// Item-IDs fuer UI-MsgPool:
//--------------------------

//! sollten auch nach unter 1000 verschoben werden!

#define MSGPOOL_START               1100
//--------------------------------------
#define SCITEM_STRING               1100
#define SCITEM_SEARCHDATA           1101
#define SCITEM_SORTDATA             1102
#define SCITEM_QUERYDATA            1103
#define SCITEM_SUBTDATA             1104
#define SCITEM_CONSOLIDATEDATA      1105
#define SCITEM_PIVOTDATA            1106
#define SCITEM_SOLVEDATA            1107
#define SCITEM_USERLIST             1108
#define SCITEM_PRINTWARN            1109
//--------------------------------------
#define MSGPOOL_END                 1109

//-------------------------
// Item-IDs fuer Attribute:
//-------------------------
#define ATTR_STARTINDEX         100     // Anfang Attribute

#define ATTR_PATTERN_START      100     // Anfang Zellattribut-Pattern

#define ATTR_FONT               100     // Anfang Zellattribute
#define ATTR_FONT_HEIGHT        101
#define ATTR_FONT_WEIGHT        102
#define ATTR_FONT_POSTURE       103
#define ATTR_FONT_UNDERLINE     104
#define ATTR_FONT_CROSSEDOUT    105
#define ATTR_FONT_CONTOUR       106
#define ATTR_FONT_SHADOWED      107
#define ATTR_FONT_COLOR         108
#define ATTR_FONT_LANGUAGE      109
#define ATTR_CJK_FONT           110
#define ATTR_CJK_FONT_HEIGHT    111
#define ATTR_CJK_FONT_WEIGHT    112
#define ATTR_CJK_FONT_POSTURE   113
#define ATTR_CJK_FONT_LANGUAGE  114
#define ATTR_CTL_FONT           115
#define ATTR_CTL_FONT_HEIGHT    116
#define ATTR_CTL_FONT_WEIGHT    117
#define ATTR_CTL_FONT_POSTURE   118
#define ATTR_CTL_FONT_LANGUAGE  119
#define ATTR_FONT_EMPHASISMARK  120
#define ATTR_USERDEF            121     // not saved in binary files
#define ATTR_FONT_WORDLINE      122
#define ATTR_FONT_RELIEF        123
#define ATTR_HYPHENATE          124
#define ATTR_SCRIPTSPACE        125
#define ATTR_HANGPUNCTUATION    126
#define ATTR_FORBIDDEN_RULES    127
#define ATTR_HOR_JUSTIFY        128
#define ATTR_INDENT             129
#define ATTR_VER_JUSTIFY        130
#define ATTR_STACKED            131
#define ATTR_ROTATE_VALUE       132
#define ATTR_ROTATE_MODE        133
#define ATTR_VERTICAL_ASIAN     134
#define ATTR_WRITINGDIR         135
#define ATTR_LINEBREAK          136
#define ATTR_SHRINKTOFIT        137
#define ATTR_BORDER_TLBR        138
#define ATTR_BORDER_BLTR        139
#define ATTR_MARGIN             140
#define ATTR_MERGE              141
#define ATTR_MERGE_FLAG         142
#define ATTR_VALUE_FORMAT       143
#define ATTR_LANGUAGE_FORMAT    144
#define ATTR_BACKGROUND         145
#define ATTR_PROTECTION         146
#define ATTR_BORDER             147
#define ATTR_BORDER_INNER       148     // innen, wg. Vorlagen-EditDialog
#define ATTR_SHADOW             149
#define ATTR_VALIDDATA          150
#define ATTR_CONDITIONAL        151

#define ATTR_PATTERN_END        151     // Ende Zellattribut-Pattern

#define ATTR_PATTERN            152
                                        // Seitenattribute
#define ATTR_LRSPACE            153     // Editor: PageDesc-TabPage
#define ATTR_ULSPACE            154
#define ATTR_PAGE               155
#define ATTR_PAGE_PAPERTRAY     156
#define ATTR_PAGE_PAPERBIN      157
#define ATTR_PAGE_SIZE          158
#define ATTR_PAGE_MAXSIZE       159
#define ATTR_PAGE_HORCENTER     160
#define ATTR_PAGE_VERCENTER     161

#define ATTR_PAGE_ON            162     // Editor: Header/Footer-Page
#define ATTR_PAGE_DYNAMIC       163
#define ATTR_PAGE_SHARED        164

#define ATTR_PAGE_NOTES         165     // Editor: Tabelle
#define ATTR_PAGE_GRID          166
#define ATTR_PAGE_HEADERS       167
#define ATTR_PAGE_CHARTS        168
#define ATTR_PAGE_OBJECTS       169
#define ATTR_PAGE_DRAWINGS      170
#define ATTR_PAGE_TOPDOWN       171
#define ATTR_PAGE_SCALE         172
#define ATTR_PAGE_SCALETOPAGES  173
#define ATTR_PAGE_FIRSTPAGENO   174

#define ATTR_PAGE_PRINTAREA     175     // Editor: Druckbereiche
#define ATTR_PAGE_REPEATROW     176
#define ATTR_PAGE_REPEATCOL     177
#define ATTR_PAGE_PRINTTABLES   178

#define ATTR_PAGE_HEADERLEFT    179     // Inhalte der Kopf-/
#define ATTR_PAGE_FOOTERLEFT    180     // Fusszeilen (links)
#define ATTR_PAGE_HEADERRIGHT   181     // Inhalte der Kopf-/
#define ATTR_PAGE_FOOTERRIGHT   182     // Fusszeilen (rechts)
#define ATTR_PAGE_HEADERSET     183     // die Sets dazu...
#define ATTR_PAGE_FOOTERSET     184

#define ATTR_PAGE_FORMULAS      185
#define ATTR_PAGE_NULLVALS      186

#define ATTR_PAGE_SCALETO       187     // #i8868# scale printout to with/height

#define ATTR_ENDINDEX           ATTR_PAGE_SCALETO        // Ende Pool-Range

//--------------------------------
// Dummy Slot-IDs fuer Dialoge
//--------------------------------
#define SID_SCATTR_PAGE_NOTES           ATTR_PAGE_NOTES
#define SID_SCATTR_PAGE_GRID            ATTR_PAGE_GRID
#define SID_SCATTR_PAGE_HEADERS         ATTR_PAGE_HEADERS
#define SID_SCATTR_PAGE_CHARTS          ATTR_PAGE_CHARTS
#define SID_SCATTR_PAGE_OBJECTS         ATTR_PAGE_OBJECTS
#define SID_SCATTR_PAGE_DRAWINGS        ATTR_PAGE_DRAWINGS
#define SID_SCATTR_PAGE_TOPDOWN         ATTR_PAGE_TOPDOWN
#define SID_SCATTR_PAGE_SCALE           ATTR_PAGE_SCALE
#define SID_SCATTR_PAGE_SCALETOPAGES    ATTR_PAGE_SCALETOPAGES
#define SID_SCATTR_PAGE_FIRSTPAGENO     ATTR_PAGE_FIRSTPAGENO
#define SID_SCATTR_PAGE_PRINTAREA       ATTR_PAGE_PRINTAREA
#define SID_SCATTR_PAGE_REPEATROW       ATTR_PAGE_REPEATROW
#define SID_SCATTR_PAGE_REPEATCOL       ATTR_PAGE_REPEATCOL
#define SID_SCATTR_PAGE_PRINTTABLES     ATTR_PAGE_PRINTTABLES
#define SID_SCATTR_PAGE_HEADERLEFT      ATTR_PAGE_HEADERLEFT
#define SID_SCATTR_PAGE_FOOTERLEFT      ATTR_PAGE_FOOTERLEFT
#define SID_SCATTR_PAGE_HEADERRIGHT     ATTR_PAGE_HEADERRIGHT
#define SID_SCATTR_PAGE_FOOTERRIGHT     ATTR_PAGE_FOOTERRIGHT
#define SID_SCATTR_PAGE_FORMULAS        ATTR_PAGE_FORMULAS
#define SID_SCATTR_PAGE_NULLVALS        ATTR_PAGE_NULLVALS
#define SID_SCATTR_PAGE_SCALETO         ATTR_PAGE_SCALETO

#endif

<|endoftext|>


<commit_before>#include <Nazara/Core/MovablePtr.hpp>
#include <Nazara/Core/StackVector.hpp>
#include <Catch/catch.hpp>
#include <array>
#include <numeric>

// This is a quick way to check that checks are valid
#define USE_STD_VECTOR 0

class DestructionCounter
{
	public:
		DestructionCounter() :
		m_counter(nullptr),
		m_value(0)
		{
		}

		DestructionCounter(std::size_t* counter, int value) :
		m_counter(counter),
		m_value(value)
		{
			if (m_counter)
				(*m_counter)++;
		}

		DestructionCounter(const DestructionCounter& counter) :
		m_counter(counter.m_counter),
		m_value(counter.m_value)
		{
			if (m_counter)
				(*m_counter)++;
		}

		DestructionCounter(DestructionCounter&& counter) :
		m_counter(counter.m_counter),
		m_value(counter.m_value)
		{
			if (m_counter)
				(*m_counter)++;
		}

		~DestructionCounter()
		{
			if (m_counter)
			{
				assert(*m_counter > 0);
				(*m_counter)--;
			}
		}

		operator int() const
		{
			return m_value;
		}

		DestructionCounter& operator=(const DestructionCounter& counter)
		{
			if (m_counter)
			{
				assert(*m_counter > 0);
				(*m_counter)--;
			}

			m_counter = counter.m_counter;
			m_value = counter.m_value;

			if (m_counter)
				(*m_counter)++;

			return *this;
		}

		DestructionCounter& operator=(DestructionCounter&& counter)
		{
			if (this == &counter)
				return *this;

			if (m_counter)
			{
				assert(*m_counter > 0);
				(*m_counter)--;
			}

			m_counter = counter.m_counter;
			m_value = counter.m_value;

			if (m_counter)
				(*m_counter)++;

			return *this;
		}

	private:
		std::size_t* m_counter;
		int m_value;
};

SCENARIO("StackVector", "[CORE][STACKVECTOR]")
{
	GIVEN("A StackVector to contain multiple int")
	{
		std::size_t counter = 0;
		{
			volatile std::size_t capacity = 50;
#if USE_STD_VECTOR
			std::vector<DestructionCounter> vector;
			vector.reserve(capacity);
#else
			Nz::StackVector<DestructionCounter> vector = NazaraStackVector(DestructionCounter, capacity);
#endif

			WHEN("At construction, the vector is empty but has capacity")
			{
				CHECK(vector.capacity() == capacity);
				CHECK(vector.empty());
				CHECK(vector.size() == 0);
			}

			WHEN("Emplacing five elements, vector size increase accordingly")
			{
				for (std::size_t i = 0; i < 5; ++i)
				{
#if USE_STD_VECTOR
					vector.emplace_back(&counter, int(i));
#else
					CHECK(vector.emplace_back(&counter, int(i)) == int(i));
#endif
				}

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 0, 1, 2, 3, 4 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("Pushing three elements, vector size increase accordingly")
			{
				for (std::size_t i = 0; i < 3; ++i)
				{
					DestructionCounter val(&counter, int(i));
#if USE_STD_VECTOR
					vector.push_back(val);
#else
					CHECK(vector.push_back(val) == val);
#endif
				}

				CHECK(!vector.empty());
				CHECK(vector.size() == 3);

				std::array<int, 3> expectedValues = { 0, 1, 2 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));

				THEN("We resize to five")
				{
					vector.resize(5);

					CHECK(!vector.empty());
					CHECK(vector.size() == 5);

					std::array<int, 5> expectedValues = { 0, 1, 2, 0, 0 };
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));

					AND_THEN("We resize it back to zero")
					{
						vector.resize(0);

						CHECK(vector.empty());
						CHECK(vector.size() == 0);
					}
					AND_THEN("We clear it")
					{
						vector.clear();

						CHECK(vector.empty());
						CHECK(vector.size() == 0);
						CHECK(counter == 0);
					}
				}
			}

			WHEN("We generate its content will iota")
			{
				vector.resize(10);
				for (std::size_t i = 0; i < vector.size(); ++i)
					vector[i] = DestructionCounter(&counter, -5 + int(i));

				std::array<int, 10> expectedValues = { -5, -4, -3, -2, -1, 0, 1, 2, 3, 4 };
				CHECK(vector.size() == expectedValues.size());
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));

				AND_WHEN("We pop back some elements")
				{
					for (std::size_t i = 0; i < 5; ++i)
						vector.pop_back();

					std::array<int, 5> expectedValues = { -5, -4, -3, -2, -1 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase elements at the beginning")
				{
					vector.erase(vector.begin());
					vector.erase(vector.begin());

					std::array<int, 8> expectedValues = { -3, -2, -1, 0, 1, 2, 3, 4 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase elements in the middle")
				{
					vector.erase(vector.begin() + 2);
					vector.erase(vector.begin() + 2);
					vector.erase(vector.begin() + 6);

					std::array<int, 7> expectedValues = { -5, -4, -1, 0, 1, 2, 4 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase elements at the end")
				{
					vector.erase(vector.end() - 1);
					vector.erase(vector.end() - 1);

					std::array<int, 8> expectedValues = { -5, -4, -3, -2, -1, 0, 1, 2 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase a range")
				{
					vector.erase(vector.begin() + 2, vector.end() - 3);

					std::array<int, 5> expectedValues = { -5, -4, 2, 3, 4 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase everything")
				{
					vector.erase(vector.begin(), vector.end());

					CHECK(vector.empty());
				}
			}

			WHEN("We generate its content using emplace")
			{
				for (std::size_t i = 0; i < 5; ++i)
					CHECK(*vector.emplace(vector.end(), &counter, int(i)) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 0, 1, 2, 3, 4 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using emplace, in reverse order")
			{
				for (std::size_t i = 0; i < 5; ++i)
					CHECK(*vector.emplace(vector.begin(), &counter, int(i)) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 4, 3, 2, 1, 0 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using emplace, at the middle")
			{
				for (std::size_t i = 0; i < 10; ++i)
					CHECK(*vector.emplace(vector.begin() + i / 2, &counter, int(i)) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 10);

				std::array<int, 10> expectedValues = { 1, 3, 5, 7, 9, 8, 6, 4, 2, 0 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using insert")
			{
				for (std::size_t i = 0; i < 5; ++i)
					CHECK(*vector.insert(vector.end(), DestructionCounter(&counter, int(i))) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 0, 1, 2, 3, 4 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using insert, in reverse order")
			{
				for (std::size_t i = 0; i < 5; ++i)
					CHECK(*vector.insert(vector.begin(), DestructionCounter(&counter, int(i))) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 4, 3, 2, 1, 0 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using insert, at the middle")
			{
				for (std::size_t i = 0; i < 10; ++i)
					CHECK(*vector.insert(vector.begin() + i / 2, DestructionCounter(&counter, int(i))) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 10);

				std::array<int, 10> expectedValues = { 1, 3, 5, 7, 9, 8, 6, 4, 2, 0 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}
		}

		CHECK(counter == 0);
	}
}
<commit_msg>Core/StackVector: Add unit tests<commit_after>#include <Nazara/Core/MovablePtr.hpp>
#include <Nazara/Core/StackVector.hpp>
#include <Catch/catch.hpp>
#include <array>
#include <numeric>

// This is a quick way to check that checks are valid
#define USE_STD_VECTOR 0

class DestructionCounter
{
	public:
		DestructionCounter() :
		m_counter(nullptr),
		m_value(0)
		{
		}

		DestructionCounter(std::size_t* counter, int value) :
		m_counter(counter),
		m_value(value)
		{
			if (m_counter)
				(*m_counter)++;
		}

		DestructionCounter(const DestructionCounter& counter) :
		m_counter(counter.m_counter),
		m_value(counter.m_value)
		{
			if (m_counter)
				(*m_counter)++;
		}

		DestructionCounter(DestructionCounter&& counter) :
		m_counter(counter.m_counter),
		m_value(counter.m_value)
		{
			if (m_counter)
				(*m_counter)++;
		}

		~DestructionCounter()
		{
			if (m_counter)
			{
				assert(*m_counter > 0);
				(*m_counter)--;
			}
		}

		operator int() const
		{
			return m_value;
		}

		DestructionCounter& operator=(const DestructionCounter& counter)
		{
			if (m_counter)
			{
				assert(*m_counter > 0);
				(*m_counter)--;
			}

			m_counter = counter.m_counter;
			m_value = counter.m_value;

			if (m_counter)
				(*m_counter)++;

			return *this;
		}

		DestructionCounter& operator=(DestructionCounter&& counter)
		{
			if (this == &counter)
				return *this;

			if (m_counter)
			{
				assert(*m_counter > 0);
				(*m_counter)--;
			}

			m_counter = counter.m_counter;
			m_value = counter.m_value;

			if (m_counter)
				(*m_counter)++;

			return *this;
		}

	private:
		std::size_t* m_counter;
		int m_value;
};

SCENARIO("StackVector", "[CORE][STACKVECTOR]")
{
	GIVEN("A StackVector to contain multiple int")
	{
		std::size_t counter = 0;
		{
			volatile std::size_t capacity = 50;
#if USE_STD_VECTOR
			std::vector<DestructionCounter> vector;
			vector.reserve(capacity);
#else
			Nz::StackVector<DestructionCounter> vector = NazaraStackVector(DestructionCounter, capacity);
#endif

			WHEN("At construction, the vector is empty but has capacity")
			{
				CHECK(vector.capacity() == capacity);
				CHECK(vector.empty());
				CHECK(vector.size() == 0);
				CHECK(vector.max_size() == capacity);
			}

			WHEN("Resizing it changes its size and create/destroy elements")
			{
				vector.resize(vector.capacity());
				CHECK(vector.size() == vector.capacity());
				CHECK(counter == 0);
				vector.resize(0);
				CHECK(vector.empty());
				CHECK(vector.size() == 0);
				CHECK(counter == 0);
			}

			WHEN("Resizing it allocates elements")
			{
				vector.resize(vector.capacity(), DestructionCounter(&counter, 0));
				CHECK(vector.size() == vector.capacity());
				CHECK(counter == capacity);
				vector.resize(0);
				CHECK(vector.empty());
				CHECK(vector.size() == 0);
				CHECK(counter == 0);
			}

			WHEN("Emplacing five elements, vector size increase accordingly")
			{
				for (std::size_t i = 0; i < 5; ++i)
				{
#if USE_STD_VECTOR
					vector.emplace_back(&counter, int(i));
#else
					CHECK(vector.emplace_back(&counter, int(i)) == int(i));
#endif
				}

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 0, 1, 2, 3, 4 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("Pushing three elements, vector size increase accordingly")
			{
				for (std::size_t i = 0; i < 3; ++i)
				{
					DestructionCounter val(&counter, int(i));
#if USE_STD_VECTOR
					vector.push_back(val);
#else
					CHECK(vector.push_back(val) == val);
#endif
				}

				CHECK(!vector.empty());
				CHECK(vector.size() == 3);

				std::array<int, 3> expectedValues = { 0, 1, 2 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));

				THEN("We resize to five")
				{
					vector.resize(5);

					CHECK(!vector.empty());
					CHECK(vector.size() == 5);

					std::array<int, 5> expectedValues = { 0, 1, 2, 0, 0 };
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));

					AND_THEN("We resize it back to zero")
					{
						vector.resize(0);

						CHECK(vector.empty());
						CHECK(vector.size() == 0);
					}
					AND_THEN("We clear it")
					{
						vector.clear();

						CHECK(vector.empty());
						CHECK(vector.size() == 0);
						CHECK(counter == 0);
					}
				}
			}

			WHEN("We generate its content will iota")
			{
				vector.resize(10);
				for (std::size_t i = 0; i < vector.size(); ++i)
					vector[i] = DestructionCounter(&counter, -5 + int(i));

				std::array<int, 10> expectedValues = { -5, -4, -3, -2, -1, 0, 1, 2, 3, 4 };
				CHECK(vector.size() == expectedValues.size());
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));

				AND_WHEN("We pop back some elements")
				{
					for (std::size_t i = 0; i < 5; ++i)
						vector.pop_back();

					std::array<int, 5> expectedValues = { -5, -4, -3, -2, -1 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase elements at the beginning")
				{
					vector.erase(vector.begin());
					vector.erase(vector.begin());

					std::array<int, 8> expectedValues = { -3, -2, -1, 0, 1, 2, 3, 4 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase elements in the middle")
				{
					vector.erase(vector.begin() + 2);
					vector.erase(vector.begin() + 2);
					vector.erase(vector.begin() + 6);

					std::array<int, 7> expectedValues = { -5, -4, -1, 0, 1, 2, 4 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase elements at the end")
				{
					vector.erase(vector.end() - 1);
					vector.erase(vector.end() - 1);

					std::array<int, 8> expectedValues = { -5, -4, -3, -2, -1, 0, 1, 2 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase a range")
				{
					vector.erase(vector.begin() + 2, vector.end() - 3);

					std::array<int, 5> expectedValues = { -5, -4, 2, 3, 4 };
					CHECK(vector.size() == expectedValues.size());
					CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
				}
				AND_WHEN("We erase everything")
				{
					vector.erase(vector.begin(), vector.end());

					CHECK(vector.empty());
				}
			}

			WHEN("We generate its content using emplace")
			{
				for (std::size_t i = 0; i < 5; ++i)
					CHECK(*vector.emplace(vector.end(), &counter, int(i)) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 0, 1, 2, 3, 4 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using emplace, in reverse order")
			{
				for (std::size_t i = 0; i < 5; ++i)
					CHECK(*vector.emplace(vector.begin(), &counter, int(i)) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 4, 3, 2, 1, 0 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using emplace, at the middle")
			{
				for (std::size_t i = 0; i < 10; ++i)
					CHECK(*vector.emplace(vector.begin() + i / 2, &counter, int(i)) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 10);

				std::array<int, 10> expectedValues = { 1, 3, 5, 7, 9, 8, 6, 4, 2, 0 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using insert")
			{
				for (std::size_t i = 0; i < 5; ++i)
					CHECK(*vector.insert(vector.end(), DestructionCounter(&counter, int(i))) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 0, 1, 2, 3, 4 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using insert, in reverse order")
			{
				for (std::size_t i = 0; i < 5; ++i)
					CHECK(*vector.insert(vector.begin(), DestructionCounter(&counter, int(i))) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 5);

				std::array<int, 5> expectedValues = { 4, 3, 2, 1, 0 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}

			WHEN("We generate its content using insert, at the middle")
			{
				for (std::size_t i = 0; i < 10; ++i)
					CHECK(*vector.insert(vector.begin() + i / 2, DestructionCounter(&counter, int(i))) == int(i));

				CHECK(!vector.empty());
				CHECK(vector.size() == 10);

				std::array<int, 10> expectedValues = { 1, 3, 5, 7, 9, 8, 6, 4, 2, 0 };
				CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
			}
		}

		CHECK(counter == 0);
	}
}
<|endoftext|>


<commit_before>#ifndef MJOLNIR_BOND_LENGTH_INTERACTION
#define MJOLNIR_BOND_LENGTH_INTERACTION
#include "Particle.hpp"
#include "LocalPotentialBase.hpp"
#include <mjolnir/math/fast_inv_sqrt.hpp>

namespace mjolnir
{

/*! @brief calculate energy and force of Bond length type local interaction */
template<typename traitsT>
class BondLengthInteraction
{
  public:

    typedef traitsT traits_type;
    typedef typename traits_type::time_type time_type;
    typedef typename traits_type::real_type real_type;
    typedef typename traits_type::coordinate_type coordinate_type;
    typedef Particle<coordinate_type> particle_type;
    typedef LocalPotentialBase<traits_type> potential_type;

  public:

    BondLengthInteraction() = default;
    ~BondLengthInteraction() = default;

    void
    calc_force(particle_type& p1, particle_type& p2, const potential_type& pot);

    real_type
    calc_energy(const particle_type& p1, const particle_type& p2,
                const potential_type& pot);
};

template<typename traitsT>
inline void
BondLengthInteraction<traitsT>::calc_force(particle_type& p1, particle_type& p2,
        const potential_type& pot)
{
    const real_type f = -1 * pot.derivative(length(p1.position - p2.position));
    const coordinate_type dpos = p2.position - p1.position;
    const coordinate_type force = dpos * (fast_inv_sqrt(length_sq(dpos)) * f);
    p1.force -= force;
    p2.force += force;
    return;
}

template<typename traitsT>
inline typename BondLengthInteraction<traitsT>::real_type
BondLengthInteraction<traitsT>::calc_energy(
        const particle_type& p1, const particle_type& p2,
        const potential_type& pot)
{
    return pot.potential(length(p1.position - p2.position));
}

} // mjolnir
#endif /* MJOLNIR_BOND_LENGTH_INTERACTION */
<commit_msg>change order of calculation<commit_after>#ifndef MJOLNIR_BOND_LENGTH_INTERACTION
#define MJOLNIR_BOND_LENGTH_INTERACTION
#include "Particle.hpp"
#include "LocalPotentialBase.hpp"
#include <mjolnir/math/fast_inv_sqrt.hpp>
#include <cmath>

namespace mjolnir
{

/*! @brief calculate energy and force of Bond length type local interaction */
template<typename traitsT>
class BondLengthInteraction
{
  public:

    typedef traitsT traits_type;
    typedef typename traits_type::time_type time_type;
    typedef typename traits_type::real_type real_type;
    typedef typename traits_type::coordinate_type coordinate_type;
    typedef Particle<coordinate_type> particle_type;
    typedef LocalPotentialBase<traits_type> potential_type;

  public:

    BondLengthInteraction() = default;
    ~BondLengthInteraction() = default;

    void
    calc_force(particle_type& p1, particle_type& p2, const potential_type& pot);

    real_type
    calc_energy(const particle_type& p1, const particle_type& p2,
                const potential_type& pot);
};

template<typename traitsT>
inline void
BondLengthInteraction<traitsT>::calc_force(particle_type& p1, particle_type& p2,
        const potential_type& pot)
{
    const coordinate_type dpos = p2.position - p1.position;
    const real_type lensq = length_sq(dpos);
    const real_type f = -1 * pot.derivative(std::sqrt(lensq));
    const coordinate_type force = dpos * (fast_inv_sqrt(lensq) * f);
    p1.force -= force;
    p2.force += force;
    return;
}

template<typename traitsT>
inline typename BondLengthInteraction<traitsT>::real_type
BondLengthInteraction<traitsT>::calc_energy(
        const particle_type& p1, const particle_type& p2,
        const potential_type& pot)
{
    return pot.potential(length(p1.position - p2.position));
}

} // mjolnir
#endif /* MJOLNIR_BOND_LENGTH_INTERACTION */
<|endoftext|>


<commit_before><commit_msg>Fix visibility determination for CS.<commit_after><|endoftext|>


<commit_before>
#include <cstdio>
#include <cstring>
#include <vector>

#include <unistd.h>

#include <OMX_Core.h>
#include <OMX_Component.h>

#include "common/test_omxil.h"
#include "common/omxil_utils.h"
#include "common/omxil_comp.hpp"

class comp_test_empty_buffer : public omxil_comp {
public:
	typedef omxil_comp super;

	comp_test_empty_buffer(const char *comp_name)
		: omxil_comp(comp_name)
	{
		//do nothing
	}

	virtual ~comp_test_empty_buffer()
	{
		//do nothing
	}

	virtual OMX_ERRORTYPE EventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData)
	{
		/* if (1) {
		} else*/ {
			//default handler
			return super::EventHandler(hComponent, pAppData, eEvent,
				nData1, nData2, pEventData);
		}

		return OMX_ErrorNone;
	}

};

int main(int argc, char *argv[])
{
	const char *arg_comp;
	comp_test_empty_buffer *comp;
	OMX_PARAM_PORTDEFINITIONTYPE def_in;
	std::vector<OMX_BUFFERHEADERTYPE *> buf_in;
	OMX_U32 pnum_in;
	OMX_ERRORTYPE result;
	OMX_U32 i;

	//get arguments
	if (argc < 2) {
		arg_comp = "OMX.st.video_decoder.avc";
	} else {
		arg_comp = argv[1];
	}

	//Reference:
	//    OpenMAX IL specification version 1.1.2
	//    3.4.2.1 Non-tunneled Data Flow
	//    3.2.2.17 OMX_EmptyThisBuffer

	comp = nullptr;
	result = OMX_ErrorNone;
	//port 0
	pnum_in = 0;

	result = OMX_Init();
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_Init failed.\n");
		goto err_out1;
	}

	comp = new comp_test_empty_buffer(arg_comp);
	if (comp == nullptr || comp->get_component() == nullptr) {
		fprintf(stderr, "OMX_GetHandle failed.\n");
		result = OMX_ErrorInsufficientResources;
		goto err_out2;
	}
	printf("OMX_GetHandle: name:%s, comp:%p\n",
		arg_comp, comp);

	//Get port definition(before)
	result = comp->get_param_port_definition(pnum_in, &def_in);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "get_port_definition(before) failed.\n");
		goto err_out2;
	}
	printf("IndexParamPortDefinition: before in %d -----\n", (int)def_in.nPortIndex);
	dump_port_definitiontype(&def_in);

	//Set StateIdle
	result = comp->SendCommand(OMX_CommandStateSet, OMX_StateIdle, 0);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_SendCommand(StateSet, Idle) failed.\n");
		goto err_out2;
	}

	buf_in.clear();
	for (i = 0; i < def_in.nBufferCountActual; i++) {
		OMX_BUFFERHEADERTYPE *buf;
		OMX_U8 *pb = nullptr;
		buffer_attr *pbattr = nullptr;

		pb = new OMX_U8[def_in.nBufferSize];
		pbattr = new buffer_attr;
		memset(pbattr, 0, sizeof(buffer_attr));

		result = comp->UseBuffer(&buf,
			pnum_in, pbattr, def_in.nBufferSize, pb);
		if (result != OMX_ErrorNone) {
			fprintf(stderr, "OMX_UseBuffer(in) failed.\n");
			goto err_out2;
		}
		printf("OMX_UseBuffer: in \n");
		dump_port_bufferheadertype(buf);

		comp->push_back_buffer(pnum_in, buf);
		buf_in.push_back(buf);
	}

	//Wait for StatusIdle
	printf("wait for StateIdle...\n");
	comp->wait_state_changed(OMX_StateIdle);
	printf("wait for StateIdle... Done!\n");

	//Set StateExecuting
	result = comp->SendCommand(OMX_CommandStateSet, OMX_StateExecuting, 0);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_SendCommand(StateSet, Executing) failed.\n");
		goto err_out2;
	}

	//Wait for StatusExecuting
	printf("wait for StateExecuting...\n");
	comp->wait_state_changed(OMX_StateExecuting);
	printf("wait for StateExecuting... Done!\n");

	//EmptyThisBuffer
	for (i = 0; i < 100; i++) {
		OMX_BUFFERHEADERTYPE *buf;

		comp->wait_buffer_free(pnum_in);

		buf = comp->use_free_buffer(pnum_in);
		if (buf == nullptr) {
			fprintf(stderr, "find_free_buffer(%d) failed.\n",
				(int)pnum_in);
			goto err_out2;
		}

		result = comp->EmptyThisBuffer(buf);
		if (result != OMX_ErrorNone) {
			fprintf(stderr, "EmptyThisBuffer(%d) failed.\n",
				(int)pnum_in);
			goto err_out2;
		}
	}

	//Set StateIdle
	result = comp->SendCommand(OMX_CommandStateSet, OMX_StateIdle, 0);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_SendCommand(StateSet, Idle) failed.\n");
		goto err_out2;
	}

	//Wait for StatusIdle
	printf("wait for StateIdle...\n");
	comp->wait_state_changed(OMX_StateIdle);
	printf("wait for StateIdle... Done!\n");

	//Set StateLoaded
	result = comp->SendCommand(OMX_CommandStateSet, OMX_StateLoaded, 0);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_SendCommand(StateSet, Loaded) failed.\n");
		goto err_out2;
	}

	printf("wait for EmptyDone of all buffers...\n");
	comp->wait_all_buffer_free(pnum_in);
	printf("wait for EmptyDone of all buffers... Done!\n");

	//Free buffer
	for (auto it = buf_in.begin(); it != buf_in.end(); it++) {
		OMX_U8 *pb = (*it)->pBuffer;
		buffer_attr *pbattr = static_cast<buffer_attr *>((*it)->pAppPrivate);

		result = comp->FreeBuffer(pnum_in, *it);
		if (result != OMX_ErrorNone) {
			fprintf(stderr, "OMX_FreeBuffer(%d) failed.\n",
				(int)pnum_in);
			goto err_out2;
		}

		delete pbattr;
		delete[] pb;
	}
	buf_in.clear();

	//Wait for StatusLoaded
	printf("wait for StateLoaded...\n");
	comp->wait_state_changed(OMX_StateLoaded);
	printf("wait for StateLoaded... Done!\n");

	//Terminate
	delete comp;

	result = OMX_Deinit();
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_Deinit failed.\n");
		goto err_out1;
	}

	return 0;

err_out2:
	for (auto it = buf_in.begin(); it != buf_in.end(); it++) {
		OMX_U8 *pb = (*it)->pBuffer;
		buffer_attr *pbattr = static_cast<buffer_attr *>((*it)->pAppPrivate);

		comp->FreeBuffer(pnum_in, *it);

		delete pbattr;
		delete[] pb;
	}

	delete comp;

	OMX_Deinit();

err_out1:
	return -1;
}
<commit_msg>Support port number that is start from non-zero.<commit_after>
#include <cstdio>
#include <cstring>
#include <vector>

#include <unistd.h>

#include <OMX_Core.h>
#include <OMX_Component.h>

#include "common/test_omxil.h"
#include "common/omxil_utils.h"
#include "common/omxil_comp.hpp"

class comp_test_empty_buffer : public omxil_comp {
public:
	typedef omxil_comp super;

	comp_test_empty_buffer(const char *comp_name)
		: omxil_comp(comp_name)
	{
		//do nothing
	}

	virtual ~comp_test_empty_buffer()
	{
		//do nothing
	}

	virtual OMX_ERRORTYPE EventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData)
	{
		/* if (1) {
		} else*/ {
			//default handler
			return super::EventHandler(hComponent, pAppData, eEvent,
				nData1, nData2, pEventData);
		}

		return OMX_ErrorNone;
	}

};

int main(int argc, char *argv[])
{
	const char *arg_comp;
	comp_test_empty_buffer *comp;
	OMX_PORT_PARAM_TYPE param_v;
	OMX_PARAM_PORTDEFINITIONTYPE def_in;
	std::vector<OMX_BUFFERHEADERTYPE *> buf_in;
	OMX_U32 pnum_in;
	OMX_ERRORTYPE result;
	OMX_U32 i;

	//get arguments
	if (argc < 2) {
		arg_comp = "OMX.st.video_decoder.avc";
	} else {
		arg_comp = argv[1];
	}

	//Reference:
	//    OpenMAX IL specification version 1.1.2
	//    3.4.2.1 Non-tunneled Data Flow
	//    3.2.2.17 OMX_EmptyThisBuffer

	comp = nullptr;
	result = OMX_ErrorNone;
	//port 0
	pnum_in = 0;

	result = OMX_Init();
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_Init failed.\n");
		goto err_out1;
	}

	comp = new comp_test_empty_buffer(arg_comp);
	if (comp == nullptr || comp->get_component() == nullptr) {
		fprintf(stderr, "OMX_GetHandle failed.\n");
		result = OMX_ErrorInsufficientResources;
		goto err_out2;
	}
	printf("OMX_GetHandle: name:%s, comp:%p\n",
		arg_comp, comp);

	//Get port definition(before)
	result = comp->get_param_video_init(&param_v);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "get_video_init() failed.\n");
		goto err_out2;
	}
	printf("IndexParamVideoInit: -----\n");
	dump_port_param_type(&param_v);

	pnum_in = param_v.nStartPortNumber;

	result = comp->get_param_port_definition(pnum_in, &def_in);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "get_port_definition(before) failed.\n");
		goto err_out2;
	}
	printf("IndexParamPortDefinition: before in %d -----\n", (int)def_in.nPortIndex);
	dump_port_definitiontype(&def_in);

	//Set StateIdle
	result = comp->SendCommand(OMX_CommandStateSet, OMX_StateIdle, 0);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_SendCommand(StateSet, Idle) failed.\n");
		goto err_out2;
	}

	buf_in.clear();
	for (i = 0; i < def_in.nBufferCountActual; i++) {
		OMX_BUFFERHEADERTYPE *buf;
		OMX_U8 *pb = nullptr;
		buffer_attr *pbattr = nullptr;

		pb = new OMX_U8[def_in.nBufferSize];
		pbattr = new buffer_attr;
		memset(pbattr, 0, sizeof(buffer_attr));

		result = comp->UseBuffer(&buf,
			pnum_in, pbattr, def_in.nBufferSize, pb);
		if (result != OMX_ErrorNone) {
			fprintf(stderr, "OMX_UseBuffer(in) failed.\n");
			goto err_out2;
		}
		printf("OMX_UseBuffer: in \n");
		dump_port_bufferheadertype(buf);

		comp->push_back_buffer(pnum_in, buf);
		buf_in.push_back(buf);
	}

	//Wait for StatusIdle
	printf("wait for StateIdle...\n");
	comp->wait_state_changed(OMX_StateIdle);
	printf("wait for StateIdle... Done!\n");

	//Set StateExecuting
	result = comp->SendCommand(OMX_CommandStateSet, OMX_StateExecuting, 0);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_SendCommand(StateSet, Executing) failed.\n");
		goto err_out2;
	}

	//Wait for StatusExecuting
	printf("wait for StateExecuting...\n");
	comp->wait_state_changed(OMX_StateExecuting);
	printf("wait for StateExecuting... Done!\n");

	//EmptyThisBuffer
	for (i = 0; i < 100; i++) {
		OMX_BUFFERHEADERTYPE *buf;

		comp->wait_buffer_free(pnum_in);

		buf = comp->use_free_buffer(pnum_in);
		if (buf == nullptr) {
			fprintf(stderr, "find_free_buffer(%d) failed.\n",
				(int)pnum_in);
			goto err_out2;
		}

		result = comp->EmptyThisBuffer(buf);
		if (result != OMX_ErrorNone) {
			fprintf(stderr, "EmptyThisBuffer(%d) failed.\n",
				(int)pnum_in);
			goto err_out2;
		}
	}

	//Set StateIdle
	result = comp->SendCommand(OMX_CommandStateSet, OMX_StateIdle, 0);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_SendCommand(StateSet, Idle) failed.\n");
		goto err_out2;
	}

	//Wait for StatusIdle
	printf("wait for StateIdle...\n");
	comp->wait_state_changed(OMX_StateIdle);
	printf("wait for StateIdle... Done!\n");

	//Set StateLoaded
	result = comp->SendCommand(OMX_CommandStateSet, OMX_StateLoaded, 0);
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_SendCommand(StateSet, Loaded) failed.\n");
		goto err_out2;
	}

	printf("wait for EmptyDone of all buffers...\n");
	comp->wait_all_buffer_free(pnum_in);
	printf("wait for EmptyDone of all buffers... Done!\n");

	//Free buffer
	for (auto it = buf_in.begin(); it != buf_in.end(); it++) {
		OMX_U8 *pb = (*it)->pBuffer;
		buffer_attr *pbattr = static_cast<buffer_attr *>((*it)->pAppPrivate);

		result = comp->FreeBuffer(pnum_in, *it);
		if (result != OMX_ErrorNone) {
			fprintf(stderr, "OMX_FreeBuffer(%d) failed.\n",
				(int)pnum_in);
			goto err_out2;
		}

		delete pbattr;
		delete[] pb;
	}
	buf_in.clear();

	//Wait for StatusLoaded
	printf("wait for StateLoaded...\n");
	comp->wait_state_changed(OMX_StateLoaded);
	printf("wait for StateLoaded... Done!\n");

	//Terminate
	delete comp;

	result = OMX_Deinit();
	if (result != OMX_ErrorNone) {
		fprintf(stderr, "OMX_Deinit failed.\n");
		goto err_out1;
	}

	return 0;

err_out2:
	for (auto it = buf_in.begin(); it != buf_in.end(); it++) {
		OMX_U8 *pb = (*it)->pBuffer;
		buffer_attr *pbattr = static_cast<buffer_attr *>((*it)->pAppPrivate);

		comp->FreeBuffer(pnum_in, *it);

		delete pbattr;
		delete[] pb;
	}

	delete comp;

	OMX_Deinit();

err_out1:
	return -1;
}
<|endoftext|>