<commit_before>// Copyright (C) 2016-2020 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#include <type_safe/boolean.hpp>

#include <catch.hpp>

#include <sstream>

using namespace type_safe;

#ifndef TYPE_SAFE_TEST_NO_STATIC_ASSERT
static_assert(std::is_pod<boolean>::value, "");
// conversion checks
static_assert(std::is_constructible<boolean, bool>::value, "");
static_assert(!std::is_constructible<boolean, int>::value, "");
static_assert(std::is_assignable<boolean, bool>::value, "");
static_assert(!std::is_assignable<boolean, int>::value, "");
#endif

TEST_CASE("boolean")
{
    SECTION("constructor")
    {
        boolean b1(true);
        REQUIRE(static_cast<bool>(b1));

        boolean b2(false);
        REQUIRE(!static_cast<bool>(b2));
    }
    SECTION("assignment")
    {
        boolean b1(true);
        b1 = false;
        REQUIRE(!static_cast<bool>(b1));
        b1 = true;
        REQUIRE(static_cast<bool>(b1));
    }
    SECTION("negate")
    {
        boolean b1(true);
        REQUIRE(!b1 == false);

        boolean b2(false);
        REQUIRE(!b2 == true);
    }
    SECTION("comparison")
    {
        boolean b1(true);
        REQUIRE(b1 == true);
        REQUIRE(true == b1);
        REQUIRE(b1 != false);
        REQUIRE(false != b1);
        REQUIRE(b1 == boolean(true));
        REQUIRE(b1 != boolean(false));

        boolean b2(false);
        REQUIRE(b2 == false);
        REQUIRE(false == b2);
        REQUIRE(b2 != true);
        REQUIRE(true != b2);
        REQUIRE(b2 == boolean(false));
        REQUIRE(b2 != boolean(true));
    }
    SECTION("i/o")
    {
        std::ostringstream out;
        std::istringstream in("0");

        boolean b(true);
        out << b;
        REQUIRE(out.str() == "1");

        in >> b;
        REQUIRE(!static_cast<bool>(b));
    }
}
<commit_msg>Replace is_pod in test project with is_standard_layout and is_trivially_copyable (#132)<commit_after>// Copyright (C) 2016-2020 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#include <type_safe/boolean.hpp>

#include <catch.hpp>

#include <sstream>

using namespace type_safe;

#ifndef TYPE_SAFE_TEST_NO_STATIC_ASSERT
static_assert(std::is_standard_layout<boolean>::value, "");
static_assert(std::is_trivially_copyable<boolean>::value, "");
// conversion checks
static_assert(std::is_constructible<boolean, bool>::value, "");
static_assert(!std::is_constructible<boolean, int>::value, "");
static_assert(std::is_assignable<boolean, bool>::value, "");
static_assert(!std::is_assignable<boolean, int>::value, "");
#endif

TEST_CASE("boolean")
{
    SECTION("constructor")
    {
        boolean b1(true);
        REQUIRE(static_cast<bool>(b1));

        boolean b2(false);
        REQUIRE(!static_cast<bool>(b2));
    }
    SECTION("assignment")
    {
        boolean b1(true);
        b1 = false;
        REQUIRE(!static_cast<bool>(b1));
        b1 = true;
        REQUIRE(static_cast<bool>(b1));
    }
    SECTION("negate")
    {
        boolean b1(true);
        REQUIRE(!b1 == false);

        boolean b2(false);
        REQUIRE(!b2 == true);
    }
    SECTION("comparison")
    {
        boolean b1(true);
        REQUIRE(b1 == true);
        REQUIRE(true == b1);
        REQUIRE(b1 != false);
        REQUIRE(false != b1);
        REQUIRE(b1 == boolean(true));
        REQUIRE(b1 != boolean(false));

        boolean b2(false);
        REQUIRE(b2 == false);
        REQUIRE(false == b2);
        REQUIRE(b2 != true);
        REQUIRE(true != b2);
        REQUIRE(b2 == boolean(false));
        REQUIRE(b2 != boolean(true));
    }
    SECTION("i/o")
    {
        std::ostringstream out;
        std::istringstream in("0");

        boolean b(true);
        out << b;
        REQUIRE(out.str() == "1");

        in >> b;
        REQUIRE(!static_cast<bool>(b));
    }
}
<|endoftext|>


<commit_before>#include "system/solution/mpi_group_angular_solution.h"

namespace bart {

namespace system {

namespace solution {

MPIGroupAngularSolution::MPIGroupAngularSolution(const int total_angles)
    : total_angles_(total_angles) {
  for (int angle = 0; angle < total_angles; ++angle) {
    // Insert uninitilized MPIVectors
    MPIVector new_vector;
    solutions_[angle] = new_vector;
  }
  this->set_description("Group solution (MPI), total angles = " + total_angles);
  this->is_default_implementation(true);
}

} // namespace solution

} // namespace system

} // namespace bart<commit_msg>added needed to_string to description of MPI Group Angular solution<commit_after>#include "system/solution/mpi_group_angular_solution.h"

namespace bart {

namespace system {

namespace solution {

MPIGroupAngularSolution::MPIGroupAngularSolution(const int total_angles)
    : total_angles_(total_angles) {
  for (int angle = 0; angle < total_angles; ++angle) {
    // Insert uninitilized MPIVectors
    MPIVector new_vector;
    solutions_[angle] = new_vector;
  }
  this->set_description("Group solution (MPI), total angles = " +
      std::to_string(total_angles));
  this->is_default_implementation(true);
}

} // namespace solution

} // namespace system

} // namespace bart<|endoftext|>


<commit_before>/*
 * Copyright 2009-2018 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     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.
 *
 */
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE vc2index_test
#include <boost/test/unit_test.hpp>
#include <votca/xtp/vc2index.h>
#include <iostream>

using namespace votca::xtp;
BOOST_AUTO_TEST_SUITE(vc2index_test)

BOOST_AUTO_TEST_CASE(index_test) {
    int vmin=0;
    int cmin=10;
    int ctotal=10;
    int vtotal=9;

    vc2index vc=vc2index(vmin,cmin,ctotal);

    int v=3;
    int c=12;

    BOOST_CHECK_EQUAL(vc.I(v,c),32);

    BOOST_CHECK_EQUAL(vc.c(vc.I(v,c)),c);
    BOOST_CHECK_EQUAL(vc.v(vc.I(v,c)),v);

    std::vector<int> indexv;
    std::vector<int> indexc;

    for (int v = 0; v < vtotal;v++) {
            for (int c = 0; c < ctotal; c++) {
              indexv.push_back(vmin + v);
              indexc.push_back(cmin + c);
            }
          }

    for(int j=0;j<indexv.size();j++){
        BOOST_CHECK_EQUAL(indexv[j],vc.v(j));
    }

     for(int j=0;j<indexc.size();j++){
        BOOST_CHECK_EQUAL(indexc[j],vc.c(j));
    }

}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>fixed unsigned warning<commit_after>/*
 * Copyright 2009-2018 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 *     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.
 *
 */
#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE vc2index_test
#include <boost/test/unit_test.hpp>
#include <votca/xtp/vc2index.h>
#include <iostream>

using namespace votca::xtp;
BOOST_AUTO_TEST_SUITE(vc2index_test)

BOOST_AUTO_TEST_CASE(index_test) {
    int vmin=0;
    int cmin=10;
    int ctotal=10;
    int vtotal=9;

    vc2index vc=vc2index(vmin,cmin,ctotal);

    int v=3;
    int c=12;

    BOOST_CHECK_EQUAL(vc.I(v,c),32);

    BOOST_CHECK_EQUAL(vc.c(vc.I(v,c)),c);
    BOOST_CHECK_EQUAL(vc.v(vc.I(v,c)),v);

    std::vector<int> indexv;
    std::vector<int> indexc;

    for (int v = 0; v < vtotal;v++) {
            for (int c = 0; c < ctotal; c++) {
              indexv.push_back(vmin + v);
              indexc.push_back(cmin + c);
            }
          }

    for(unsigned j=0;j<indexv.size();j++){
        BOOST_CHECK_EQUAL(indexv[j],vc.v(j));
    }

     for(unsigned j=0;j<indexc.size();j++){
        BOOST_CHECK_EQUAL(indexc[j],vc.c(j));
    }

}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*
 * SessionClang.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionClang.hpp"

#include <core/Exec.hpp>

#include <core/json/JsonRpc.hpp>

#include <core/system/System.hpp>
#include <core/system/Process.hpp>

#include <r/RSexp.hpp>
#include <r/RRoutines.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/IncrementalFileChangeHandler.hpp>

#include "libclang/LibClang.hpp"
#include "libclang/UnsavedFiles.hpp"
#include "libclang/SourceIndex.hpp"

#include "CodeCompletion.hpp"

using namespace core ;

namespace session {
namespace modules {
namespace clang {

using namespace libclang;

namespace {

bool isCppSourceDoc(const FilePath& docPath)
{
   std::string ex = docPath.extensionLowerCase();
   return (ex == ".c" || ex == ".cc" || ex == ".cpp" || ex == ".m" ||
           ex == ".mm" || ex == ".h" || ex == ".hpp");
}

bool noTranslationUnitsFilter(const FileInfo& fileInfo)
{
   return false;
}

bool translationUnitFilter(const FileInfo& packageSrcDir,
                           const FileInfo& fileInfo)
{

   return
      // must be within package/src
      boost::algorithm::starts_with(fileInfo.absolutePath(),
                                    packageSrcDir.absolutePath()) &&

      // must be a C++ source doc
      isCppSourceDoc(FilePath(fileInfo.absolutePath()));
}

void translationUnitChangeHandler(const core::system::FileChangeEvent& event)
{
   using namespace core::system;

   switch(event.type())
   {
      case FileChangeEvent::FileAdded:
      case FileChangeEvent::FileModified:
         sourceIndex().updateTranslationUnit(event.fileInfo().absolutePath());
         break;
      case FileChangeEvent::FileRemoved:
         sourceIndex().removeTranslationUnit(event.fileInfo().absolutePath());
         break;
      case FileChangeEvent::None:
         break;
   }
}

void onSourceDocUpdated(boost::shared_ptr<source_database::SourceDocument> pDoc)
{
   // ignore if the file doesn't have a path
   if (pDoc->path().empty())
      return;

   // resolve to a full path
   FilePath docPath = module_context::resolveAliasedPath(pDoc->path());

   // verify that it's an indexable C/C++ file (we allow any and all
   // files into the database here since these files are open within
   // the source editor)
   if (!isCppSourceDoc(docPath))
      return;

   // update unsaved files (we do this even if the document is dirty
   // as even in this case it will need to be removed from the list
   // of unsaved files)
   unsavedFiles().update(pDoc);

   // update the main index if we've either never seen this doc
   // or if it's not dirty (the former case is needed for resuming
   // from suspend and ensuring that docs alive in the editor but
   // not the project filesystem are tracked)
   std::string path = docPath.absolutePath();
   if (!sourceIndex().hasTranslationUnit(path) || !pDoc->dirty())
      sourceIndex().updateTranslationUnit(path);
}

// diagnostic function to assist in determine whether/where
// libclang was loaded from (and any errors which occurred
// that prevented loading, e.g. inadequate version, missing
// symbols, etc.)
SEXP rs_isLibClangAvailable()
{
   // check availability
   std::string diagnostics;
   bool isAvailable = isLibClangAvailable(&diagnostics);

   // print diagnostics
   module_context::consoleWriteOutput(diagnostics);

   // return status
   r::sexp::Protect rProtect;
   return r::sexp::create(isAvailable, &rProtect);
}

// incremental file change handler
boost::scoped_ptr<IncrementalFileChangeHandler> pFileChangeHandler;

} // anonymous namespace

bool isAvailable()
{
   return clang().isLoaded();
}

Error initialize()
{
   // attempt to load clang interface
   loadLibClang();

   // register diagnostics function
   R_CallMethodDef methodDef ;
   methodDef.name = "rs_isLibClangAvailable" ;
   methodDef.fun = (DL_FUNC)rs_isLibClangAvailable;
   methodDef.numArgs = 0;
   r::routines::addCallMethod(methodDef);

   // subscribe to onSourceDocUpdated (used for maintaining both the
   // main source index and the unsaved files list)
   source_database::events().onDocUpdated.connect(onSourceDocUpdated);

   // connect source doc removed events to unsaved files list
   source_database::events().onDocRemoved.connect(
             boost::bind(&UnsavedFiles::remove, &unsavedFiles(), _1));
   source_database::events().onRemoveAll.connect(
             boost::bind(&UnsavedFiles::removeAll, &unsavedFiles()));

   // create a filter based on whether we are in a package
   using namespace projects;
   IncrementalFileChangeHandler::Filter filter = noTranslationUnitsFilter;
   if (projectContext().config().buildType == r_util::kBuildTypePackage)
   {
      FilePath pkgSrc = projectContext().buildTargetPath().childPath("src");
      if (pkgSrc.exists())
         filter = boost::bind(translationUnitFilter, FileInfo(pkgSrc), _1);
   }

   // create incremental file change handler (this is used for updating
   // the main source index). also subscribe it to the file monitor
   pFileChangeHandler.reset(new IncrementalFileChangeHandler(
             filter,
             translationUnitChangeHandler,
             boost::posix_time::milliseconds(200),
             boost::posix_time::milliseconds(20),
             false)); /* allow indexing during idle time */
   pFileChangeHandler->subscribeToFileMonitor("C++ Code Completion");

   ExecBlock initBlock ;
   using boost::bind;
   using namespace module_context;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "print_cpp_completions", printCppCompletions));
   return initBlock.execute();

   // return success
   return Success();
}

} // namespace clang
} // namespace modules
} // namesapce session

<commit_msg>only index c++ translation units (i.e. not headers)<commit_after>/*
 * SessionClang.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionClang.hpp"

#include <core/Exec.hpp>

#include <core/json/JsonRpc.hpp>

#include <core/system/System.hpp>
#include <core/system/Process.hpp>

#include <r/RSexp.hpp>
#include <r/RRoutines.hpp>

#include <session/SessionModuleContext.hpp>
#include <session/IncrementalFileChangeHandler.hpp>

#include "libclang/LibClang.hpp"
#include "libclang/UnsavedFiles.hpp"
#include "libclang/SourceIndex.hpp"

#include "CodeCompletion.hpp"

using namespace core ;

namespace session {
namespace modules {
namespace clang {

using namespace libclang;

namespace {

bool isCppSourceDoc(const FilePath& docPath)
{
   std::string ex = docPath.extensionLowerCase();
   return (ex == ".c" || ex == ".cc" || ex == ".cpp" ||
           ex == ".m" || ex == ".mm");
}

bool noTranslationUnitsFilter(const FileInfo& fileInfo)
{
   return false;
}

bool translationUnitFilter(const std::string packageSrcDir,
                           const FileInfo& fileInfo)
{

   return
      // must be within package/src
      boost::algorithm::starts_with(fileInfo.absolutePath(), packageSrcDir) &&

      // must be a C++ doc
      isCppSourceDoc(FilePath(fileInfo.absolutePath()));
}

void translationUnitChangeHandler(const core::system::FileChangeEvent& event)
{
   using namespace core::system;

   switch(event.type())
   {
      case FileChangeEvent::FileAdded:
      case FileChangeEvent::FileModified:
         sourceIndex().updateTranslationUnit(event.fileInfo().absolutePath());
         break;
      case FileChangeEvent::FileRemoved:
         sourceIndex().removeTranslationUnit(event.fileInfo().absolutePath());
         break;
      case FileChangeEvent::None:
         break;
   }
}

void onSourceDocUpdated(boost::shared_ptr<source_database::SourceDocument> pDoc)
{
   // ignore if the file doesn't have a path
   if (pDoc->path().empty())
      return;

   // resolve to a full path
   FilePath docPath = module_context::resolveAliasedPath(pDoc->path());

   // verify that it's an indexable C/C++ file (we allow any and all
   // files into the database here since these files are open within
   // the source editor)
   if (!isCppSourceDoc(docPath))
      return;

   // update unsaved files (we do this even if the document is dirty
   // as even in this case it will need to be removed from the list
   // of unsaved files)
   unsavedFiles().update(pDoc);

   // update the main index if we've either never seen this doc
   // or if it's not dirty (the former case is needed for resuming
   // from suspend and ensuring that docs alive in the editor but
   // not the project filesystem are tracked)
   std::string path = docPath.absolutePath();
   if (!sourceIndex().hasTranslationUnit(path) || !pDoc->dirty())
      sourceIndex().updateTranslationUnit(path);
}

// diagnostic function to assist in determine whether/where
// libclang was loaded from (and any errors which occurred
// that prevented loading, e.g. inadequate version, missing
// symbols, etc.)
SEXP rs_isLibClangAvailable()
{
   // check availability
   std::string diagnostics;
   bool isAvailable = isLibClangAvailable(&diagnostics);

   // print diagnostics
   module_context::consoleWriteOutput(diagnostics);

   // return status
   r::sexp::Protect rProtect;
   return r::sexp::create(isAvailable, &rProtect);
}

// incremental file change handler
boost::scoped_ptr<IncrementalFileChangeHandler> pFileChangeHandler;

} // anonymous namespace

bool isAvailable()
{
   return clang().isLoaded();
}

Error initialize()
{
   // attempt to load clang interface
   loadLibClang();

   // register diagnostics function
   R_CallMethodDef methodDef ;
   methodDef.name = "rs_isLibClangAvailable" ;
   methodDef.fun = (DL_FUNC)rs_isLibClangAvailable;
   methodDef.numArgs = 0;
   r::routines::addCallMethod(methodDef);

   // subscribe to onSourceDocUpdated (used for maintaining both the
   // main source index and the unsaved files list)
   source_database::events().onDocUpdated.connect(onSourceDocUpdated);

   // connect source doc removed events to unsaved files list
   source_database::events().onDocRemoved.connect(
             boost::bind(&UnsavedFiles::remove, &unsavedFiles(), _1));
   source_database::events().onRemoveAll.connect(
             boost::bind(&UnsavedFiles::removeAll, &unsavedFiles()));

   // create a filter based on whether we are in a package
   using namespace projects;
   IncrementalFileChangeHandler::Filter filter = noTranslationUnitsFilter;
   if (projectContext().config().buildType == r_util::kBuildTypePackage)
   {
      FilePath pkgSrc = projectContext().buildTargetPath().childPath("src");
      if (pkgSrc.exists())
         filter = boost::bind(translationUnitFilter, pkgSrc.absolutePath(), _1);
   }

   // create incremental file change handler (this is used for updating
   // the main source index). also subscribe it to the file monitor
   pFileChangeHandler.reset(new IncrementalFileChangeHandler(
             filter,
             translationUnitChangeHandler,
             boost::posix_time::milliseconds(200),
             boost::posix_time::milliseconds(20),
             false)); /* allow indexing during idle time */
   pFileChangeHandler->subscribeToFileMonitor("C++ Code Completion");

   ExecBlock initBlock ;
   using boost::bind;
   using namespace module_context;
   initBlock.addFunctions()
      (bind(registerRpcMethod, "print_cpp_completions", printCppCompletions));
   return initBlock.execute();

   // return success
   return Success();
}

} // namespace clang
} // namespace modules
} // namesapce session

<|endoftext|>


<commit_before>#include <tetra/meta/Variant.hpp>

using namespace tetra;
using namespace tetra::meta;

Variant::Variant( const MetaData& metaData ) noexcept
  : metaData{&metaData},
    pObj{metaData.constructInstance()}
{
}

Variant::~Variant()
{
  if ( pObj != nullptr && metaData != nullptr )
  {
    metaData->destroyInstance( pObj );
    pObj = nullptr;
    metaData = nullptr;
  }
}

Variant::Variant( Variant&& variant ) noexcept
  : metaData{&variant.getMetaData()},
    pObj{variant.pObj}
{
  variant.metaData = nullptr;
  variant.pObj = nullptr;
}

Variant& Variant::operator=( Variant&& variant ) noexcept
{
  if ( pObj != nullptr && metaData != nullptr )
  {
    metaData->destroyInstance( pObj );
  }

  // in-place new to call the move c'tor
  new ( this ) Variant{std::move( variant )};

  return *this;
}

void Variant::copy( const Variant& variant ) noexcept
{
  if ( pObj != nullptr && metaData != nullptr )
  {
    metaData->destroyInstance( pObj );
  }

  metaData = variant.metaData;
  pObj     = metaData->constructInstance();

  metaData->copyInstance( pObj, variant.pObj );
}

bool Variant::serialize( Json::Value& root ) const
{
  if (!getMetaData().canSerialize())
    return false;

  return getMetaData().serializeInstance( this->pObj, root );
}

bool Variant::deserialize( Json::Value& root )
{
  if (!getMetaData().canSerialize())
    return false;

  return getMetaData().deserializeInstance( this->pObj, root );
}

const MetaData& Variant::getMetaData() const noexcept
{
  return *metaData;
}
<commit_msg>fixed a bug in the variant::copy method where copying a non-initialized variant would cause undefined behavior<commit_after>#include <tetra/meta/Variant.hpp>

using namespace tetra;
using namespace tetra::meta;

Variant::Variant( const MetaData& metaData ) noexcept
  : metaData{&metaData},
    pObj{metaData.constructInstance()}
{
}

Variant::~Variant()
{
  if ( pObj != nullptr && metaData != nullptr )
  {
    metaData->destroyInstance( pObj );
    pObj = nullptr;
    metaData = nullptr;
  }
}

Variant::Variant( Variant&& variant ) noexcept
  : metaData{&variant.getMetaData()},
    pObj{variant.pObj}
{
  variant.metaData = nullptr;
  variant.pObj = nullptr;
}

Variant& Variant::operator=( Variant&& variant ) noexcept
{
  if ( pObj != nullptr && metaData != nullptr )
  {
    metaData->destroyInstance( pObj );
  }

  // in-place new to call the move c'tor
  new ( this ) Variant{std::move( variant )};

  return *this;
}

void Variant::copy( const Variant& variant ) noexcept
{
  if ( pObj != nullptr && metaData != nullptr )
  {
    metaData->destroyInstance( pObj );
    pObj = nullptr;
    metaData = nullptr;
  }

  if ( variant.metaData != nullptr && variant.pObj != nullptr )
  {
    metaData = variant.metaData;
    pObj = metaData->constructInstance();

    metaData->copyInstance( pObj, variant.pObj );
  }
}

bool Variant::serialize( Json::Value& root ) const
{
  if (!getMetaData().canSerialize())
    return false;

  return getMetaData().serializeInstance( this->pObj, root );
}

bool Variant::deserialize( Json::Value& root )
{
  if (!getMetaData().canSerialize())
    return false;

  return getMetaData().deserializeInstance( this->pObj, root );
}

const MetaData& Variant::getMetaData() const noexcept
{
  return *metaData;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include "tfileaiologger.h"
<commit_msg>added async I/O file writer for Windows.<commit_after>/* Copyright (c) 2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include "tfileaiowriter.h"
#include <QList>
#include <windows.h>

typedef struct
{
    char *aio_buf;
    int aio_nbytes;
    OVERLAPPED aio_overlap;
} aiobuf_t;

class TFileAioWriterData
{
public:
    mutable QMutex mutex;
    QString fileName;
    HANDLE fileHandle;
    QList<aiobuf_t *> syncBuffer;

    TFileAioWriterData() : mutex(QMutex::Recursive), fileName(), fileHandle(INVALID_HANDLE_VALUE), syncBuffer() { }
    void clearSyncBuffer();
};

void TFileAioWriterData::clearSyncBuffer()
{
    for (QListIterator<aiobuf_t *> it(syncBuffer); it.hasNext(); ) {
        aiobuf_t *ab = it.next();
        delete (char *)ab->aio_buf;
        delete ab;
    }
    syncBuffer.clear();
}

/*!
  Constructor.
 */
TFileAioWriter::TFileAioWriter(const QString &name)
    : d(new TFileAioWriterData)
{
    d->fileName = name;
}

TFileAioWriter::~TFileAioWriter()
{
    close();
    delete d;
}

bool TFileAioWriter::open()
{
    QMutexLocker locker(&d->mutex);

    if (d->fileHandle == INVALID_HANDLE_VALUE) {
        if (d->fileName.isEmpty())
            return false;

        d->fileHandle = CreateFile((const wchar_t*)d->fileName.utf16(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL);
        if (d->fileHandle == INVALID_HANDLE_VALUE) {
            //tSystemError("file open failed: %s", qPrintable(d->fileName));
        }
    }

    return (d->fileHandle != INVALID_HANDLE_VALUE);
}

void TFileAioWriter::close()
{
    QMutexLocker locker(&d->mutex);

    flush();

    if (d->fileHandle != INVALID_HANDLE_VALUE) {
        CloseHandle(d->fileHandle);
    }
    d->fileHandle = INVALID_HANDLE_VALUE;
}

bool TFileAioWriter::isOpen() const
{
    return (d->fileHandle != INVALID_HANDLE_VALUE);
}

int TFileAioWriter::write(const char *data, int length)
{
    QMutexLocker locker(&d->mutex);

    if (!isOpen()) {
        return -1;
    }

    // check whether last writing is finished
    if (d->syncBuffer.count() > 0) {
        aiobuf_t *lastab = d->syncBuffer.last();
        if (HasOverlappedIoCompleted(&lastab->aio_overlap)) {
            d->clearSyncBuffer();
        }
    }

    aiobuf_t *ab = new aiobuf_t;
    memset(ab, 0, sizeof(aiobuf_t));

    ab->aio_nbytes = length;
    ab->aio_buf = new char[length];
    ab->aio_overlap.Offset = 0xFFFFFFFF;
    ab->aio_overlap.OffsetHigh = 0xFFFFFFFF;
    memcpy((void *)ab->aio_buf, data, length);

    DWORD dwWritten;
    BOOL res = WriteFile(d->fileHandle, ab->aio_buf, (DWORD)length, &dwWritten, &ab->aio_overlap);

    if (!res) {
        delete (char *)ab->aio_buf;
        delete ab;

        close();
        return -1;
    }

    d->syncBuffer << ab;
    return (int)dwWritten;
}

void TFileAioWriter::flush()
{
    QMutexLocker locker(&d->mutex);

    FlushFileBuffers(d->fileHandle);
    d->clearSyncBuffer();
}

void TFileAioWriter::setFileName(const QString &name)
{
    QMutexLocker locker(&d->mutex);

    if (isOpen()) {
        close();
    }
    d->fileName = name;
}

QString TFileAioWriter::fileName() const
{
    QMutexLocker locker(&d->mutex);
    return d->fileName;
}
<|endoftext|>


<commit_before>#pragma once

#include "slotted_bag.hpp"
#include "thread_pool_options.hpp"
#include "thread_pool_state.hpp"

#include <atomic>
#include <thread>
#include <limits>
#include <mutex>
#include <chrono>
#include <condition_variable>

namespace tp
{

/**
* @brief The Worker class owns task queue and executing thread.
* In thread it tries to pop task from queue. If queue is empty then it tries
* to steal task from the sibling worker. If steal was unsuccessful then spins
* with one millisecond delay.
* @details State Machine:
*
*            +----------------+---------------+
*            |                |               |
*            v                |               |
*       +--------+       +----------+      +------+
*    +--| Active | ----> | BusyWait | ---> | Idle |
*    |  +--------+       +----------+      +------+
*    |       ^
*    |       |
*    +-------+
*
*/
template <typename Task, template<typename> class Queue>
class Worker final
{
    using WorkerVector = std::vector<std::unique_ptr<Worker<Task, Queue>>>;

    class WorkerStoppedException final : public std::exception
    {
    };

    /**
    * @brief State An Enum representing the Rouser thread state.
    */
    enum class State
    {
        Initialized,
        Running,
        Stopped
    };

public:
    /**
    * @brief Worker Constructor.
    * @param busy_wait_options The busy wait behaviour options.
    * @param queue_size Length of underlying task queue.
    */
    explicit Worker(ThreadPoolOptions::BusyWaitOptions const& busy_wait_options, size_t queue_size);

    /**
    * @brief Copy ctor implementation.
    */
    Worker(Worker const&) = delete;

    /**
    * @brief Copy assignment implementation.
    */
    Worker& operator=(Worker const& rhs) = delete;

    /**
    * @brief Move ctor implementation.
    */
    Worker(Worker&& rhs) = delete;

    /**
    * @brief Move assignment implementaion.
    */
    Worker& operator=(Worker&& rhs) = delete;

    /**
    * @brief Destructor implementation.
    */
    ~Worker();

    /**
    * @brief start Create the executing thread and start tasks execution.
    * @param id Worker ID.
    * @param state A pointer to thread pool's shared state.
    * @note The parameters passed into this function generally relate to the global thread pool state.
    */
    void start(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state);

    /**
    * @brief stop Stop all worker's thread and stealing activity.
    * Waits until the executing thread becomes finished.
    * @note Stop may only be called once start() has been invoked.
    * Repeated successful calls to stop() will be no-ops after the first.
    */
    void stop();

    /**
    * @brief tryPost Post task to queue.
    * @param handler Handler to be executed in executing thread.
    * @return true on success.
    */
    template <typename Handler>
    bool tryPost(Handler&& handler);

    /**
    * @brief tryGetLocalTask Get one task from this worker queue.
    * @param task Place for the obtained task to be stored.
    * @return true on success.
    */
    bool tryGetLocalTask(Task& task);

    /**
    * @brief getWorkerIdForCurrentThread Return worker ID associated with
    * current thread if exists.
    * @return Worker ID.
    */
    static size_t getWorkerIdForCurrentThread();

    /**
    * @brief wake Awake the worker if it was previously asleep.
    */
    void wake();

private:

    /**
    * @brief tryRoundRobinSteal Try stealing a thread from sibling workers in a round-robin fashion.
    * @param task Place for the obtained task to be stored.
    * @param workers Sibling workers for performing round robin work stealing.
    * @return true upon success, false otherwise.
    */
    bool tryRoundRobinSteal(Task& task, WorkerVector& workers);

    /**
    * @brief HandleTask Process a specific task.
    * @param task The task to be processed.
    */
    void handleTask(Task& task);

    /**
    * @brief tryGetTask Try to obtain a work item.
    * @details This entails attempting to pop an item from the local queue, and if not successful,
    * the worker will attempt to perform a round robin steal.
    * @param task Place for the obtained task to be stored.
    * @param workers Sibling workers for performing round robin work stealing.
    * @return true upon success, false otherwise.
    */
    bool tryGetTask(Task& task, WorkerVector& workers);

    /**
    * @brief threadFunc Executing thread function.
    * @param id Worker ID.
    * @param state A pointer to thread pool's shared state.
    * @note The parameters passed into this function generally relate to the global thread pool state.
    */
    void threadFunc(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state);

    Queue<Task> m_queue;
    std::atomic<State> m_state;
    std::thread m_thread;
    size_t m_next_donor;
    ThreadPoolOptions::BusyWaitOptions m_busy_wait_options;

    std::mutex m_idle_mutex;
    std::condition_variable m_idle_cv;

    bool m_is_idle;
    bool m_abort_idle;

};

/// Implementation

namespace detail
{
    inline size_t& thread_id()
    {
        static thread_local size_t tss_id = std::numeric_limits<size_t>::max();
        return tss_id;
    }
}

template <typename Task, template<typename> class Queue>
inline Worker<Task, Queue>::Worker(ThreadPoolOptions::BusyWaitOptions const& busy_wait_options, size_t queue_size)
    : m_queue(queue_size)
    , m_state(State::Initialized)
    , m_next_donor(0) // Initialized in threadFunc.
    , m_busy_wait_options(busy_wait_options)
    , m_is_idle(false)
    , m_abort_idle(false)
{
}

template <typename Task, template<typename> class Queue>
inline Worker<Task, Queue>::~Worker()
{
    stop();
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::stop()
{
    auto expectedState = State::Running;
    if (m_state.compare_exchange_strong(expectedState, State::Stopped, std::memory_order_acq_rel, std::memory_order_relaxed))
    {
        wake();
        m_thread.join();
    }
    else if (expectedState == State::Initialized)
        throw std::runtime_error("Cannot stop Worker: stop may only be calld after the Worker has been started.");
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::start(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state)
{
    auto expectedState = State::Initialized;
    if (!m_state.compare_exchange_strong(expectedState, State::Running, std::memory_order_acq_rel, std::memory_order_relaxed))
        throw std::runtime_error("Cannot start Worker: it has previously been started or stopped.");

    m_thread = std::thread(&Worker<Task, Queue>::threadFunc, this, id, state);
}

template <typename Task, template<typename> class Queue>
inline size_t Worker<Task, Queue>::getWorkerIdForCurrentThread()
{
    return detail::thread_id();
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::wake()
{
    bool notify;
    {
        std::unique_lock<std::mutex> lock(m_idle_mutex);

        m_abort_idle = true;
        notify = m_is_idle;
    }

    // Notify outside of lock.
    if (notify)
        m_idle_cv.notify_one();
}

template <typename Task, template<typename> class Queue>
template <typename Handler>
inline bool Worker<Task, Queue>::tryPost(Handler&& handler)
{
    return m_queue.push(std::forward<Handler>(handler));
}

template <typename Task, template<typename> class Queue>
inline bool Worker<Task, Queue>::tryGetLocalTask(Task& task)
{
    return m_queue.pop(task);
}

template <typename Task, template<typename> class Queue>
inline bool Worker<Task, Queue>::tryRoundRobinSteal(Task& task, WorkerVector& workers)
{
    auto starting_index = m_next_donor;

    // Iterate once through the worker ring, checking for queued work items on each thread.
    do
    {
        // Don't steal from local queue.
        if (m_next_donor != detail::thread_id() && workers[m_next_donor]->tryGetLocalTask(task))
        {
            // Increment before returning so that m_next_donor always points to the worker that has gone the longest
            // without a steal attempt. This helps enforce fairness in the stealing.
            ++m_next_donor %= workers.size();
            return true;
        }

        ++m_next_donor %= workers.size();
    } while (m_next_donor != starting_index);

    return false;
}

template <typename Task, template <typename> class Queue>
void Worker<Task, Queue>::handleTask(Task& task)
{
    try
    {
        task();
    }
    catch (...)
    {
		LogPrint("mempool", "%s\n", "Unknown Worker task Error!!!");
		printf("Unknown Worker task Error!!\n");
        // Suppress all exceptions.
    }
}

template <typename Task, template <typename> class Queue>
bool Worker<Task, Queue>::tryGetTask(Task& task, WorkerVector& workers)
{
    if (m_state.load(std::memory_order_acquire) != State::Running)
        throw WorkerStoppedException();

    // Prioritize local queue, then try stealing from sibling workers.
    return tryGetLocalTask(task) || tryRoundRobinSteal(task, workers);
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::threadFunc(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state)
{
    detail::thread_id() = id;
    m_next_donor = (id + 1) % state->workers().size();
    Task handler;
    bool task_found = false;

    try
    {
        while (true)
        {
            // By default, this loop operates in the active state.
            // We poll for items from our local task queue and try to steal from others.
            if (tryGetTask(handler, state->workers()))
            {
                handleTask(handler);
                continue;
            };

            // We were unable to obtain a task.
            // We now transition into the busy wait state.
            task_found = false;
            state->numBusyWaiters().fetch_add(1, std::memory_order_acq_rel);

            for (auto i = 0u; i < m_busy_wait_options.numIterations() && !task_found; i++)
            {
                std::this_thread::sleep_for(m_busy_wait_options.iterationFunction()(i));
                task_found = tryGetTask(handler, state->workers());
            }

            // If we found a task during our busy wait sequence, we abort it and transition back into the active loop.
            if (task_found)
            {
                state->numBusyWaiters().fetch_sub(1, std::memory_order_acq_rel);
                handleTask(handler); // Handle the task body only once we decrement the busy waiting loop.
                continue;
            }

            // No tasks were found during the busy wait sequence.
            // We now transition into the idle state.
            {
                std::unique_lock<std::mutex> lock(m_idle_mutex);
                m_is_idle = false;
                m_abort_idle = false;
            }

            // We put this worker up for grabs as a recipient to new posts in the thread pool.
            state->idleWorkers().fill(id);

            // We need to transition out of the busy wait state after we have submitted ourselves to the idle
            // worker queue in order to avoid a race.
            state->numBusyWaiters().fetch_sub(1, std::memory_order_acq_rel);

            // While we were adding this worker to the idle worker bag, a job may have been posted into this
            // worker's queue. We need to check for work again before initiating the deep sleep sequence, otherwise
            // the given task may be lost.
            // Any further posts will flip the m_abort_idle flag to true, and we will catch them later.
            if (tryGetTask(handler, state->workers()))
            {
                handleTask(handler);
                // A task was indeed posted in the time it took this worker to enter the bag.
                // We remove the worker from the bag. If the internal state of the bag was not changed,
                // this means a different thread has already removed this worker from the idle queue,
                // and this case will be caught below. Looping early in this case will cause a loss of synchronization.
                if (state->idleWorkers().empty(id))
                    continue;
            }

            {
                std::unique_lock<std::mutex> lock(m_idle_mutex);

                // A post has occurred during the initialization of the sleep sequence! Abort the sleep sequence.
                if (m_abort_idle)
                    continue;

                m_is_idle = true;
                m_idle_cv.wait(lock, [this]() { return m_abort_idle; });
            }
        }
    }
    catch (WorkerStoppedException &e)
    {
        // Allow thread function to complete.
		LogPrint("mempool", "%s: %s\n", "Worker Error", e.what());
		printf("worker error %s\n", e.what())
    }
}

}<commit_msg>compile<commit_after>#pragma once

#include "slotted_bag.hpp"
#include "thread_pool_options.hpp"
#include "thread_pool_state.hpp"

#include <atomic>
#include <thread>
#include <limits>
#include <mutex>
#include <chrono>
#include <condition_variable>

namespace tp
{

/**
* @brief The Worker class owns task queue and executing thread.
* In thread it tries to pop task from queue. If queue is empty then it tries
* to steal task from the sibling worker. If steal was unsuccessful then spins
* with one millisecond delay.
* @details State Machine:
*
*            +----------------+---------------+
*            |                |               |
*            v                |               |
*       +--------+       +----------+      +------+
*    +--| Active | ----> | BusyWait | ---> | Idle |
*    |  +--------+       +----------+      +------+
*    |       ^
*    |       |
*    +-------+
*
*/
template <typename Task, template<typename> class Queue>
class Worker final
{
    using WorkerVector = std::vector<std::unique_ptr<Worker<Task, Queue>>>;

    class WorkerStoppedException final : public std::exception
    {
    };

    /**
    * @brief State An Enum representing the Rouser thread state.
    */
    enum class State
    {
        Initialized,
        Running,
        Stopped
    };

public:
    /**
    * @brief Worker Constructor.
    * @param busy_wait_options The busy wait behaviour options.
    * @param queue_size Length of underlying task queue.
    */
    explicit Worker(ThreadPoolOptions::BusyWaitOptions const& busy_wait_options, size_t queue_size);

    /**
    * @brief Copy ctor implementation.
    */
    Worker(Worker const&) = delete;

    /**
    * @brief Copy assignment implementation.
    */
    Worker& operator=(Worker const& rhs) = delete;

    /**
    * @brief Move ctor implementation.
    */
    Worker(Worker&& rhs) = delete;

    /**
    * @brief Move assignment implementaion.
    */
    Worker& operator=(Worker&& rhs) = delete;

    /**
    * @brief Destructor implementation.
    */
    ~Worker();

    /**
    * @brief start Create the executing thread and start tasks execution.
    * @param id Worker ID.
    * @param state A pointer to thread pool's shared state.
    * @note The parameters passed into this function generally relate to the global thread pool state.
    */
    void start(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state);

    /**
    * @brief stop Stop all worker's thread and stealing activity.
    * Waits until the executing thread becomes finished.
    * @note Stop may only be called once start() has been invoked.
    * Repeated successful calls to stop() will be no-ops after the first.
    */
    void stop();

    /**
    * @brief tryPost Post task to queue.
    * @param handler Handler to be executed in executing thread.
    * @return true on success.
    */
    template <typename Handler>
    bool tryPost(Handler&& handler);

    /**
    * @brief tryGetLocalTask Get one task from this worker queue.
    * @param task Place for the obtained task to be stored.
    * @return true on success.
    */
    bool tryGetLocalTask(Task& task);

    /**
    * @brief getWorkerIdForCurrentThread Return worker ID associated with
    * current thread if exists.
    * @return Worker ID.
    */
    static size_t getWorkerIdForCurrentThread();

    /**
    * @brief wake Awake the worker if it was previously asleep.
    */
    void wake();

private:

    /**
    * @brief tryRoundRobinSteal Try stealing a thread from sibling workers in a round-robin fashion.
    * @param task Place for the obtained task to be stored.
    * @param workers Sibling workers for performing round robin work stealing.
    * @return true upon success, false otherwise.
    */
    bool tryRoundRobinSteal(Task& task, WorkerVector& workers);

    /**
    * @brief HandleTask Process a specific task.
    * @param task The task to be processed.
    */
    void handleTask(Task& task);

    /**
    * @brief tryGetTask Try to obtain a work item.
    * @details This entails attempting to pop an item from the local queue, and if not successful,
    * the worker will attempt to perform a round robin steal.
    * @param task Place for the obtained task to be stored.
    * @param workers Sibling workers for performing round robin work stealing.
    * @return true upon success, false otherwise.
    */
    bool tryGetTask(Task& task, WorkerVector& workers);

    /**
    * @brief threadFunc Executing thread function.
    * @param id Worker ID.
    * @param state A pointer to thread pool's shared state.
    * @note The parameters passed into this function generally relate to the global thread pool state.
    */
    void threadFunc(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state);

    Queue<Task> m_queue;
    std::atomic<State> m_state;
    std::thread m_thread;
    size_t m_next_donor;
    ThreadPoolOptions::BusyWaitOptions m_busy_wait_options;

    std::mutex m_idle_mutex;
    std::condition_variable m_idle_cv;

    bool m_is_idle;
    bool m_abort_idle;

};

/// Implementation

namespace detail
{
    inline size_t& thread_id()
    {
        static thread_local size_t tss_id = std::numeric_limits<size_t>::max();
        return tss_id;
    }
}

template <typename Task, template<typename> class Queue>
inline Worker<Task, Queue>::Worker(ThreadPoolOptions::BusyWaitOptions const& busy_wait_options, size_t queue_size)
    : m_queue(queue_size)
    , m_state(State::Initialized)
    , m_next_donor(0) // Initialized in threadFunc.
    , m_busy_wait_options(busy_wait_options)
    , m_is_idle(false)
    , m_abort_idle(false)
{
}

template <typename Task, template<typename> class Queue>
inline Worker<Task, Queue>::~Worker()
{
    stop();
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::stop()
{
    auto expectedState = State::Running;
    if (m_state.compare_exchange_strong(expectedState, State::Stopped, std::memory_order_acq_rel, std::memory_order_relaxed))
    {
        wake();
        m_thread.join();
    }
    else if (expectedState == State::Initialized)
        throw std::runtime_error("Cannot stop Worker: stop may only be calld after the Worker has been started.");
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::start(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state)
{
    auto expectedState = State::Initialized;
    if (!m_state.compare_exchange_strong(expectedState, State::Running, std::memory_order_acq_rel, std::memory_order_relaxed))
        throw std::runtime_error("Cannot start Worker: it has previously been started or stopped.");

    m_thread = std::thread(&Worker<Task, Queue>::threadFunc, this, id, state);
}

template <typename Task, template<typename> class Queue>
inline size_t Worker<Task, Queue>::getWorkerIdForCurrentThread()
{
    return detail::thread_id();
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::wake()
{
    bool notify;
    {
        std::unique_lock<std::mutex> lock(m_idle_mutex);

        m_abort_idle = true;
        notify = m_is_idle;
    }

    // Notify outside of lock.
    if (notify)
        m_idle_cv.notify_one();
}

template <typename Task, template<typename> class Queue>
template <typename Handler>
inline bool Worker<Task, Queue>::tryPost(Handler&& handler)
{
    return m_queue.push(std::forward<Handler>(handler));
}

template <typename Task, template<typename> class Queue>
inline bool Worker<Task, Queue>::tryGetLocalTask(Task& task)
{
    return m_queue.pop(task);
}

template <typename Task, template<typename> class Queue>
inline bool Worker<Task, Queue>::tryRoundRobinSteal(Task& task, WorkerVector& workers)
{
    auto starting_index = m_next_donor;

    // Iterate once through the worker ring, checking for queued work items on each thread.
    do
    {
        // Don't steal from local queue.
        if (m_next_donor != detail::thread_id() && workers[m_next_donor]->tryGetLocalTask(task))
        {
            // Increment before returning so that m_next_donor always points to the worker that has gone the longest
            // without a steal attempt. This helps enforce fairness in the stealing.
            ++m_next_donor %= workers.size();
            return true;
        }

        ++m_next_donor %= workers.size();
    } while (m_next_donor != starting_index);

    return false;
}

template <typename Task, template <typename> class Queue>
void Worker<Task, Queue>::handleTask(Task& task)
{
    try
    {
        task();
    }
    catch (...)
    {
		LogPrint("mempool", "%s\n", "Unknown Worker task Error!!!");
		printf("Unknown Worker task Error!!\n");
        // Suppress all exceptions.
    }
}

template <typename Task, template <typename> class Queue>
bool Worker<Task, Queue>::tryGetTask(Task& task, WorkerVector& workers)
{
    if (m_state.load(std::memory_order_acquire) != State::Running)
        throw WorkerStoppedException();

    // Prioritize local queue, then try stealing from sibling workers.
    return tryGetLocalTask(task) || tryRoundRobinSteal(task, workers);
}

template <typename Task, template<typename> class Queue>
inline void Worker<Task, Queue>::threadFunc(const size_t id, std::shared_ptr<ThreadPoolState<Task, Queue>> state)
{
    detail::thread_id() = id;
    m_next_donor = (id + 1) % state->workers().size();
    Task handler;
    bool task_found = false;

    try
    {
        while (true)
        {
            // By default, this loop operates in the active state.
            // We poll for items from our local task queue and try to steal from others.
            if (tryGetTask(handler, state->workers()))
            {
                handleTask(handler);
                continue;
            };

            // We were unable to obtain a task.
            // We now transition into the busy wait state.
            task_found = false;
            state->numBusyWaiters().fetch_add(1, std::memory_order_acq_rel);

            for (auto i = 0u; i < m_busy_wait_options.numIterations() && !task_found; i++)
            {
                std::this_thread::sleep_for(m_busy_wait_options.iterationFunction()(i));
                task_found = tryGetTask(handler, state->workers());
            }

            // If we found a task during our busy wait sequence, we abort it and transition back into the active loop.
            if (task_found)
            {
                state->numBusyWaiters().fetch_sub(1, std::memory_order_acq_rel);
                handleTask(handler); // Handle the task body only once we decrement the busy waiting loop.
                continue;
            }

            // No tasks were found during the busy wait sequence.
            // We now transition into the idle state.
            {
                std::unique_lock<std::mutex> lock(m_idle_mutex);
                m_is_idle = false;
                m_abort_idle = false;
            }

            // We put this worker up for grabs as a recipient to new posts in the thread pool.
            state->idleWorkers().fill(id);

            // We need to transition out of the busy wait state after we have submitted ourselves to the idle
            // worker queue in order to avoid a race.
            state->numBusyWaiters().fetch_sub(1, std::memory_order_acq_rel);

            // While we were adding this worker to the idle worker bag, a job may have been posted into this
            // worker's queue. We need to check for work again before initiating the deep sleep sequence, otherwise
            // the given task may be lost.
            // Any further posts will flip the m_abort_idle flag to true, and we will catch them later.
            if (tryGetTask(handler, state->workers()))
            {
                handleTask(handler);
                // A task was indeed posted in the time it took this worker to enter the bag.
                // We remove the worker from the bag. If the internal state of the bag was not changed,
                // this means a different thread has already removed this worker from the idle queue,
                // and this case will be caught below. Looping early in this case will cause a loss of synchronization.
                if (state->idleWorkers().empty(id))
                    continue;
            }

            {
                std::unique_lock<std::mutex> lock(m_idle_mutex);

                // A post has occurred during the initialization of the sleep sequence! Abort the sleep sequence.
                if (m_abort_idle)
                    continue;

                m_is_idle = true;
                m_idle_cv.wait(lock, [this]() { return m_abort_idle; });
            }
        }
    }
    catch (WorkerStoppedException &e)
    {
        // Allow thread function to complete.
		LogPrint("mempool", "%s: %s\n", "Worker Error", e.what());
		printf("worker error %s\n", e.what());
    }
}

}<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/generic/memory/lib/utils/mss_math.H $              */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
<commit_msg>Remove ZQCAL redundant CCS inst, move to draminit_training<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/generic/memory/lib/utils/mss_math.H $              */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#ifndef _MSS_MATH_H_
#define _MSS_MATH_H_

#include <cstdint>

namespace mss
{
///
/// @brief Calculates inclusive range
/// @tparam T input and output type
/// @param[in] i_start starting point
/// @param[in] i_end ending point
/// @return inclusive range calculation
///
// TODO RTC:174277 - create unit test structure for generic/memory
template<typename T >
inline constexpr T inclusive_range( const T i_start, const T i_end)
{
    return (i_end - i_start) + 1;
}

}// mss

#endif
<|endoftext|>


<commit_before>//
//  EnttecDevice.cpp
//
//  Created by Soso Limited.
//
//

#include "EnttecDevice.h"
#include "cinder/app/App.h"
#include "cinder/Log.h"

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace dmx;

namespace {

const auto EnttecDeviceDummyBaudRate = 57600;
const auto StartOfMessage = 0x7E;
const auto EndOfMessage = 0xE7;
const auto DataStartCode = 0x00;

enum MessageLabel {
//	ReprogramFirmware = 1,
//	ProgramFlashPage = 2,
	GetWidgetParameters = 3,
	SetWidgetParameters = 4,
	ReceivedDMXPacket = 5,
	OutputOnlySendDMXPacket = 6,
	SendRMDPacket = 7,
	ReceiveDMXOnChange = 8,
	ReceivedDMXChangeOfStatePacket = 9,
	GetWidgetSerialNumber = 10,
	SendRDMDiscovery = 11
};

uint8_t leastSignificantByte(int value) {
	return value & 0xFF;
}

uint8_t mostSignificantByte(int value) {
	return (value >> 8) & 0xFF;
}

int combinedNumber(uint8_t lsb, uint8_t msb) {
	return (msb << 8) + lsb;
}

} // namespace

EnttecDevice::EnttecDevice(const std::string &device_name, int device_fps)
{
	_target_frame_time = std::chrono::milliseconds(1000 / device_fps);
	_message_body.assign(512, 0);
	connect(device_name);
}

EnttecDevice::~EnttecDevice()
{
	stopLoop();
	// For now, turn out the lights as the previous implementation did so.
	// In future, perhaps it is better to let the user specify what to do.
	fillBuffer(0);
	writeData();
	closeConnection();
}

void EnttecDevice::closeConnection() {
	stopLoop();

	if (_serial) {
		CI_LOG_I("Shutting down serial connection: " << _serial->getDevice().getPath());
		_serial->flush();
		_serial.reset();
	}
}

void EnttecDevice::startLoop() {
	_do_loop = true;
	_loop_thread = std::thread(&EnttecDevice::dataSendLoop, this);
}

void EnttecDevice::stopLoop() {
	_do_loop = false;
	if (_loop_thread.joinable()) {
		_loop_thread.join();
	}
}

bool EnttecDevice::connect(const std::string &device_name)
{
	closeConnection();

	try
	{
		const Serial::Device dev = Serial::findDeviceByNameContains(device_name);
		_serial = Serial::create(dev, EnttecDeviceDummyBaudRate);
		_serial->flush();
        auto old_stuff = std::vector<uint8_t>();
        old_stuff.resize(_serial->getNumBytesAvailable());
        _serial->readAvailableBytes(old_stuff.data(), old_stuff.size());
        for (auto &c: old_stuff) {
            console() << "Draining: " << (int)c << endl;
        }
		return true;
	}
	catch(const std::exception &exc)
	{
		CI_LOG_E("Error initializing DMX device: " << exc.what());
		CI_ASSERT(_serial == nullptr);
		return false;
	}
}

void EnttecDevice::dataSendLoop()
{
	ci::ThreadSetup thread_setup;
	CI_LOG_I("Starting DMX loop.");

	auto before = std::chrono::high_resolution_clock::now();
	while (_do_loop)
	{
		writeData();

		auto after = std::chrono::high_resolution_clock::now();
		auto actual_frame_time = after - before;
		before = after;
		std::this_thread::sleep_for(_target_frame_time - actual_frame_time);
	}

	CI_LOG_I("Exiting DMX loop.");
}

void EnttecDevice::applySettings(const dmx::EnttecDevice::Settings &settings) {
	std::lock_guard<std::mutex> lock(_data_mutex);

	const auto message = std::array<uint8_t, 8> {
		StartOfMessage,
		MessageLabel::SetWidgetParameters,
		leastSignificantByte(0), // no user settings to pass through
		mostSignificantByte(0),
		settings.break_time,
		settings.mark_after_break_time,
		settings.device_fps,
		EndOfMessage
	};

	_target_frame_time = std::chrono::milliseconds(1000 / settings.device_fps);
	_serial->writeBytes(message.data(), message.size());
}

std::future<EnttecDevice::Settings> EnttecDevice::loadSettings() const {
	return std::async(std::launch::async, [this] () {
		std::lock_guard<std::mutex> lock(_data_mutex);

		const auto message = std::array<uint8_t, 5> {
			StartOfMessage,
			MessageLabel::GetWidgetParameters,
			leastSignificantByte(0),
			mostSignificantByte(0),
			EndOfMessage
		};

		const auto is_response_valid = [] (const std::string &response, size_t message_start) {
			auto has_start = (message_start != string::npos);
			auto contains_enough_data = (response.size() - message_start) > 6;
			auto type = (uint8_t)response[message_start + 1];

			return has_start && contains_enough_data && (type == MessageLabel::GetWidgetParameters);
		};

		if (_serial) {
			_serial->writeBytes(message.data(), message.size());

			auto response = std::string("");
			auto message_start = string::npos;
			while (! is_response_valid(response, message_start)) {
				response = _serial->readStringUntil(EndOfMessage);
				for (auto &c: response) {
					console() << (uint8_t)c << ", ";
				}
				console() << endl;
			}

			CI_ASSERT((uint8_t)response[message_start] == StartOfMessage);
			CI_ASSERT((uint8_t)response.back() == EndOfMessage);

			auto firmware_number = combinedNumber(response[message_start + 2], response[message_start + 3]);
			auto settings = Settings {
				firmware_number,
				(uint8_t)response[message_start + 4],
				(uint8_t)response[message_start + 5],
				(uint8_t)response[message_start + 6]
			};
			return settings;
		}
		else {
			CI_LOG_W("Not connected via serial, returning empty settings.");
			return Settings{ 0, 0, 0, 0 };
		}
	});
}

void EnttecDevice::writeData()
{
	std::lock_guard<std::mutex> lock(_data_mutex);

	if (_serial) {
		const auto data_size = _message_body.size() + 1; // account for data start code
		const auto header = std::array<uint8_t, 5> {
			StartOfMessage,
			MessageLabel::OutputOnlySendDMXPacket,
			leastSignificantByte(data_size),
			mostSignificantByte(data_size),
			DataStartCode
		};
		_serial->writeBytes(header.data(), header.size());
		_serial->writeBytes(_message_body.data(), _message_body.size());
		_serial->writeByte(EndOfMessage);
	}
}

void EnttecDevice::bufferData(const uint8_t *data, size_t size)
{
	std::lock_guard<std::mutex> lock(_data_mutex);
	size = std::min(size, _message_body.size());
	std::memcpy(_message_body.data(), data, size);
}

void EnttecDevice::fillBuffer(uint8_t value)
{
	std::lock_guard<std::mutex> lock(_data_mutex);
	std::memset(_message_body.data(), value, _message_body.size());
}

namespace dmx {

std::ostream& operator << (std::ostream& os, const EnttecDevice::Settings& settings) {
    os << "Firmware version: " << settings.firmware_number;
		os << ", Break time: " << (int)settings.break_time;
		os << ", Mark after break time: " << (int)settings.mark_after_break_time;
		os << ", Device fps: " << (int)settings.device_fps;
    return os;
}

}<commit_msg>Improve device settings querying behavior.<commit_after>//
//  EnttecDevice.cpp
//
//  Created by Soso Limited.
//
//

#include "EnttecDevice.h"
#include "cinder/app/App.h"
#include "cinder/Log.h"

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace dmx;

namespace {

const auto EnttecDeviceDummyBaudRate = 56000;
const auto StartOfMessage = 0x7E;
const auto EndOfMessage = 0xE7;
const auto DataStartCode = 0x00;

enum MessageLabel {
//	ReprogramFirmware = 1,
//	ProgramFlashPage = 2,
	GetWidgetParameters = 3,
	SetWidgetParameters = 4,
	ReceivedDMXPacket = 5,
	OutputOnlySendDMXPacket = 6,
	SendRMDPacket = 7,
	ReceiveDMXOnChange = 8,
	ReceivedDMXChangeOfStatePacket = 9,
	GetWidgetSerialNumber = 10,
	SendRDMDiscovery = 11
};

uint8_t leastSignificantByte(int value) {
	return value & 0xFF;
}

uint8_t mostSignificantByte(int value) {
	return (value >> 8) & 0xFF;
}

int combinedNumber(uint8_t lsb, uint8_t msb) {
	return (msb << 8) + lsb;
}

} // namespace

EnttecDevice::EnttecDevice(const std::string &device_name, int device_fps)
{
	_target_frame_time = std::chrono::milliseconds(1000 / device_fps);
	_message_body.assign(512, 0);
	connect(device_name);
}

EnttecDevice::~EnttecDevice()
{
	stopLoop();
	// For now, turn out the lights as the previous implementation did so.
	// In future, perhaps it is better to let the user specify what to do.
	fillBuffer(0);
	writeData();
	closeConnection();
}

void EnttecDevice::closeConnection() {
	stopLoop();

	if (_serial) {
		CI_LOG_I("Shutting down serial connection: " << _serial->getDevice().getPath());
		_serial->flush();
		_serial.reset();
	}
}

void EnttecDevice::startLoop() {
	_do_loop = true;
	_loop_thread = std::thread(&EnttecDevice::dataSendLoop, this);
}

void EnttecDevice::stopLoop() {
	_do_loop = false;
	if (_loop_thread.joinable()) {
		_loop_thread.join();
	}
}

bool EnttecDevice::connect(const std::string &device_name)
{
	closeConnection();

	try
	{
		const Serial::Device dev = Serial::findDeviceByNameContains(device_name);
		_serial = Serial::create(dev, EnttecDeviceDummyBaudRate);
		_serial->flush();

		// Drain serial.
		auto old_stuff = std::vector<uint8_t>();
		old_stuff.resize(_serial->getNumBytesAvailable());
		_serial->readAvailableBytes(old_stuff.data(), old_stuff.size());
		return true;
	}
	catch(const std::exception &exc)
	{
		CI_LOG_E("Error initializing DMX device: " << exc.what());
		CI_ASSERT(_serial == nullptr);
		return false;
	}
}

void EnttecDevice::dataSendLoop()
{
	ci::ThreadSetup thread_setup;
	CI_LOG_I("Starting DMX loop.");

	auto before = std::chrono::high_resolution_clock::now();
	while (_do_loop)
	{
		writeData();

		auto after = std::chrono::high_resolution_clock::now();
		auto actual_frame_time = after - before;
		before = after;
		std::this_thread::sleep_for(_target_frame_time - actual_frame_time);
	}

	CI_LOG_I("Exiting DMX loop.");
}

void EnttecDevice::applySettings(const dmx::EnttecDevice::Settings &settings) {
	std::lock_guard<std::mutex> lock(_data_mutex);

	const auto message = std::array<uint8_t, 8> {
		StartOfMessage,
		MessageLabel::SetWidgetParameters,
		leastSignificantByte(0), // no user settings to pass through
		mostSignificantByte(0),
		settings.break_time,
		settings.mark_after_break_time,
		settings.device_fps,
		EndOfMessage
	};

	_target_frame_time = std::chrono::milliseconds(1000 / settings.device_fps);
	_serial->writeBytes(message.data(), message.size());
}

std::future<EnttecDevice::Settings> EnttecDevice::loadSettings() const {
	return std::async(std::launch::async, [this] () {
		std::lock_guard<std::mutex> lock(_data_mutex);

		const auto message = std::array<uint8_t, 5> {
			StartOfMessage,
			MessageLabel::GetWidgetParameters,
			leastSignificantByte(0),
			mostSignificantByte(0),
			EndOfMessage
		};

		if (_serial) {
			_serial->writeBytes(message.data(), message.size());

			auto response = std::vector<uint8_t>();
			auto response_is_valid = [&response] {
				if (! response.empty()) {
					return response.back() == EndOfMessage;
				}
				return false;
			};

			while (! response_is_valid()) {
				auto byte = _serial->readByte();
				if (byte == StartOfMessage) {
					response = { byte };
				}
				else {
					response.push_back(byte);
				}

				CI_LOG_D((int)byte);
			}

			const auto message_body_start = 4; // start, type, data lsb, data msb
			// skip two bytes (lsb, msb of message size)
			const auto firmware_index_lsb = message_body_start;
			const auto firmware_index_msb = message_body_start + 1;
			const auto break_time_index = message_body_start + 2;
			const auto mark_after_break_time_index = message_body_start + 3;
			const auto device_fps_index = message_body_start + 4;
			CI_ASSERT(response[0] == StartOfMessage);
			CI_ASSERT(response.back() == EndOfMessage);

			auto firmware_number = combinedNumber(response[firmware_index_lsb], response[firmware_index_msb]);
			auto settings = Settings {
				firmware_number,
				response[break_time_index],
				response[mark_after_break_time_index],
				response[device_fps_index]
			};
			return settings;
		}
		else {
			CI_LOG_W("Not connected via serial, returning empty settings.");
			return Settings{ 0, 0, 0, 0 };
		}
	});
}

void EnttecDevice::writeData()
{
	std::lock_guard<std::mutex> lock(_data_mutex);

	if (_serial) {
		const auto data_size = _message_body.size() + 1; // account for data start code
		const auto header = std::array<uint8_t, 5> {
			StartOfMessage,
			MessageLabel::OutputOnlySendDMXPacket,
			leastSignificantByte(data_size),
			mostSignificantByte(data_size),
			DataStartCode
		};
		_serial->writeBytes(header.data(), header.size());
		_serial->writeBytes(_message_body.data(), _message_body.size());
		_serial->writeByte(EndOfMessage);
	}
}

void EnttecDevice::bufferData(const uint8_t *data, size_t size)
{
	std::lock_guard<std::mutex> lock(_data_mutex);
	size = std::min(size, _message_body.size());
	std::memcpy(_message_body.data(), data, size);
}

void EnttecDevice::fillBuffer(uint8_t value)
{
	std::lock_guard<std::mutex> lock(_data_mutex);
	std::memset(_message_body.data(), value, _message_body.size());
}

namespace dmx {

std::ostream& operator << (std::ostream& os, const EnttecDevice::Settings& settings) {
    os << "Firmware version: " << settings.firmware_number;
		os << ", Break time: " << (int)settings.break_time;
		os << ", Mark after break time: " << (int)settings.mark_after_break_time;
		os << ", Device fps: " << (int)settings.device_fps;
    return os;
}

}<|endoftext|>


<commit_before>#include <iostream>

#define BOOST_TEST_DYN_LINK
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <vector>

#include "cursor.h"

using namespace Akumuli;

void test_cursor(int n_iter, int buf_size) {
    CoroCursor cursor;
    std::vector<EntryOffset> expected;
    auto generator = [n_iter, &expected, &cursor](Caller& caller) {
        for (EntryOffset i = 0u; i < (EntryOffset)n_iter; i++) {
            cursor.put(caller, i);
            expected.push_back(i);
        }
        cursor.complete(caller);
    };
    std::vector<EntryOffset> actual;
    cursor.start(generator);
    while(!cursor.is_done()) {
        EntryOffset offsets[buf_size];
        int n_read = cursor.read(offsets, buf_size);
        std::copy(offsets, offsets + n_read, std::back_inserter(actual));
    }
    cursor.close();
    BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), actual.begin(), actual.end());
}

void test_cursor_error(int n_iter, int buf_size) {
    CoroCursor cursor;
    std::vector<EntryOffset> expected;
    auto generator = [n_iter, &expected, &cursor](Caller& caller) {
        for (EntryOffset i = 0u; i < (EntryOffset)n_iter; i++) {
            cursor.put(caller, i);
            expected.push_back(i);
        }
        cursor.set_error(caller, -1);
    };
    std::vector<EntryOffset> actual;
    cursor.start(generator);
    while(!cursor.is_done()) {
        EntryOffset offsets[buf_size];
        int n_read = cursor.read(offsets, buf_size);
        std::copy(offsets, offsets + n_read, std::back_inserter(actual));
    }
    BOOST_CHECK(cursor.is_error());
    cursor.close();
    BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), actual.begin(), actual.end());
}

BOOST_AUTO_TEST_CASE(Test_cursor_10_10)
{
    test_cursor(10, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_10_100)
{
    test_cursor(10, 100);
}

BOOST_AUTO_TEST_CASE(Test_cursor_100_10)
{
    test_cursor(100, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_100_7)
{
    test_cursor(100, 7);
}

BOOST_AUTO_TEST_CASE(Test_cursor_error_10_10)
{
    test_cursor_error(10, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_error_10_100)
{
    test_cursor_error(10, 100);
}

BOOST_AUTO_TEST_CASE(Test_cursor_error_100_10)
{
    test_cursor_error(100, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_error_100_7)
{
    test_cursor_error(100, 7);
}
<commit_msg>Add cursor tests<commit_after>#include <iostream>

#define BOOST_TEST_DYN_LINK
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <vector>

#include "cursor.h"

using namespace Akumuli;

void test_cursor(int n_iter, int buf_size) {
    CoroCursor cursor;
    std::vector<EntryOffset> expected;
    auto generator = [n_iter, &expected, &cursor](Caller& caller) {
        for (EntryOffset i = 0u; i < (EntryOffset)n_iter; i++) {
            cursor.put(caller, i);
            expected.push_back(i);
        }
        cursor.complete(caller);
    };
    std::vector<EntryOffset> actual;
    cursor.start(generator);
    while(!cursor.is_done()) {
        EntryOffset offsets[buf_size];
        int n_read = cursor.read(offsets, buf_size);
        std::copy(offsets, offsets + n_read, std::back_inserter(actual));
    }
    cursor.close();
    BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), actual.begin(), actual.end());
}

void test_cursor_error(int n_iter, int buf_size) {
    CoroCursor cursor;
    std::vector<EntryOffset> expected;
    auto generator = [n_iter, &expected, &cursor](Caller& caller) {
        for (EntryOffset i = 0u; i < (EntryOffset)n_iter; i++) {
            cursor.put(caller, i);
            expected.push_back(i);
        }
        cursor.set_error(caller, -1);
    };
    std::vector<EntryOffset> actual;
    cursor.start(generator);
    while(!cursor.is_done()) {
        EntryOffset offsets[buf_size];
        int n_read = cursor.read(offsets, buf_size);
        std::copy(offsets, offsets + n_read, std::back_inserter(actual));
    }
    BOOST_CHECK(cursor.is_error());
    cursor.close();
    BOOST_REQUIRE_EQUAL_COLLECTIONS(expected.begin(), expected.end(), actual.begin(), actual.end());
}

BOOST_AUTO_TEST_CASE(Test_cursor_0_10)
{
    test_cursor(0, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_10_10)
{
    test_cursor(10, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_10_100)
{
    test_cursor(10, 100);
}

BOOST_AUTO_TEST_CASE(Test_cursor_100_10)
{
    test_cursor(100, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_100_7)
{
    test_cursor(100, 7);
}

BOOST_AUTO_TEST_CASE(Test_cursor_error_0_10)
{
    test_cursor_error(0, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_error_10_10)
{
    test_cursor_error(10, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_error_10_100)
{
    test_cursor_error(10, 100);
}

BOOST_AUTO_TEST_CASE(Test_cursor_error_100_10)
{
    test_cursor_error(100, 10);
}

BOOST_AUTO_TEST_CASE(Test_cursor_error_100_7)
{
    test_cursor_error(100, 7);
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/hdat/hdattpmdata.H $                                  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef HDATTPMDATA_H
#define HDATTPMDATA_H

/**
 * @file hdattpmdata.H
 *
 * @brief This file contains the class definition for the TPM data object
 *        which manages the HDAT TPM section.
 *
 */

#include <stdint.h>
#include <errl/errlentry.H>
#include <hdat/hdat_reasoncodes.H>
#include "hdatutil.H"
#include <hdat/hdat.H>
#include <sys/misc.h>
#include <securerom/ROM.H>

#define TPM_SRTM_EVENT_LOG_MAX (64 * KILOBYTE)

#define TPM_DRTM_EVENT_LOG_MAX (64 * KILOBYTE)

#define NUM_I2C_PHYS_PRESENCE_DEVICES 2

namespace HDAT
{

/**
 * @brief Enumeration definition for known defaults to TPM data fields
 */
enum {
    TpmDataInstance = 0,
    TpmDataVersion = 0x11,
    TpmDataHdrSize = 0x20,
    TpmDataPtrOffset = 0x20,
    TpmDataPtrCnt = 1,
    TpmDataChildStrCnt = 0,
    TpmDataChildStrOffset = 0,
    TpmDataMinRqrdPcrdVersion = 0x1
};

/**
 * @brief Enumeration definition for the TPM states of existence
 */
enum TpmState {
    TpmPresentAndFunctional = 0x1,
    TpmPresentNonFunctional = 0x2,
    TpmNonPresent = 0x3,
};

/**
 * @brief Structure definition for HDAT Tpm Node Data Header
 */
struct hdatTpmData_t
{
    hdatHDIF_t hdatHdr;
    hdatHDIFDataHdr_t hdatSbTpmInfo; // Pointer pair to secure boot TPM info
    hdatHDIFDataHdr_t hdatPhysInter; // Physical interaction mechanism details
    hdatHDIFDataHdr_t hdatHashVerifyFunc; // Hash and Verification functions
    uint8_t hdatReserved1[8]; // Padding for alignment and growth/compatibility
} __attribute__ ((packed));

/**
 *  @brief Structure definition for Secureboot TPM Instance Info
 */
struct hdatSbTpmInstInfo_t
{
    uint32_t hdatChipId;
    uint32_t hdatDbobId; // Drawer/Book/Octant/Blade ID
    uint8_t hdatLocality1Addr;
    uint8_t hdatLocality2Addr;
    uint8_t hdatLocality3Addr;
    uint8_t hdatLocality4Addr;
    uint8_t hdatFunctionalStatus;
    uint8_t reserved[3];
    uint32_t hdatTpmSrtmEventLogOffset;
    uint32_t hdatTpmSrtmEventLogEntrySize;
    uint32_t hdatTpmDrtmEventLogOffset;
    uint32_t hdatTpmDrtmEventLogEntrySize;
} __attribute__ ((packed));

/**
 *  @brief Type used to specify I2C link IDs
 */
typedef uint32_t i2cLinkId_t;

/**
 *  @brief Special/sentinel i2cLinkId_t values
 */
enum I2C_LINK_ID : i2cLinkId_t
{
    NOT_APPLICABLE = 0xFFFFFFFF,
};

/**
 * @brief Structure definition for HDAT physical interaction mechanism info
 */
struct hdatPhysInterMechInfo_t
{
    // ID of I2C device in the PCRD that supports the "window open" function
    i2cLinkId_t i2cLinkIdWindowOpen;

    // ID of I2C device in the PCRD that supports the "physical presence"
    // function
    i2cLinkId_t i2cLinkIdPhysicalPresence;

} __attribute__ ((packed));

/**
 * @brief Structure definition for HDAT Hash and Verification Function instances
 */
struct hdatHashVerifyFunc_t
{
    sbFuncType_t sbFuncType; // Type of secureboot function
    sbFuncVer_t sbFuncVer; // Version of verify function
    uint32_t dbobId; // Drawer/Book/Octant/Blade ID
    uint32_t sbFuncOffset; // Offset of function within SecureROM
};

extern const char g_hdatTpmDataEyeCatch[];

/** Begin Class Description
 *
 * @brief  The HdatTpmData class is used to construct the Node TPM Related Data
 *         hypervisor data area.
 *
 * Description: This class defines a specialized object.  It is not intended
 *              that any component can create an object of this type.
 *              In particular, the object is built only by the hdat component.
 *
 *              The real purpose of the object is to create the Node TPM
 *              data structure as defined by the PHYP Initialization
 *              architecture.  This data structure is eventually copied to
 *              main memory.  The class is not defined to be a general purpose
 *              interface for building this object by anyone other than the
 *              hdat process.
 *
 * Thread safety:  An HdatTpmData object is not thread safe.  That is, a
 *                 single object cannot be shared and used concurrently by
 *                 multiple threads at the same time.  An object can be used by
 *                 multiple threads if the threads serialize access.  And of
 *                 course, each thread can use its own object with no concerns
 *                 about what other threads are doing.
 *
 * Signal handler usage: This class is not intended to be used in a signal
 *                        handler and nothing has been done to try and make
 *                        it safe to use in a signal handler.
 *
 * End Class Description
 */
class HdatTpmData
{
    public:
        /**
         * @brief Construct an HdatTpmData object.
         *
         *       This is the constructor for the HdatTpmData object.
         *
         *       After creating a new HdatTpmData object via new, you must
         *       check o_errlHndl to see if the constructor ran successfully.
         *       If o_errHndl indicates an error was reported by the
         *       constructor, then new has already allocated heap storage and
         *       the object must be deleted in order to free the heap storage.
         *
         * @pre None
         *
         * @post An HdatTpmData object has been constructed.
         *       Heap storage has been allocated.
         *
         * @param[out] o_errlHndl If any errors occur, the HdatTpmData object is
         *                                      NOT constructed and an error is
         *                                      returned in this parameter
         * @param[in] i_msAddr The main memory address that the service
         *                                      processor subsystem structure
         *                                      will be DMA'd to.
         */
        HdatTpmData(errlHndl_t &o_errlHndl, const HDAT::hdatMsAddr_t &i_msAddr);

        /**
         * @brief HdatTpmData object destructor
         *
         *        This is the destructor for an HdatTpmData object.
         *        Any heap storage allocated for the object is deallocated.
         *
         * @pre No preconditions exist
         *
         * @post The HdatTpmData object has been destroyed and can
         *       no longer be used.
         *
         */
        ~HdatTpmData();

         /**
          * @brief Load TPM Related Data to Mainstore
          *
          * @pre None
          *
          * @post None
          *
          * @param[out] o_size Size of TPM Data structure
          * @param[out] o_count Number of TPM Data structures
          *
          * @retval errlHndl_t nullptr on success, error log on error
          */
        errlHndl_t hdatLoadTpmData(uint32_t &o_size,uint32_t &o_count);

        // delete copy/move constructors and operators
        HdatTpmData(const HdatTpmData& ) = delete;
        HdatTpmData& operator=(const HdatTpmData& ) = delete;
        HdatTpmData(HdatTpmData&&) = delete;
        HdatTpmData& operator=(HdatTpmData&&) = delete;

    private:

        HDAT::hdatMsAddr_t     iv_msAddr;

        hdatTpmData_t *iv_hdatTpmData;

}; // end of HdatTpmData class

/**
 * @brief Calculate the maximum number of TPMs per node for this system.
 *
 * @pre None
 *
 * @post None
 *
 * @retval uint16_t Returns the maximum number of TPMs per node for this system
 */
uint16_t hdatCalcMaxTpmsPerNode();

/**
 * @brief Calculate the maximum size of the HDAT TPM data section
 *
 * @pre None
 *
 * @post None
 *
 * @retval uint32_t Maximum size of the HDAT TPM data section
 */
uint32_t hdatTpmDataCalcMaxSize();

}
#endif // HDATTPMDATA_H
<commit_msg>Fix number of TPM related HDAT section pointer pairs<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/hdat/hdattpmdata.H $                                  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef HDATTPMDATA_H
#define HDATTPMDATA_H

/**
 * @file hdattpmdata.H
 *
 * @brief This file contains the class definition for the TPM data object
 *        which manages the HDAT TPM section.
 *
 */

#include <stdint.h>
#include <errl/errlentry.H>
#include <hdat/hdat_reasoncodes.H>
#include "hdatutil.H"
#include <hdat/hdat.H>
#include <sys/misc.h>
#include <securerom/ROM.H>

#define TPM_SRTM_EVENT_LOG_MAX (64 * KILOBYTE)

#define TPM_DRTM_EVENT_LOG_MAX (64 * KILOBYTE)

#define NUM_I2C_PHYS_PRESENCE_DEVICES 2

namespace HDAT
{

/**
 * @brief Enumeration definition for known defaults to TPM data fields
 */
enum {
    TpmDataInstance = 0,
    TpmDataVersion = 0x11,
    TpmDataHdrSize = 0x20,
    TpmDataPtrOffset = 0x20,
    TpmDataPtrCnt = 3,
    TpmDataChildStrCnt = 0,
    TpmDataChildStrOffset = 0,
    TpmDataMinRqrdPcrdVersion = 0x1
};

/**
 * @brief Enumeration definition for the TPM states of existence
 */
enum TpmState {
    TpmPresentAndFunctional = 0x1,
    TpmPresentNonFunctional = 0x2,
    TpmNonPresent = 0x3,
};

/**
 * @brief Structure definition for HDAT Tpm Node Data Header
 */
struct hdatTpmData_t
{
    hdatHDIF_t hdatHdr;
    hdatHDIFDataHdr_t hdatSbTpmInfo; // Pointer pair to secure boot TPM info
    hdatHDIFDataHdr_t hdatPhysInter; // Physical interaction mechanism details
    hdatHDIFDataHdr_t hdatHashVerifyFunc; // Hash and Verification functions
    uint8_t hdatReserved1[8]; // Padding for alignment and growth/compatibility
} __attribute__ ((packed));

/**
 *  @brief Structure definition for Secureboot TPM Instance Info
 */
struct hdatSbTpmInstInfo_t
{
    uint32_t hdatChipId;
    uint32_t hdatDbobId; // Drawer/Book/Octant/Blade ID
    uint8_t hdatLocality1Addr;
    uint8_t hdatLocality2Addr;
    uint8_t hdatLocality3Addr;
    uint8_t hdatLocality4Addr;
    uint8_t hdatFunctionalStatus;
    uint8_t reserved[3];
    uint32_t hdatTpmSrtmEventLogOffset;
    uint32_t hdatTpmSrtmEventLogEntrySize;
    uint32_t hdatTpmDrtmEventLogOffset;
    uint32_t hdatTpmDrtmEventLogEntrySize;
} __attribute__ ((packed));

/**
 *  @brief Type used to specify I2C link IDs
 */
typedef uint32_t i2cLinkId_t;

/**
 *  @brief Special/sentinel i2cLinkId_t values
 */
enum I2C_LINK_ID : i2cLinkId_t
{
    NOT_APPLICABLE = 0xFFFFFFFF,
};

/**
 * @brief Structure definition for HDAT physical interaction mechanism info
 */
struct hdatPhysInterMechInfo_t
{
    // ID of I2C device in the PCRD that supports the "window open" function
    i2cLinkId_t i2cLinkIdWindowOpen;

    // ID of I2C device in the PCRD that supports the "physical presence"
    // function
    i2cLinkId_t i2cLinkIdPhysicalPresence;

} __attribute__ ((packed));

/**
 * @brief Structure definition for HDAT Hash and Verification Function instances
 */
struct hdatHashVerifyFunc_t
{
    sbFuncType_t sbFuncType; // Type of secureboot function
    sbFuncVer_t sbFuncVer; // Version of verify function
    uint32_t dbobId; // Drawer/Book/Octant/Blade ID
    uint32_t sbFuncOffset; // Offset of function within SecureROM
};

extern const char g_hdatTpmDataEyeCatch[];

/** Begin Class Description
 *
 * @brief  The HdatTpmData class is used to construct the Node TPM Related Data
 *         hypervisor data area.
 *
 * Description: This class defines a specialized object.  It is not intended
 *              that any component can create an object of this type.
 *              In particular, the object is built only by the hdat component.
 *
 *              The real purpose of the object is to create the Node TPM
 *              data structure as defined by the PHYP Initialization
 *              architecture.  This data structure is eventually copied to
 *              main memory.  The class is not defined to be a general purpose
 *              interface for building this object by anyone other than the
 *              hdat process.
 *
 * Thread safety:  An HdatTpmData object is not thread safe.  That is, a
 *                 single object cannot be shared and used concurrently by
 *                 multiple threads at the same time.  An object can be used by
 *                 multiple threads if the threads serialize access.  And of
 *                 course, each thread can use its own object with no concerns
 *                 about what other threads are doing.
 *
 * Signal handler usage: This class is not intended to be used in a signal
 *                        handler and nothing has been done to try and make
 *                        it safe to use in a signal handler.
 *
 * End Class Description
 */
class HdatTpmData
{
    public:
        /**
         * @brief Construct an HdatTpmData object.
         *
         *       This is the constructor for the HdatTpmData object.
         *
         *       After creating a new HdatTpmData object via new, you must
         *       check o_errlHndl to see if the constructor ran successfully.
         *       If o_errHndl indicates an error was reported by the
         *       constructor, then new has already allocated heap storage and
         *       the object must be deleted in order to free the heap storage.
         *
         * @pre None
         *
         * @post An HdatTpmData object has been constructed.
         *       Heap storage has been allocated.
         *
         * @param[out] o_errlHndl If any errors occur, the HdatTpmData object is
         *                                      NOT constructed and an error is
         *                                      returned in this parameter
         * @param[in] i_msAddr The main memory address that the service
         *                                      processor subsystem structure
         *                                      will be DMA'd to.
         */
        HdatTpmData(errlHndl_t &o_errlHndl, const HDAT::hdatMsAddr_t &i_msAddr);

        /**
         * @brief HdatTpmData object destructor
         *
         *        This is the destructor for an HdatTpmData object.
         *        Any heap storage allocated for the object is deallocated.
         *
         * @pre No preconditions exist
         *
         * @post The HdatTpmData object has been destroyed and can
         *       no longer be used.
         *
         */
        ~HdatTpmData();

         /**
          * @brief Load TPM Related Data to Mainstore
          *
          * @pre None
          *
          * @post None
          *
          * @param[out] o_size Size of TPM Data structure
          * @param[out] o_count Number of TPM Data structures
          *
          * @retval errlHndl_t nullptr on success, error log on error
          */
        errlHndl_t hdatLoadTpmData(uint32_t &o_size,uint32_t &o_count);

        // delete copy/move constructors and operators
        HdatTpmData(const HdatTpmData& ) = delete;
        HdatTpmData& operator=(const HdatTpmData& ) = delete;
        HdatTpmData(HdatTpmData&&) = delete;
        HdatTpmData& operator=(HdatTpmData&&) = delete;

    private:

        HDAT::hdatMsAddr_t     iv_msAddr;

        hdatTpmData_t *iv_hdatTpmData;

}; // end of HdatTpmData class

/**
 * @brief Calculate the maximum number of TPMs per node for this system.
 *
 * @pre None
 *
 * @post None
 *
 * @retval uint16_t Returns the maximum number of TPMs per node for this system
 */
uint16_t hdatCalcMaxTpmsPerNode();

/**
 * @brief Calculate the maximum size of the HDAT TPM data section
 *
 * @pre None
 *
 * @post None
 *
 * @retval uint32_t Maximum size of the HDAT TPM data section
 */
uint32_t hdatTpmDataCalcMaxSize();

}
#endif // HDATTPMDATA_H
<|endoftext|>