text:
/**
 * @file ompl_constrained_planner_tests.cpp
 * @brief This contains unit test ompl constrained planning
 *
 * @author Levi Armstrong
 * @date February 24, 2020
 * @version TODO
 * @bug No known bugs
 *
 * @copyright Copyright (c) 2020, Southwest Research Institute
 *
 * @par License
 * Software License Agreement (Apache License)
 * @par
 * 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
 * @par
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <tesseract_common/macros.h>
TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
#include <boost/filesystem/path.hpp>

#include <ompl/geometric/planners/sbl/SBL.h>
#include <ompl/geometric/planners/est/EST.h>
#include <ompl/geometric/planners/kpiece/LBKPIECE1.h>
#include <ompl/geometric/planners/kpiece/BKPIECE1.h>
#include <ompl/geometric/planners/kpiece/KPIECE1.h>
#include <ompl/geometric/planners/rrt/RRT.h>
#include <ompl/geometric/planners/rrt/RRTConnect.h>
#include <ompl/geometric/planners/rrt/RRTstar.h>
#include <ompl/geometric/planners/rrt/TRRT.h>
#include <ompl/geometric/planners/prm/PRM.h>
#include <ompl/geometric/planners/prm/PRMstar.h>
#include <ompl/geometric/planners/prm/LazyPRMstar.h>
#include <ompl/geometric/planners/prm/SPARS.h>

#include <ompl/util/RandomNumbers.h>

#include <functional>
#include <cmath>
#include <gtest/gtest.h>
TESSERACT_COMMON_IGNORE_WARNINGS_POP

#include <tesseract/tesseract.h>
#include <tesseract_environment/core/utils.h>
#include <tesseract_motion_planners/ompl/ompl_motion_planner.h>
#include <tesseract_motion_planners/ompl/ompl_planner_configurator.h>
#include <tesseract_motion_planners/ompl/config/ompl_planner_constrained_config.h>
#include <trajopt/problem_description.hpp>
#include <trajopt_utils/logging.hpp>

using namespace tesseract;
using namespace tesseract_scene_graph;
using namespace tesseract_collision;
using namespace tesseract_environment;
using namespace tesseract_geometry;
using namespace tesseract_kinematics;
using namespace tesseract_motion_planners;

const static int SEED = 1;
const static std::vector<double> start_state = { -0.5, 0.5, 0.0, -1.3348, 0.0, 1.4959, 0.0 };
const static std::vector<double> end_state = { 0.5, 0.5, 0.0, -1.3348, 0.0, 1.4959, 0.0 };

std::string locateResource(const std::string& url)
{
  std::string mod_url = url;
  if (url.find("package://tesseract_support") == 0)
  {
    mod_url.erase(0, strlen("package://tesseract_support"));
    size_t pos = mod_url.find('/');
    if (pos == std::string::npos)
    {
      return std::string();
    }

    std::string package = mod_url.substr(0, pos);
    mod_url.erase(0, pos);
    std::string package_path = std::string(TESSERACT_SUPPORT_DIR);

    if (package_path.empty())
    {
      return std::string();
    }

    mod_url = package_path + mod_url;
  }

  return mod_url;
}

class GlassUprightConstraint : public ompl::base::Constraint
{
public:
  GlassUprightConstraint(const Eigen::Vector3d& normal, tesseract_kinematics::ForwardKinematics::Ptr fwd_kin)
    : ompl::base::Constraint(fwd_kin->numJoints(), 1), normal_(normal.normalized()), fwd_kin_(std::move(fwd_kin))
  {
  }

  ~GlassUprightConstraint() override = default;

  void function(const Eigen::Ref<const Eigen::VectorXd>& x, Eigen::Ref<Eigen::VectorXd> out) const override
  {
    Eigen::Isometry3d pose;
    fwd_kin_->calcFwdKin(pose, x);

    Eigen::Vector3d z_axis = pose.matrix().col(2).template head<3>().normalized();

    out[0] = std::atan2(z_axis.cross(normal_).norm(), z_axis.dot(normal_));
  }

private:
  Eigen::Vector3d normal_;
  tesseract_kinematics::ForwardKinematics::Ptr fwd_kin_;
};

TEST(OMPLConstraintPlanner, OMPLConstraintPlannerUnit)  // NOLINT
{
  EXPECT_EQ(ompl::RNG::getSeed(), SEED) << "Randomization seed does not match expected: " << ompl::RNG::getSeed()
                                        << " vs. " << SEED;

  // Step 1: Load scene and srdf
  tesseract_scene_graph::ResourceLocator::Ptr locator =
      std::make_shared<tesseract_scene_graph::SimpleResourceLocator>(locateResource);
  Tesseract::Ptr tesseract = std::make_shared<Tesseract>();
  boost::filesystem::path urdf_path(std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.urdf");
  boost::filesystem::path srdf_path(std::string(TESSERACT_SUPPORT_DIR) + "/urdf/lbr_iiwa_14_r820.srdf");
  EXPECT_TRUE(tesseract->init(urdf_path, srdf_path, locator));

  // Step 3: Create ompl planner config and populate it
  auto kin = tesseract->getEnvironment()->getManipulatorManager()->getFwdKinematicSolver("manipulator");
  std::vector<double> swp = start_state;
  std::vector<double> ewp = end_state;

  Eigen::Vector3d normal = -1.0 * Eigen::Vector3d::UnitZ();
  tesseract_motion_planners::OMPLMotionPlanner ompl_planner;

  std::vector<tesseract_motion_planners::OMPLPlannerConfigurator::ConstPtr> planners;

  auto rrtconnect_planner = std::make_shared<tesseract_motion_planners::RRTConnectConfigurator>();
  planners.push_back(rrtconnect_planner);

  auto ompl_config =
      std::make_shared<tesseract_motion_planners::OMPLPlannerConstrainedConfig>(tesseract, "manipulator", planners);

  ompl_config->start_waypoint = std::make_shared<tesseract_motion_planners::JointWaypoint>(swp, kin->getJointNames());
  ompl_config->end_waypoint = std::make_shared<tesseract_motion_planners::JointWaypoint>(ewp, kin->getJointNames());
  ompl_config->collision_safety_margin = 0.02;
  ompl_config->planning_time = 400.0;
  ompl_config->max_solutions = 2;
  ompl_config->longest_valid_segment_fraction = 0.01;

  ompl_config->collision_continuous = true;
  ompl_config->collision_check = true;
  ompl_config->simplify = false;
  ompl_config->n_output_states = 50;
  ompl_config->constraint = std::make_shared<GlassUprightConstraint>(normal, kin);

  // Set the planner configuration
  ompl_planner.setConfiguration(ompl_config);

  tesseract_motion_planners::PlannerResponse ompl_planning_response;
  tesseract_common::StatusCode status = ompl_planner.solve(ompl_planning_response);

  if (!status)
  {
    CONSOLE_BRIDGE_logError("CI Error: %s", status.message().c_str());
  }
  EXPECT_TRUE(status);
  CONSOLE_BRIDGE_logInform("Number of states: %d", ompl_planning_response.joint_trajectory.trajectory.rows());

  EXPECT_TRUE(ompl_planning_response.joint_trajectory.trajectory.rows() > 2);

  long cnt = 0;
  double max_angle = 0;
  for (long r = 0; r < ompl_planning_response.joint_trajectory.trajectory.rows(); ++r)
  {
    Eigen::Isometry3d pose;
    kin->calcFwdKin(pose, ompl_planning_response.joint_trajectory.trajectory.row(r));

    Eigen::Vector3d z_axis = pose.matrix().col(2).template head<3>().normalized();

    double angle = std::abs(std::atan2(z_axis.cross(normal).norm(), z_axis.dot(normal)));

    if (angle > max_angle)
      max_angle = angle;

    if (angle > 0.2)
      ++cnt;
  }

  CONSOLE_BRIDGE_logWarn("CI Warn: Max error found: %f radians", max_angle);

  if (cnt != 0)
  {
    CONSOLE_BRIDGE_logError("CI Error: %d out of %d did not satisfy constraint",
                            cnt,
                            ompl_planning_response.joint_trajectory.trajectory.rows());
  }

  EXPECT_TRUE(cnt == 0);
}

int main(int argc, char** argv)
{
  testing::InitGoogleTest(&argc, argv);

  // Set the randomization seed for the planners to get repeatable results
  ompl::RNG::setSeed(SEED);

  return RUN_ALL_TESTS();
}


text:
//******************************************************************************
// RCF - Remote Call Framework
//
// Copyright (c) 2005 - 2013, Delta V Software. All rights reserved.
// http://www.deltavsoft.com
//
// RCF is distributed under dual licenses - closed source or GPL.
// Consult your particular license for conditions of use.
//
// If you have not purchased a commercial license, you are using RCF
// under GPL terms.
//
// Version: 2.0
// Contact: support <at> deltavsoft.com
//
//******************************************************************************

#ifndef INCLUDE_RCF_HTTPCONNECTFILTER_HPP
#define INCLUDE_RCF_HTTPCONNECTFILTER_HPP

#include <boost/shared_ptr.hpp>

#include <RCF/Filter.hpp>
#include <RCF/ByteBuffer.hpp>

namespace RCF {

    class HttpConnectFilter : public Filter
    {
    public:

        HttpConnectFilter();
        HttpConnectFilter(const std::string serverAddr, int serverPort);

        void resetState();

        void read(
            const ByteBuffer &byteBuffer,
            std::size_t bytesRequested);

        void write(const std::vector<ByteBuffer> &byteBuffers);

        void onReadCompleted(const ByteBuffer &byteBuffer);

        void onWriteCompleted(std::size_t bytesTransferred);

        int getFilterId() const;

    private:

        std::string mServerAddr;
        int mServerPort;

        bool mPassThrough;

        std::vector<ByteBuffer> mOrigWriteBuffers;

        std::string mHttpConnectRequest;
        std::string mHttpConnectResponse;

        std::size_t mWritePos;
        std::size_t mReadPos;

        std::vector<char> mReadVector;
    };

} // namespace RCF

#endif // ! INCLUDE_RCF_HTTPCONNECTFILTER_HPP

ext: hpp

max_stars_repo_name: ASMlover/study

max_issues_repo_name: ASMlover/study

max_forks_repo_name: ASMlover/study


text:
//////////////////////////////////////////////////////////////////////////////////////////////
/// \file ParseBA.hpp
/// \brief Parses a simple bundle adjustment problem (poses, landmarks and measurements)
///
/// \author Sean Anderson, ASRL
//////////////////////////////////////////////////////////////////////////////////////////////

#ifndef STEAM_PARSE_BUNDLE_ADJUSTMENT_HPP
#define STEAM_PARSE_BUNDLE_ADJUSTMENT_HPP

#include <stdio.h>
#include <iostream>

#include <Eigen/Core>
#include <lgmath.hpp>
#include <steam/evaluator/samples/StereoCameraErrorEval.hpp>

namespace steam {
namespace data {

//////////////////////////////////////////////////////////////////////////////////////////////
/// \brief Structure used to store the bundle adjustment dataset
//////////////////////////////////////////////////////////////////////////////////////////////
struct SimpleBaDataset {

  //////////////////////////////////////////////////////////////////////////////////////////////
  /// \brief Structure used to store a vehicle pose estimate
  //////////////////////////////////////////////////////////////////////////////////////////////
  struct Frame {
    unsigned int frameID;
    double time;
    Eigen::Matrix<double,6,1> pose_vec_k0;
    lgmath::se3::Transformation T_k0;
  };

  //////////////////////////////////////////////////////////////////////////////////////////////
  /// \brief Structure used to store a landmark estimate
  //////////////////////////////////////////////////////////////////////////////////////////////
  struct Landmark {
    unsigned int landID;
    Eigen::Matrix<double,3,1> point;
  };

  //////////////////////////////////////////////////////////////////////////////////////////////
  /// \brief Structure used to store camera intrinsics
  //////////////////////////////////////////////////////////////////////////////////////////////
  struct CameraIntrinsics {
    double b;
    double fu;
    double fv;
    double cu;
    double cv;
  };

  //////////////////////////////////////////////////////////////////////////////////////////////
  /// \brief Structure used to store a stereo camera measurement (with assoc. frame and land IDs)
  //////////////////////////////////////////////////////////////////////////////////////////////
  struct StereoMeas {
    unsigned int frameID;
    unsigned int landID;
    double time;
    Eigen::Matrix<double,4,1> data; // ul vl ur vr
  };

  std::vector<Frame> frames_gt;     // ground-truth poses
  std::vector<Landmark> land_gt;    // ground-truth landmarks
  std::vector<Frame> frames_ic;     // initial condition of poses
  std::vector<Landmark> land_ic;    // initial condition of landmarks
  lgmath::se3::Transformation T_cv; // extrinsic calibration between cam and vehicle: T_cam_vehicle
  CameraIntrinsics camParams;       // camera intrinsics
  Eigen::Matrix4d noise;            // 4x4 stereo measurement noise covariance
  std::vector<StereoMeas> meas;     // stereo measurements [ul vl ur vr]'
};

//////////////////////////////////////////////////////////////////////////////////////////////
/// \brief Function that parses a simple BA dataset
//////////////////////////////////////////////////////////////////////////////////////////////
SimpleBaDataset parseSimpleBaDataset(const std::string& file);

} // data
} // steam

#endif // STEAM_PARSE_BUNDLE_ADJUSTMENT_HPP

max_stars_repo_name: neophack/steam

max_issues_repo_name: neophack/steam

max_forks_repo_name: neophack/steam


text:
/*
 * Copyright 2021 Assured Information Security, Inc.
 *
 * 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.
 */
#pragma once

#include "core/domain/DomainImpl.hh"
#include "core/domain/VcpuImpl.hh"
#include "core/event/EventImpl.hh"
#include "core/injection/RegisterGuard.hh"
#include "windows/WindowsGuestImpl.hh"

#include <introvirt/core/breakpoint/Breakpoint.hh>
#include <introvirt/core/domain/Domain.hh>
#include <introvirt/core/domain/Vcpu.hh>
#include <introvirt/core/event/Event.hh>
#include <introvirt/core/exception/InvalidMethodException.hh>
#include <introvirt/core/exception/SystemCallInjectionException.hh>
#include <introvirt/core/exception/VirtualAddressNotPresentException.hh>
#include <introvirt/core/injection/system_call.hh>
#include <introvirt/fwd.hh>
#include <introvirt/windows/event/WindowsEvent.hh>
#include <introvirt/windows/kernel/nt/const/NTSTATUS.hh>
#include <introvirt/windows/kernel/nt/syscall/NtDeleteFile.hh>
#include <introvirt/windows/kernel/nt/types/TEB.hh>
#include <introvirt/windows/kernel/nt/types/objects/THREAD.hh>

#include <boost/algorithm/string.hpp>
#include <log4cxx/logger.h>

#include <cassert>
#include <cstdint>
#include <optional>

namespace introvirt {
namespace windows {
namespace inject {

extern thread_local std::optional<nt::NTSTATUS> LastStatusValueInject;

static log4cxx::LoggerPtr
    syscall_injector_logger(log4cxx::Logger::getLogger("introvirt.win.inject.SystemCallInjector"));

template <typename PtrType>
class SystemCallInjector final {
  public:
    /**
     * @brief Sleep the current thread until the system call returns
     */
    void call(WindowsSystemCall& handler) {
        auto& vcpu = static_cast<VcpuImpl&>(event_.vcpu());
        auto& regs = vcpu.registers();

        // Lock the thread affinity
        auto& thread = static_cast<WindowsEvent&>(event_).task().pcr().CurrentThread();
        const uint64_t desired_affinity = (1u << event_.vcpu().id());
        const auto original_affinity = thread.Affinity();
        const auto original_user_affinity = thread.UserAffinity();
        const auto original_ideal_processor = thread.IdealProcessor();
        const auto original_user_ideal_processor = thread.UserIdealProcessor();

        thread.Affinity(desired_affinity);
        thread.UserAffinity(desired_affinity);
        thread.IdealProcessor(event_.vcpu().id());
        thread.UserIdealProcessor(event_.vcpu().id());

        // Save the original LastStatusValue so we can restore it later
        auto* teb = thread.Teb();
        // TODO: What happens if Teb is null?

        nt::NTSTATUS original_laststatus;
        if (teb)
            original_laststatus = teb->LastStatusValue();

        static_cast<DomainImpl&>(event_.domain()).start_injection(event_);

        std::unique_ptr<Event> return_event;
        try {
            // Wait for the return event
            vcpu.syscall_injection_start();
            return_event = event_.impl().suspend([](const introvirt::Event& event) {
                if (event.type() == EventType::EVENT_FAST_SYSCALL_RET) {
                    return WakeAction::ACCEPT;
                }
                return WakeAction::PASS;
            });
            event_.impl().injection_performed(true);

        } catch (...) {
            // Duplicated because c++ doesn't have 'finally'
            vcpu.syscall_injection_end();
            static_cast<DomainImpl&>(event_.domain()).end_injection(event_);

            if (teb) {
                // Update the injection laststatus values
                LastStatusValueInject.emplace(teb->LastStatusValue());

                // Restore the original values
                teb->LastStatusValue(original_laststatus);
            }

            // Restore the thread affinity
            thread.Affinity(original_affinity);
            thread.UserAffinity(original_user_affinity);
            thread.IdealProcessor(original_ideal_processor);
            thread.UserIdealProcessor(original_user_ideal_processor);

            if (original_cs_) {
                LOG4CXX_DEBUG(syscall_injector_logger, "Restoring original CS");
                regs.cs(*original_cs_);
            }

            throw;
        }

        vcpu.syscall_injection_end();
        static_cast<DomainImpl&>(event_.domain()).end_injection(event_);

        if (teb) {
            // Update the injection laststatus values
            LastStatusValueInject.emplace(teb->LastStatusValue());

            // Restore the original values
            teb->LastStatusValue(original_laststatus);
        }

        // Restore the thread affinity
        thread.Affinity(original_affinity);
        thread.UserAffinity(original_user_affinity);
        thread.IdealProcessor(original_ideal_processor);
        thread.UserIdealProcessor(original_user_ideal_processor);

        if (original_cs_) {
            LOG4CXX_DEBUG(syscall_injector_logger, "Restoring original CS");
            regs.cs(*original_cs_);
        }

        handler.handle_return_event(*return_event);

        LOG4CXX_DEBUG(syscall_injector_logger, "System call completed");
    }

    uint64_t stack_pointer() const { return rsp_; }

    SystemCallInjector(Event& event, SystemCallIndex index, unsigned int argument_count,
                       unsigned int additional_stack)
        : event_(static_cast<WindowsEvent&>(event)), guest_(event_.guest()) {
        introvirt_assert(event.os_type() == OS::Windows, "");

        auto& vcpu = event_.vcpu();
        auto& regs = vcpu.registers();

        // Set the VCPU to the correct call number
        const uint32_t callNumber = guest_.syscalls().native(index);
        if (unlikely(callNumber == 0xFFFFFFFF)) {
            throw SystemCallInjectionException("Guest does not support " + to_string(index));
        }

        guard_.emplace(event.vcpu());

        regs.rax(callNumber);

        if constexpr (std::is_same_v<PtrType, uint64_t>) {
            // 64-Bit mode

            // Get the current code segment
            auto cs = regs.cs();
            if (!cs.long_mode()) {
                // Processor is in WoW64 (32-bit) mode, jump us back to 64-bit mode
                x86::SegmentSelector sel(0x33);
                x86::Segment seg(sel, 0x0, 0x0, 0xFB, true, 3, false, true, true, false, false);
                original_cs_.emplace(cs);
                regs.cs(seg);
            }

            begin_syscall(argument_count, additional_stack);
        } else {
            // 32-Bit mode
            begin_sysenter(argument_count, additional_stack);
        }

        LOG4CXX_DEBUG(syscall_injector_logger, "Preparing to inject " << index << " into ["
                                                                      << event.task().pid() << ':'
                                                                      << event.task().tid() << "]");
    }

  private:
    void verify_stack_present(uint64_t stack_bottom, uint64_t stack_top) {
        const PtrType first_page = stack_bottom & ~(0xFFFULL);
        const PtrType last_page = stack_top & ~(0xFFFULL);
        PtrType i = last_page;
        do {
            auto& vcpu = event_.vcpu();

            try {
                // Make sure the page is accessible
                guest_ptr<uint8_t> p(vcpu, i);
            } catch (VirtualAddressNotPresentException& ex) {
                LOG4CXX_DEBUG(syscall_injector_logger,
                              "Stack " << ex.virtual_address()
                                       << " not paged in while injecting system call, fixing...");

                // Try to do a hack where we get the kernel to page in the stack for us
                // The call to NtLoadDriver doesn't succeed. We just want it to read some memory.

                if constexpr (std::is_same_v<PtrType, uint32_t>) {
                    // On x64 we don't need any stack space to call NtDeleteFile.
                    // On x86 we need 12 bytes of stack to call NtDeleteFile.
                    // Return address, return stack, and the argument.
                    if (i == last_page || (stack_top & 0xFFF) < 12) {
                        // If we're on the top page, then we don't have ANY room.
                        // If we're not, and we still don't have 12 bytes available,
                        // we can't even inject this one-argument call.
                        // TODO: Something clever
                        throw;
                    }
                }

                auto result =
                    introvirt::inject::system_call<nt::NtDeleteFile>(guest_ptr<void>(vcpu, i));
                LOG4CXX_DEBUG(syscall_injector_logger,
                              "Paged in stack via NtDeleteFile hack: " << result);

                // Okay we should be paged in!
            }
            i -= 0x1000;
        } while (i >= first_page);
    }

    void begin_sysenter(unsigned int arg_count, unsigned int additional_stack) {
        auto& vcpu = event_.vcpu();
        auto& regs = vcpu.registers();
        uint64_t rip;

        /*
         * Inject a SYSENTER instruction.
         *
         * Before executing SYSENTER, Windows sets EDX to the current ESP value.
         * We need to make sure that the return address exists on at EDX.
         */

        // Move the stack backwards enough to hold our arguments plus the return address
        const unsigned int stack_offset = (arg_count + 2) * sizeof(uint32_t);

        switch (event_.type()) {
        case EventType::EVENT_FAST_SYSCALL:
            verify_stack_present(regs.rdx() - stack_offset - additional_stack, regs.rdx());
            break;
        case EventType::EVENT_FAST_SYSCALL_RET:
        case EventType::EVENT_EXCEPTION:
            verify_stack_present(regs.rsp() - stack_offset - additional_stack, regs.rsp());
            break;
        }

        // Force a SYSENTER in the guest
        // This works even if we're already in an EVENT_FAST_SYSCALL.
        // In KVM, since the RIP changes, it won't happen twice.
        // It will not work if the VCPU is already in the kernel, though!
        // For example, if we do this in a CR3 write event the guest will die.
        vcpu.inject_sysenter();

        switch (event_.type()) {
        case EventType::EVENT_FAST_SYSCALL:
            // SYSENTER has already been triggered
            // Get the original return address from the stack
            rip = *guest_ptr<uint32_t>(vcpu, regs.rdx());
            // Windows has moved the userland stack pointer to RDX, move it back to make some room
            regs.rdx(regs.rdx() - stack_offset);
            break;
        case EventType::EVENT_FAST_SYSCALL_RET:
        case EventType::EVENT_EXCEPTION:
            // Set up a SYSENTER frame
            rip = regs.rip(); // Save the userland instruction pointer, SYSENTER will change it
            regs.rdx(regs.rsp() - stack_offset); // In Windows rdx holds the userland stack pointer
            break;
        default:
            // TODO: Handle breakpoint/HAP events
            LOG4CXX_WARN(syscall_injector_logger, "Invalid event type in begin_sysenter()");
            throw InvalidMethodException(); // TODO: Proper exception
        }

        rsp_ = regs.rdx();

        // Write the return address on our new stack
        *guest_ptr<uint32_t>(vcpu, regs.rdx()) = rip;
    }

    void begin_syscall(unsigned int arg_count, unsigned int additional_stack) {
        /*
         * Inject a SYSCALL.
         *
         * SYSCALL saves the return address for in RCX, no need to save it anywhere.
         * All we have to do is lower the stack pointer enough for our arguments.
         *
         * Local variables will be placed below the arguments.
         */
        auto& regs = event_.vcpu().registers();

        // Make sure we're aligned
        regs.rsp(regs.rsp() & ~0x7LL);

        const uint64_t stack_bottom = regs.rsp() - (arg_count + 2) * sizeof(uint64_t);

        // Prevents a recursive loop with NtDeleteFile to page in the stack
        if (arg_count > 4 || additional_stack > 0)
            verify_stack_present(stack_bottom - additional_stack, regs.rsp());

        // This works even if we're already in an EVENT_FAST_SYSCALL.
        // In KVM, since the RIP changes, it won't happen twice.
        // It will not work if the VCPU is already in the kernel, though!
        // For example, if we do this in a CR3 write event the guest will die.
        event_.vcpu().inject_syscall();

        regs.rsp(stack_bottom);

        rsp_ = regs.rsp();
    }

  private:
    std::optional<introvirt::inject::RegisterGuard> guard_;
    WindowsEvent& event_;
    WindowsGuest& guest_;
    std::optional<x86::Segment> original_cs_;
    uint64_t rsp_;
};

} // namespace inject
} // namespace windows
} // namespace introvirt

ext: hh

max_stars_repo_name: IntroVirt/IntroVirt

max_issues_repo_name: IntroVirt/IntroVirt

max_forks_repo_name: IntroVirt/IntroVirt


text:
//  Copyright (c) 2007-2013 Hartmut Kaiser
//  Copyright (c) 2013-2015 Agustin Berge
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef HPX_LCOS_LOCAL_DETAIL_CONDITION_VARIABLE_HPP
#define HPX_LCOS_LOCAL_DETAIL_CONDITION_VARIABLE_HPP

#include <hpx/config.hpp>
#include <hpx/error_code.hpp>
#include <hpx/lcos/local/spinlock.hpp>
#include <hpx/runtime/threads/thread_data_fwd.hpp>
#include <hpx/runtime/threads/thread_enums.hpp>
#include <hpx/util/steady_clock.hpp>

#include <boost/intrusive/slist.hpp>

#include <cstddef>
#include <mutex>
#include <utility>

///////////////////////////////////////////////////////////////////////////////
namespace hpx { namespace lcos { namespace local { namespace detail
{
    class condition_variable
    {
    public:
        HPX_NON_COPYABLE(condition_variable);

    private:
        typedef lcos::local::spinlock mutex_type;

    private:
        // define data structures needed for intrusive slist container used for
        // the queues
        struct queue_entry
        {
            typedef boost::intrusive::slist_member_hook<
                boost::intrusive::link_mode<boost::intrusive::normal_link>
            > hook_type;

            queue_entry(threads::thread_id_type const& id, void* q)
              : id_(id), q_(q)
            {}

            threads::thread_id_type id_;
            void* q_;
            hook_type slist_hook_;
        };

        typedef boost::intrusive::member_hook<
            queue_entry, queue_entry::hook_type,
            &queue_entry::slist_hook_
        > slist_option_type;

        typedef boost::intrusive::slist<
            queue_entry, slist_option_type,
            boost::intrusive::cache_last<true>,
            boost::intrusive::constant_time_size<true>
        > queue_type;

        struct reset_queue_entry
        {
            reset_queue_entry(queue_entry& e, queue_type& q)
              : e_(e), last_(q.last())
            {}

            ~reset_queue_entry()
            {
                if (e_.id_ != threads::invalid_thread_id)
                {
                    queue_type* q = static_cast<queue_type*>(e_.q_);
                    q->erase(last_);     // remove entry from queue
                }
            }

            queue_entry& e_;
            queue_type::const_iterator last_;
        };

    public:
        HPX_EXPORT condition_variable();

        HPX_EXPORT ~condition_variable();

        HPX_EXPORT bool empty(
            std::unique_lock<mutex_type> const& lock) const;

        HPX_EXPORT std::size_t size(
            std::unique_lock<mutex_type> const& lock) const;

        // Return false if no more threads are waiting (returns true if queue
        // is non-empty).
        HPX_EXPORT bool notify_one(std::unique_lock<mutex_type> lock,
            threads::thread_priority priority, error_code& ec = throws);

        HPX_EXPORT void notify_all(std::unique_lock<mutex_type> lock,
            threads::thread_priority priority, error_code& ec = throws);

        bool notify_one(std::unique_lock<mutex_type> lock,
            error_code& ec = throws)
        {
            return notify_one(std::move(lock),
                threads::thread_priority_default, ec);
        }

        void notify_all(std::unique_lock<mutex_type> lock,
            error_code& ec = throws)
        {
            return notify_all(std::move(lock),
                threads::thread_priority_default, ec);
        }

        HPX_EXPORT void abort_all(
            std::unique_lock<mutex_type> lock);

        HPX_EXPORT threads::thread_state_ex_enum wait(
            std::unique_lock<mutex_type>& lock,
            char const* description, error_code& ec = throws);

        threads::thread_state_ex_enum wait(
            std::unique_lock<mutex_type>& lock,
            error_code& ec = throws)
        {
            return wait(lock, "condition_variable::wait", ec);
        }

        HPX_EXPORT threads::thread_state_ex_enum wait_until(
            std::unique_lock<mutex_type>& lock,
            util::steady_time_point const& abs_time,
            char const* description, error_code& ec = throws);

        threads::thread_state_ex_enum wait_until(
            std::unique_lock<mutex_type>& lock,
            util::steady_time_point const& abs_time,
            error_code& ec = throws)
        {
            return wait_until(lock, abs_time,
                "condition_variable::wait_until", ec);
        }

        threads::thread_state_ex_enum wait_for(
            std::unique_lock<mutex_type>& lock,
            util::steady_duration const& rel_time,
            char const* description, error_code& ec = throws)
        {
            return wait_until(lock, rel_time.from_now(), description, ec);
        }

        threads::thread_state_ex_enum wait_for(
            std::unique_lock<mutex_type>& lock,
            util::steady_duration const& rel_time,
            error_code& ec = throws)
        {
            return wait_until(lock, rel_time.from_now(),
                "condition_variable::wait_for", ec);
        }

    private:
        template <typename Mutex>
        void abort_all(std::unique_lock<Mutex> lock);

        // re-add the remaining items to the original queue
        HPX_EXPORT void prepend_entries(
            std::unique_lock<mutex_type>& lock, queue_type& queue);

    private:
        queue_type queue_;
    };

}}}}

#endif /*HPX_LCOS_LOCAL_DETAIL_CONDITION_VARIABLE_HPP*/

max_forks_repo_name: biddisco/hpx


text:
/*
 * Copyright (c) 2017, Respective Authors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <boost/test/unit_test.hpp>

#include <eos/chain/database.hpp>
#include <eos/chain/exceptions.hpp>
#include <eos/chain/account_object.hpp>

#include <eos/native_system_contract_plugin/native_system_contract_plugin.hpp>

#include <eos/utilities/tempdir.hpp>

#include <fc/crypto/digest.hpp>

#include "../common/database_fixture.hpp"

using namespace eos;
using namespace chain;

BOOST_AUTO_TEST_SUITE(block_tests)

// Simple test of block production and head_block_num tracking
BOOST_FIXTURE_TEST_CASE(produce_blocks, testing_fixture)
{ try {
      MKDB(db)

      BOOST_CHECK_EQUAL(db.head_block_num(), 0);
      db.produce_blocks();
      BOOST_CHECK_EQUAL(db.head_block_num(), 1);
      db.produce_blocks(5);
      BOOST_CHECK_EQUAL(db.head_block_num(), 6);
      db.produce_blocks(db.get_global_properties().active_producers.size());
      BOOST_CHECK_EQUAL(db.head_block_num(), db.get_global_properties().active_producers.size() + 6);
} FC_LOG_AND_RETHROW() }

// Simple test to verify a simple transfer transaction works
BOOST_FIXTURE_TEST_CASE(transfer, testing_fixture)
{ try {
      MKDB(db)

      BOOST_CHECK_EQUAL(db.head_block_num(), 0);
      db.produce_blocks(10);
      BOOST_CHECK_EQUAL(db.head_block_num(), 10);

      signed_transaction trx;
      BOOST_REQUIRE_THROW(db.push_transaction(trx), transaction_exception); // no messages
      trx.messages.resize(1);
      trx.set_reference_block(db.head_block_id());
      trx.set_expiration(db.head_block_time() + 100);
      trx.messages[0].sender = "init1";
      trx.messages[0].recipient = "sys";
      trx.messages[0].type = "Transfer";
      trx.messages[0].set("Transfer", Transfer{ "init2", 100, "memo" });
      BOOST_REQUIRE_THROW(db.push_transaction(trx), message_validate_exception); // "fail to notify receiver, init2"
      trx.messages[0].notify = {"init2"};
      trx.messages[0].set("Transfer", Transfer{ "init2", 100, "memo" });
      db.push_transaction(trx);

      BOOST_CHECK_EQUAL(db.get_account("init1").balance, 100000 - 100);
      BOOST_CHECK_EQUAL(db.get_account("init2").balance, 100000 + 100);
      db.produce_blocks(1);

      BOOST_REQUIRE_THROW(db.push_transaction(trx), transaction_exception); // not unique

} FC_LOG_AND_RETHROW() }

//Simple test of account creation
BOOST_FIXTURE_TEST_CASE(create_account, testing_fixture)
{ try {
      MKDB(db);
      db.produce_blocks(10);

      const auto& init1_account = db.get_account("init1");

      BOOST_CHECK_EQUAL(init1_account.balance, 100000);

      auto joe_private_key = fc::ecc::private_key::regenerate(fc::sha256::hash("joe"));
      public_key_type joe_public_key = joe_private_key.get_public_key();

      signed_transaction trx;
      trx.messages.resize(1);
      trx.set_reference_block(db.head_block_id());
      trx.set_expiration(db.head_block_time() + 100);
      trx.messages[0].sender = "init1";
      trx.messages[0].recipient = "sys";
      trx.messages[0].type = "CreateAccount";
      trx.messages[0].set("CreateAccount",
                          CreateAccount{"joe", {1, {}, {{joe_public_key, 1}}}, {1, {}, {{joe_public_key, 1}}}, 1000});
      db.push_transaction(trx);

      const auto& joe_account = db.get_account("joe");
      BOOST_CHECK_EQUAL(joe_account.balance, 1000);
      BOOST_CHECK_EQUAL(init1_account.balance, 100000 - 1000);

      const auto& joe_owner_authority = db.get<permission_object, by_owner>(boost::make_tuple(joe_account.id, "owner"));
      BOOST_CHECK_EQUAL(joe_owner_authority.auth.threshold, 1);
      BOOST_CHECK_EQUAL(joe_owner_authority.auth.accounts.size(), 0);
      BOOST_CHECK_EQUAL(joe_owner_authority.auth.keys.size(), 1);
      BOOST_CHECK_EQUAL(string(joe_owner_authority.auth.keys[0].key), string(joe_public_key));
      BOOST_CHECK_EQUAL(joe_owner_authority.auth.keys[0].weight, 1);

      const auto& joe_active_authority = db.get<permission_object, by_owner>(boost::make_tuple(joe_account.id, "active"));
      BOOST_CHECK_EQUAL(joe_active_authority.auth.threshold, 1);
      BOOST_CHECK_EQUAL(joe_active_authority.auth.accounts.size(), 0);
      BOOST_CHECK_EQUAL(joe_active_authority.auth.keys.size(), 1);
      BOOST_CHECK_EQUAL(string(joe_active_authority.auth.keys[0].key), string(joe_public_key));
      BOOST_CHECK_EQUAL(joe_active_authority.auth.keys[0].weight, 1);
} FC_LOG_AND_RETHROW() }

// Simple test of block production when a block is missed
BOOST_FIXTURE_TEST_CASE(missed_blocks, testing_fixture)
{ try {
      MKDB(db)

      db.produce_blocks();
      BOOST_CHECK_EQUAL(db.head_block_num(), 1);

      producer_id_type skipped_producers[3] = {db.get_scheduled_producer(1),
                                               db.get_scheduled_producer(2),
                                               db.get_scheduled_producer(3)};
      auto next_block_time = db.get_slot_time(4);
      auto next_producer = db.get_scheduled_producer(4);

      BOOST_CHECK_EQUAL(db.head_block_num(), 1);
      db.produce_blocks(1, 3);
      BOOST_CHECK_EQUAL(db.head_block_num(), 2);
      BOOST_CHECK_EQUAL(db.head_block_time().to_iso_string(), next_block_time.to_iso_string());
      BOOST_CHECK_EQUAL(db.head_block_producer()._id, next_producer._id);
      BOOST_CHECK_EQUAL(db.get(next_producer).total_missed, 0);

      for (auto producer : skipped_producers) {
         BOOST_CHECK_EQUAL(db.get(producer).total_missed, 1);
      }
} FC_LOG_AND_RETHROW() }

// Simple sanity test of test network: if databases aren't connected to the network, they don't sync to eachother
BOOST_FIXTURE_TEST_CASE(no_network, testing_fixture)
{ try {
      MKDBS((db1)(db2))

      BOOST_CHECK_EQUAL(db1.head_block_num(), 0);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 0);
      db1.produce_blocks();
      BOOST_CHECK_EQUAL(db1.head_block_num(), 1);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 0);
      db2.produce_blocks(5);
      BOOST_CHECK_EQUAL(db1.head_block_num(), 1);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 5);
} FC_LOG_AND_RETHROW() }

// Test that two databases on the same network do sync to eachother
BOOST_FIXTURE_TEST_CASE(simple_network, testing_fixture)
{ try {
      MKDBS((db1)(db2))
      MKNET(net, (db1)(db2))

      BOOST_CHECK_EQUAL(db1.head_block_num(), 0);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 0);
      db1.produce_blocks();
      BOOST_CHECK_EQUAL(db1.head_block_num(), 1);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 1);
      BOOST_CHECK_EQUAL(db1.head_block_id().str(), db2.head_block_id().str());
      db2.produce_blocks(5);
      BOOST_CHECK_EQUAL(db1.head_block_num(), 6);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 6);
      BOOST_CHECK_EQUAL(db1.head_block_id().str(), db2.head_block_id().str());
} FC_LOG_AND_RETHROW() }

// Test that two databases joining and leaving a network sync correctly after a fork
BOOST_FIXTURE_TEST_CASE(forked_network, testing_fixture)
{ try {
      MKDBS((db1)(db2))
      MKNET(net)

      BOOST_CHECK_EQUAL(db1.head_block_num(), 0);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 0);
      db1.produce_blocks();
      BOOST_CHECK_EQUAL(db1.head_block_num(), 1);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 0);
      BOOST_CHECK_NE(db1.head_block_id().str(), db2.head_block_id().str());

      net.connect_database(db1);
      net.connect_database(db2);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 1);
      BOOST_CHECK_EQUAL(db1.head_block_id().str(), db2.head_block_id().str());

      db2.produce_blocks(5);
      BOOST_CHECK_EQUAL(db1.head_block_num(), 6);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 6);
      BOOST_CHECK_EQUAL(db1.head_block_id().str(), db2.head_block_id().str());

      net.disconnect_database(db1);
      db1.produce_blocks(1, 1);
      db2.produce_blocks();
      BOOST_CHECK_EQUAL(db1.head_block_num(), 7);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 7);
      BOOST_CHECK_NE(db1.head_block_id().str(), db2.head_block_id().str());

      db2.produce_blocks(1, 1);
      net.connect_database(db1);
      BOOST_CHECK_EQUAL(db1.head_block_num(), 8);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 8);
      BOOST_CHECK_EQUAL(db1.head_block_id().str(), db2.head_block_id().str());
} FC_LOG_AND_RETHROW() }

// Check that the recent_slots_filled bitmap is being updated correctly
BOOST_FIXTURE_TEST_CASE( rsf_missed_blocks, testing_fixture )
{ try {
      MKDB(db)
      db.produce_blocks();

      auto rsf = [&]() -> string
      {
         auto rsf = db.get_dynamic_global_properties().recent_slots_filled;
         string result = "";
         result.reserve(64);
         for( int i=0; i<64; i++ )
         {
            result += ((rsf & 1) == 0) ? '0' : '1';
            rsf >>= 1;
         }
         return result;
      };

      auto pct = []( uint32_t x ) -> uint32_t
      {
         return uint64_t( config::Percent100 ) * x / 64;
      };

      BOOST_CHECK_EQUAL( rsf(),
         "1111111111111111111111111111111111111111111111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), config::Percent100 );

      db.produce_blocks(1, 1);
      BOOST_CHECK_EQUAL( rsf(),
         "0111111111111111111111111111111111111111111111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(127-64) );

      db.produce_blocks(1, 1);
      BOOST_CHECK_EQUAL( rsf(),
         "0101111111111111111111111111111111111111111111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(126-64) );

      db.produce_blocks(1, 2);
      BOOST_CHECK_EQUAL( rsf(),
         "0010101111111111111111111111111111111111111111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(124-64) );

      db.produce_blocks(1, 3);
      BOOST_CHECK_EQUAL( rsf(),
         "0001001010111111111111111111111111111111111111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(121-64) );

      db.produce_blocks(1, 5);
      BOOST_CHECK_EQUAL( rsf(),
         "0000010001001010111111111111111111111111111111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(116-64) );

      db.produce_blocks(1, 8);
      BOOST_CHECK_EQUAL( rsf(),
         "0000000010000010001001010111111111111111111111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(108-64) );

      db.produce_blocks(1, 13);
      BOOST_CHECK_EQUAL( rsf(),
         "0000000000000100000000100000100010010101111111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(95-64) );

      db.produce_blocks();
      BOOST_CHECK_EQUAL( rsf(),
         "1000000000000010000000010000010001001010111111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(95-64) );

      db.produce_blocks();
      BOOST_CHECK_EQUAL( rsf(),
         "1100000000000001000000001000001000100101011111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(95-64) );

      db.produce_blocks();
      BOOST_CHECK_EQUAL( rsf(),
         "1110000000000000100000000100000100010010101111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(95-64) );

      db.produce_blocks();
      BOOST_CHECK_EQUAL( rsf(),
         "1111000000000000010000000010000010001001010111111111111111111111"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(95-64) );

      db.produce_blocks(1, 64);
      BOOST_CHECK_EQUAL( rsf(),
         "0000000000000000000000000000000000000000000000000000000000000000"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(0) );

      db.produce_blocks(1, 63);
      BOOST_CHECK_EQUAL( rsf(),
         "0000000000000000000000000000000000000000000000000000000000000001"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(1) );

      db.produce_blocks(1, 32);
      BOOST_CHECK_EQUAL( rsf(),
         "0000000000000000000000000000000010000000000000000000000000000000"
      );
      BOOST_CHECK_EQUAL( db.producer_participation_rate(), pct(1) );
} FC_LOG_AND_RETHROW() }

// Check that a db rewinds to the LIB after being closed and reopened
BOOST_FIXTURE_TEST_CASE(restart_db, testing_fixture)
{ try {
      MKDB(db)

      auto lag = EOS_PERCENT(config::ProducerCount, config::IrreversibleThresholdPercent);
      db.produce_blocks(20);

      BOOST_CHECK_EQUAL(db.head_block_num(), 20);
      BOOST_CHECK_EQUAL(db.last_irreversible_block_num(), 20 - lag);

      db.close();
      db.open();

      // After restarting, we should have rewound to the last irreversible block.
      BOOST_CHECK_EQUAL(db.head_block_num(), 20 - lag);
      db.produce_blocks(5);
      BOOST_CHECK_EQUAL(db.head_block_num(), 25 - lag);
} FC_LOG_AND_RETHROW() }

// Check that a db which is closed and reopened successfully syncs back with the network, including retrieving blocks
// that it missed while it was down
BOOST_FIXTURE_TEST_CASE(sleepy_db, testing_fixture)
{ try {
      MKDB(producer)
      MKNET(net, (producer))

      auto lag = EOS_PERCENT(config::ProducerCount, config::IrreversibleThresholdPercent);
      producer.produce_blocks(20);

      {
         // The new node, sleepy, joins, syncs, disconnects
         MKDB(sleepy, sleepy)
         net.connect_database(sleepy);
         BOOST_CHECK_EQUAL(producer.head_block_num(), 20);
         BOOST_CHECK_EQUAL(sleepy.head_block_num(), 20);

         net.disconnect_database(sleepy);
         sleepy.close();
      }

      // 5 new blocks are produced
      producer.produce_blocks(5);
      BOOST_CHECK_EQUAL(producer.head_block_num(), 25);

      // Sleepy is reborn! Check that it is now rewound to the LIB...
      MKDB(sleepy, sleepy)
      BOOST_CHECK_EQUAL(sleepy.head_block_num(), 20 - lag);

      // Reconnect sleepy to the network and check that it syncs up to the present
      net.connect_database(sleepy);
      BOOST_CHECK_EQUAL(sleepy.head_block_num(), 25);
      BOOST_CHECK_EQUAL(sleepy.head_block_id().str(), producer.head_block_id().str());
} FC_LOG_AND_RETHROW() }

// Test reindexing the blockchain
BOOST_FIXTURE_TEST_CASE(reindex, testing_fixture)
{ try {
      MKDB(db)

      auto lag = EOS_PERCENT(config::ProducerCount, config::IrreversibleThresholdPercent);
      db.produce_blocks(100);

      BOOST_CHECK_EQUAL(db.last_irreversible_block_num(), 100 - lag);
      db.close();
      db.replay();
      BOOST_CHECK_EQUAL(db.head_block_num(), 100 - lag);
      db.produce_blocks(20);
      BOOST_CHECK_EQUAL(db.head_block_num(), 120 - lag);
} FC_LOG_AND_RETHROW() }

// Test wiping a database and resyncing with an ongoing network
BOOST_FIXTURE_TEST_CASE(wipe, testing_fixture)
{ try {
      MKDBS((db1)(db2)(db3))
      MKNET(net, (db1)(db2)(db3))

      db1.produce_blocks(3);
      db2.produce_blocks(3);
      BOOST_CHECK_EQUAL(db1.head_block_num(), 6);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 6);
      BOOST_CHECK_EQUAL(db3.head_block_num(), 6);
      BOOST_CHECK_EQUAL(db1.head_block_id().str(), db2.head_block_id().str());
      BOOST_CHECK_EQUAL(db1.head_block_id().str(), db3.head_block_id().str());

      net.disconnect_database(db3);
      db3.close();
      db3.wipe();
      db3.open();
      BOOST_CHECK_EQUAL(db3.head_block_num(), 0);

      net.connect_database(db3);
      BOOST_CHECK_EQUAL(db3.head_block_num(), 6);

      db1.produce_blocks(3);
      db2.produce_blocks(3);
      BOOST_CHECK_EQUAL(db1.head_block_num(), 12);
      BOOST_CHECK_EQUAL(db2.head_block_num(), 12);
      BOOST_CHECK_EQUAL(db3.head_block_num(), 12);
      BOOST_CHECK_EQUAL(db1.head_block_id().str(), db2.head_block_id().str());
      BOOST_CHECK_EQUAL(db1.head_block_id().str(), db3.head_block_id().str());
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_SUITE_END()

ext: cpp

max_stars_repo_name: eonproject/EONCore

max_issues_repo_name: eonproject/EONCore

max_forks_repo_name: eonproject/EONCore


text:
#ifndef  MEIGEN_HPP
#define  MEIGEN_HPP

#include <vector>
#include <Eigen/Core>
#include <Eigen/Geometry>  // Eigen 几何模块

/**
 * @brief 基于eigen的一些运算
 * @note
 */
namespace meigen {

//弧度转角度
template<typename T>
static T RadianToDegree( const T& radian ){
    return T( radian / EIGEN_PI * 180.0);
}

//角度转弧度
template<typename T>
static T DegreeToRadian(const T& degree ){
    return T( degree / 180.0 * EIGEN_PI);
}

/**
 * @brief   获取空间两向量夹角大小
 * @param  [in]  vecotor1   向量1
 * @param  [in]  vecotor2   向量2
 * @retval   angle 夹角角度
 * @note     返回值弧度0-PI,不能表示具体方向
 */
template<typename T>
static double_t GetAngleBetweenVec( const T& v1,
                                    const T& v2 ){
  //计算向量间內积
  double_t dot = v1.dot( v2 );
  //计算模
  double_t mould1 = v1.norm();
  double_t mould2 = v2.norm();
  //MLOGD("mould1: %lf mould2: %lf.", mould1, mould2 );
  //计算夹角弧度
  double radian = acos( dot / ( mould1 * mould2 ) );
  return radian;
}

//已知坐标变换，求变换坐标系下一点在原坐标系中的映射
//先平移，坐标系重合
//再加上当前坐标系下点映射
///参数:
///1.原坐标系到当前坐标系旋转 Q
///2.原坐标系到当前坐标系平移 T
///3.目标点在当前坐标系下坐标
inline Eigen::Vector3d pointToOriginCoordinate( const Eigen::Quaterniond& Q,
                                                const Eigen::Vector3d& T,
                                                const Eigen::Vector3d& inP ){
  Eigen::Vector3d outP;
  //平移操作
  outP.x() = T.x();
  outP.y() = T.y();
  outP.z() = T.z();
  //旋转操作求映射
  Eigen::Quaterniond qTPCAM= Q;
  Eigen::Quaterniond pqTurn;  //( w,x,y,z)
  Eigen::Quaterniond pqOrigin( 0, inP.x(), inP.y(), inP.z() );  //( w,x,y,z)

  pqTurn  = qTPCAM.inverse() * pqOrigin * qTPCAM;

  outP.x() += pqTurn.x();
  outP.y() += pqTurn.y();
  outP.z() += pqTurn.z();
  return  outP;
}

//已知坐标变换，求变换坐标系下的点在新坐标系中的映射
//先平移，坐标系重合
//再加上当前坐标系下点映射
///参数:
///1.新坐标系旋转相对当前坐标系旋转 Q
///2.新坐标系平移相对当前坐标系平移 T
///3.目标点在当前坐标系下坐标
static Eigen::Vector3d PointToNewCoordinate( const Eigen::Quaterniond& Q,
                                             const Eigen::Vector3d& T,
                                             const Eigen::Vector3d& inP ){
  Eigen::Vector3d outP;
  //平移操作
  outP.x() -= T.x();
  outP.y() -= T.y();
  outP.z() -= T.z();

  //旋转操作求映射
  Eigen::Quaterniond qTPCAM= Q;
  Eigen::Quaterniond pqTurn;  //( w,x,y,z)
  Eigen::Quaterniond pqOrigin( 0, inP.x(), inP.y(), inP.z() );  //( w,x,y,z)

  pqTurn  = qTPCAM * pqOrigin * qTPCAM.inverse();

  outP.x() += pqTurn.x();
  outP.y() += pqTurn.y();
  outP.z() += pqTurn.z();
  return  outP;
}

///四元素转旋转向量
static Eigen::AngleAxisd QuaterniondToAngleAxisd( const Eigen::Quaterniond& q ) {
  Eigen::AngleAxisd rotation_vector( q );
  return rotation_vector;
}

//RotationRollPitchYaw To Quaterniond
//存储顺序为 ypr[ 0 ] = 绕Z ypr[1] = 绕Y ypr[2]  = 绕X
//note: Rotation ypr equal to Euler ZYX
//ypr --- y * p * r  : left take
static Eigen::Quaterniond RotationYPRToQuaterniond( const double yaw, const double pitch, const double roll ) {
  Eigen::Quaterniond q;
  Eigen::Matrix3d R;
  R   =   Eigen::AngleAxisd( yaw, Eigen::Vector3d::UnitZ())
      * Eigen::AngleAxisd( pitch, Eigen::Vector3d::UnitY())
      * Eigen::AngleAxisd( roll, Eigen::Vector3d::UnitX());
  q = R;
  return q;
}

static Eigen::Quaterniond RotationYPRToQuaterniond( const Eigen::Vector3d& ypr ) {
  Eigen::Quaterniond q;
  Eigen::Matrix3d R;
  R   =   Eigen::AngleAxisd( ypr[0], Eigen::Vector3d::UnitZ())
      * Eigen::AngleAxisd( ypr[1], Eigen::Vector3d::UnitY())
      * Eigen::AngleAxisd( ypr[2], Eigen::Vector3d::UnitX());
  q = R;
  return q;
}

////ypr-ZYX
static Eigen::Matrix3d RotationYPRToRotationMatrix( const double yaw, const double pitch, const double roll ){

  Eigen::AngleAxisd yawAngle( Eigen::AngleAxisd( yaw ,Eigen::Vector3d::UnitZ() ) );
  Eigen::AngleAxisd pitchAngle( Eigen::AngleAxisd( pitch ,Eigen::Vector3d::UnitY() ) );
  Eigen::AngleAxisd rollAngle( Eigen::AngleAxisd( roll , Eigen::Vector3d::UnitX()));

  Eigen::Matrix3d rotation_matrix;
  rotation_matrix = yawAngle * pitchAngle * rollAngle;
  return rotation_matrix;

}

/**
 * @brief   Quaterniond To Rotation YPR
 * @param  [in]  Eigen Quaterniond
 * @retval      Rotation ypr Vector3d 按照(Y,P,R)( Z, Y, X ) 方式存储
 *              返回的值范围[ 0 -- +Pi ] [ -Pi -- +Pi ] [ -Pi -- +Pi ]（ 四元素归一化问题导致 ），不适合用来提取航向角
 * @note        Rotation ypr Vector3d 按照(Y,P,R)( Z, Y, X ) 方式存储,即ypr[0]=yaw ypr[1]=pitch ypr[2]=roll
 */
static Eigen::Vector3d QuaterniondToRotationYPR( const Eigen::Quaterniond& q ) {
  Eigen::Matrix3d rotation_matrix = q.toRotationMatrix();
  Eigen::Vector3d ypr = rotation_matrix.eulerAngles(2,1,0);
  return ypr;
}

/**
 * @brief   Quaterniond To Rotation YPR
 * @param  [in]  Eigen Quaterniond
 * @retval      Rotation ypr Vector3d 按照(Y,P,R)( Z, Y, X ) 方式存储
 *              返回的值范围[ -Pi -- +Pi ] [ -Pi/2 -- +Pi/2 ] [ -Pi -- +Pi ]，适合用来提取航向角
 * @note        Rotation ypr Vector3d 按照(Y,P,R)( Z, Y, X ) 方式存储,即ypr[0]=yaw ypr[1]=pitch ypr[2]=roll
 */
static Eigen::Vector3d QuaterniondToRotationYPR_Y( const Eigen::Quaterniond& q ) {

  Eigen::Vector3d ans;
  //double q2sqr = data.q2 * data.q2;
  double q2sqr = q.y() * q.y();

  double t0 = -2.0 * (q2sqr + q.z() * q.z() ) + 1.0;

  double t1 = +2.0 * (q.x() * q.y() + q.w() * q.z() );
  double t2 = -2.0 * (q.x() * q.z() - q.w() * q.y() );
  double t3 = +2.0 * (q.y() * q.z() + q.w() * q.x() );
  double t4 = -2.0 * (q.x() * q.x() + q2sqr ) + 1.0;

  t2 = t2 > 1.0 ? 1.0 : t2;
  t2 = t2 < -1.0 ? -1.0 : t2;

  ans[ 0 ] = atan2(t1, t0);   ///yaw
  ans[ 1 ] = asin(t2);        ///pitch
  ans[ 2 ] = atan2(t3, t4);   ///roll

  return ans;
}

static Eigen::Quaterniond RotationYPRToQuaterniond_Y( const Eigen::Vector3d &ypr ) {

  Eigen::Quaterniond q;

  double yaw = ypr[ 0 ];
  double pitch = ypr[ 1 ];
  double roll = ypr[ 2 ];

  double t0 = cos( yaw * 0.5);
  double t1 = sin( yaw * 0.5);
  double t2 = cos( roll * 0.5);
  double t3 = sin( roll * 0.5);
  double t4 = cos( pitch * 0.5);
  double t5 = sin( pitch * 0.5);

  q.w() = t2 * t4 * t0 + t3 * t5 * t1;
  q.x() = t3 * t4 * t0 - t2 * t5 * t1;
  q.y() = t2 * t5 * t0 + t3 * t4 * t1;
  q.z() = t2 * t4 * t1 - t3 * t5 * t0;
  return q;

}

/**
 * @brief   已知某坐标系B在到坐标系A的旋转变换Q,以及点a在A中的值[in]输出点a在B中的值[out]
 * @param  [in]   in    源坐标
 * @param  [in]   q     q为B坐标系到A坐标系中的旋转变换
 * @retval        out   点a在B中的值
 * @note    注意输入q代表R(B/A)是B到Ａ的旋转变换
 *          这里求的是新坐标系下点坐标,而不是在原坐标系下旋转得到的坐标（应该叫仿射射变换Affine）
 */
static Eigen::Vector3d  Vector3dTransformByQuaterniond( const Eigen::Vector3d& in, const Eigen::Quaterniond& q ){
  Eigen::Quaterniond qIn( 0, in.x() , in.y(), in.z() );  //( w,x,y,z)
  Eigen::Quaterniond qTurn;
  qTurn  = q * qIn * q.inverse();
  Eigen::Vector3d out;
  out.x() = qTurn.x();
  out.y() = qTurn.y();
  out.z() = qTurn.z();
  return out;
}

/*
 * @brief:   将坐标系中的两点组成的向量p1-p0设为新坐标系的X轴，
 *           求当前坐标系到新坐标系的旋转矩阵
 * @param  [in]  p0   已知点0
 * @param  [in]  p1   已知点1
 * @param  [out]
 * @retval       rotation quaternion
 * @note
 **/
static Eigen::Quaterniond GetRotationBySetTwoPointsAsXaxis( const Eigen::Vector3d& p0, const Eigen::Vector3d& p1 ){
  Eigen::Vector3d v = p1 - p0;
  return Eigen::Quaterniond::FromTwoVectors( Eigen::Vector3d(1,0,0), v );
}

//将四元数绕v轴旋转p度,相对世界坐标系
static Eigen::Quaterniond QuaterniondAxisRotateWorld( const Eigen::Quaterniond& q, const Eigen::Vector3d& v , const double& p ) {
  Eigen::AngleAxisd rotation_vector ( p, v);
  Eigen::Quaterniond q_r = Eigen::Quaterniond ( rotation_vector );
  Eigen::Quaterniond n_q;
  n_q = q_r * q; //左乘绕世界坐标旋转，右乘绕自身,这里是左乘
  return n_q;
}
//求一组向量的均值
static Eigen::Vector3d GetVetors3dMean( const std::vector<Eigen::Vector3d>& vectors ){
  if( vectors.empty() ){
      return Eigen::Vector3d(0,0,0);
    }
  Eigen::Vector3d sum_v(0,0,0);
  Eigen::Vector3d mean_v;
  for( auto it = vectors.begin(); it < vectors.end() ; it++ ) {
      sum_v += *it;
    }
  mean_v = sum_v / vectors.size();
  return  mean_v;
}

//求一组向量的方差
static Eigen::Vector3d GetVetors3dVariance( const std::vector<Eigen::Vector3d>& vectors ){
  Eigen::Vector3d s;
  Eigen::Vector3d mean_v = GetVetors3dMean( vectors );
  Eigen::Vector3d sum_var(0, 0, 0);
  for( auto it = vectors.begin(); it < vectors.end() ; it++ ) {
      sum_var.x() += std::pow( ( it->x() - mean_v.x() ), 2 );
      sum_var.y() += std::pow( ( it->y() - mean_v.y() ), 2 );
      sum_var.z() += std::pow( ( it->z() - mean_v.z() ), 2 );
    }
  s = sum_var / ( vectors.size() - 1 );  //无偏估计
  return  s;
}
//求一组向量的标准差
static Eigen::Vector3d GetVetors3dStandardDeviation( const std::vector<Eigen::Vector3d>& vectors ){
  Eigen::Vector3d s;
  Eigen::Vector3d sd;
  s = GetVetors3dVariance( vectors );
  sd.x() = std::sqrt( s.x() );
  sd.y() = std::sqrt( s.y() );
  sd.z() = std::sqrt( s.z() );
  return  sd;
}

}///end of namespace meigen

#endif  ///end of MEIGEN_HPP

#if 0
void test_meigen( void ){
  using std::cout;
  using std::endl;

  Eigen::Vector3d v1(1,0,0);    //原始坐标系下点

  MLOGI("v1: (%f %f %f )", v1.x(), v1.y(), v1.z() );

  ///旋转向量
  Eigen::AngleAxisd rotation_vector( M_PI/4, Eigen::Vector3d ( 0,0,1 ) );     //沿 Z 轴旋转 45 度
  //Eigen::Matrix3d  R( rotation_vector );    //旋转矩阵
  Eigen::Vector3d  v1_r = rotation_vector.matrix()*v1;
  MLOGI("将v1绕Z轴旋转45度后,v1_r:");
  cout << v1_r << endl;

  ///四元素
  Eigen::Vector3d ypr0( M_PI / 4 , 0 , 0 );
  Eigen::Vector3d ypr1( M_PI / 4 , 0 , 0 );
  Eigen::Quaterniond q0,q1;
  q0 = meigen::RotationYPRToQuaterniond( ypr0 );
  q1 = meigen::RotationYPRToQuaterniond( ypr1 );
  Eigen::Quaterniond mq = q1 * q0;     //连续两次旋转，左乘
  Eigen::Matrix3d  R = mq.matrix();    //旋转矩阵

  Eigen::Vector3d v2 = meigen::Vector3dTransformByQuaterniond( v1, mq.inverse() );
  //Eigen::Vector3d v2 = R.inverse() * v1;
  MLOGI("v2:");
  cout << v2 << endl;
  Eigen::Vector3d v2_back = meigen::Vector3dTransformByQuaterniond( v2, mq );
  MLOGI("v2 back:");
  cout << v2_back << endl;

  ///两向量求旋转
  Eigen::Vector3d  vector_00(-1,-1, 0);
  Eigen::Quaterniond two_vector_q = Eigen::Quaterniond::FromTwoVectors( Eigen::Vector3d(1,0,0), vector_00 );
  Eigen::Vector3d two_vector_q_ypr = meigen::QuaterniondToRotationYPR_Y( two_vector_q );
  two_vector_q_ypr = meigen::RadianToDegree<Eigen::Vector3d>( two_vector_q_ypr );
  MLOGI("two vector rotation ypr: (%f %f %f)", two_vector_q_ypr[0],two_vector_q_ypr[1], two_vector_q_ypr[2] );

  MLOGI("");
  ///设置两点为X轴，求旋转
  MLOGI("3.Set two points as Xaxis:");
  //Eigen::Vector3d p0(0,1,0);
  //Eigen::Vector3d p1(1,0,0);
  Eigen::Vector3d p0(106.908,104.844,0);
  Eigen::Vector3d p1(99.563,104.818,0);
  Eigen::Quaterniond two_points_as_xaxis_rotation = meigen::GetRotationBySetTwoPointsAsXaxis( p0, p1 );
  Eigen::Vector3d two_points_rotation_ypr = meigen::QuaterniondToRotationYPR_Y( two_points_as_xaxis_rotation );
  two_points_rotation_ypr = meigen::RadianToDegree<Eigen::Vector3d>( two_points_rotation_ypr );
  MLOGI("two points rotation ypr: (%f %f %f)", two_points_rotation_ypr[0],
      two_points_rotation_ypr[1], two_points_rotation_ypr[2] );

  Eigen::Vector3d p0_after = meigen::Vector3dTransformByQuaterniond( p0, two_points_as_xaxis_rotation.inverse() );
  Eigen::Vector3d p1_after = meigen::Vector3dTransformByQuaterniond( p1, two_points_as_xaxis_rotation.inverse() );
  MLOGI("p0_after(%f %f %f )", p0_after.x(),p0_after.y(),p0_after.z());
  MLOGI("p1_after(%f %f %f )", p1_after.x(),p1_after.y(),p1_after.z());

}
#endif

max_stars_repo_name: deakinYellow/utility-math

max_issues_repo_name: deakinYellow/utility-math

max_forks_repo_name: deakinYellow/utility-math


text:
// [===========================================================================]
// [                                M o n e t a                                ]
// [---------------------------------------------------------------------------]
// [                                                                           ]
// [                          Copyright (C) 2005-2015                          ]
// [                      Rodrigo Madera <madera@acm.org>                      ]
// [                                                                           ]
// [---------------------------------------------------------------------------]
// [         Distributed under the Boost Software License, Version 1.0         ]
// [ Read accompanying LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt ]
// [===========================================================================]

#include "pch.hxx"
#include <moneta/codec/_aux/io/read_string.hxx>
#include <boost/iterator/filter_iterator.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>

using namespace moneta::codec;

BOOST_AUTO_TEST_CASE(test_codec_io_read_string_basic) {
	const char str[] = "The\0quick\0brown\0fox";
	char buffer[128];

	const char* itr = boost::begin(str);
	int result;

	result = io::read(itr, boost::end(str), boost::begin(buffer), boost::end(buffer));
	BOOST_CHECK_EQUAL(result, 3); // "The"
	BOOST_CHECK_EQUAL(buffer, "The");
	itr += result + 1;

	result = io::read(itr, boost::end(str), boost::begin(buffer), boost::end(buffer));
	BOOST_CHECK_EQUAL(result, 5); // "quick"
	BOOST_CHECK_EQUAL(buffer, "quick");
	itr += result + 1;

	result = io::read(itr, boost::end(str), boost::begin(buffer), boost::end(buffer));
	BOOST_CHECK_EQUAL(result, 5); // "brown"
	BOOST_CHECK_EQUAL(buffer, "brown");
	itr += result + 1;

	result = io::read(itr, boost::end(str), boost::begin(buffer), boost::end(buffer));
	BOOST_CHECK_EQUAL(result, 3); // "fox"
	BOOST_CHECK_EQUAL(buffer, "fox");
}

BOOST_AUTO_TEST_CASE(test_codec_io_read_string_scarce_output) {
	const char str[] = "The\0quick\0brown\0fox";

	{
		const char* itr = boost::begin(str);
		int result;

		char* b0 = 0;
		result = io::read(itr, boost::end(str), b0, b0);
		BOOST_CHECK_EQUAL(result, 0);
	}

	{
		const char* itr = boost::begin(str);
		int result;

		char b1[1];
		result = io::read(itr, boost::end(str), boost::begin(b1), boost::end(b1));
		BOOST_CHECK_EQUAL(result, 1);
		BOOST_CHECK_EQUAL(b1[0], 'T');
	}

	{
		const char* itr = boost::begin(str);
		int result;

		char b2[2];
		result = io::read(itr, boost::end(str), boost::begin(b2), boost::end(b2));
		BOOST_CHECK_EQUAL(result, 2);
		BOOST_CHECK_EQUAL(b2[0], 'T');
		BOOST_CHECK_EQUAL(b2[1], 'h');
	}

	{
		const char* itr = boost::begin(str);
		int result;

		char b3[3];
		result = io::read(itr, boost::end(str), boost::begin(b3), boost::end(b3));
		BOOST_CHECK_EQUAL(result, 3);
		BOOST_CHECK_EQUAL(b3[0], 'T');
		BOOST_CHECK_EQUAL(b3[1], 'h');
		BOOST_CHECK_EQUAL(b3[2], 'e');
	}
}

BOOST_AUTO_TEST_CASE(test_codec_io_read_string_no_null) {
	const char str[] = "The\0quick\0brown\0fox";
	char buffer[7] = "XXXXXX";

	const char* itr = boost::begin(str);
	int result;

	result = io::read(itr, boost::end(str), boost::begin(buffer), boost::end(buffer), false);
	BOOST_CHECK_EQUAL(result, 3); // "The"
	BOOST_CHECK_EQUAL(buffer, "TheXXX");
	itr += result + 1;

	result = io::read(itr, boost::end(str), boost::begin(buffer), boost::end(buffer), false);
	BOOST_CHECK_EQUAL(result, 5); // "quick"
	BOOST_CHECK_EQUAL(buffer, "quickX");
	itr += result + 1;

	result = io::read(itr, boost::end(str), boost::begin(buffer), boost::end(buffer), false);
	BOOST_CHECK_EQUAL(result, 5); // "brown"
	BOOST_CHECK_EQUAL(buffer, "brownX");
	itr += result + 1;

	result = io::read(itr, boost::end(str), boost::begin(buffer), boost::end(buffer), false);
	BOOST_CHECK_EQUAL(result, 3); // "fox"
	BOOST_CHECK_EQUAL(buffer, "foxwnX");
}

ext: cxx

max_stars_repo_name: madera/Moneta

max_issues_repo_name: madera/Moneta

max_forks_repo_name: madera/Moneta


text:
#define BOOST_TEST_MODULE TEST_MODEL_JSON
#include <boost/test/unit_test.hpp>
#include "libs/csv_parser/csv_parser.h"
#include <sstream>

BOOST_AUTO_TEST_CASE(test_basic_input)
{
    std::istringstream invalid;
    csv::parser::source_type src{invalid};
    try {
        csv::parser p;
        BOOST_TEST(p.good(), "initial state is good");
        auto i = p.process(src);
        BOOST_TEST(i == 0, "this should not produce anything");
        BOOST_TEST(p.eof(), "we don't have any more data to process");
        std::string t = p.get_token() ;
        BOOST_TEST(t.empty(), "we should not have data in the token");
    } catch (const std::exception& ){
    } catch (...) {
        BOOST_TEST(false, "unknown exception thrown, we expecting some standard exception");
    }
}


text:
#include <limits>
#include <random>

#include <complex>

#include <armadillo>
#include <highfive/H5File.hpp>

#include "common.hpp"
#include "interface.hpp"

using namespace HighFive;

// This contraption has been modified from
// https://stackoverflow.com/a/25200473 to only extract the first-level inner
// type.  This was done to cover the cases of Armadillo and libaview
// containers that may hold std::complex<T>, so that T is not mistakenly
// extracted.  We need this because both HDF5 and HighFive (understandably)
// treat std::complex<T> as a compound datatype.
//
// TODO to be bulletproof, it should go to the innermost type unless
// std::complex is found, in which case it should stop.  The current
// implementation will break with something like std::vector<std::vector<T>>.

template<typename T>
struct inner_type_impl
{
    using type = T;
};

template<template<typename> class E, typename T>
struct inner_type_impl<E<T>>
{
    // using type = typename inner_type_impl<T>::type;
    using type = T;
};

template<typename T>
using inner_type = typename inner_type_impl<T>::type;

template <typename T>
DataType get_dtype(const T &val) {
    return create_and_check_datatype<inner_type<decltype(static_cast<T>(const_cast<T&>(val)))>>();
}

// std::ostream &operator<<(std::ostream &os, const HighFive::DataType &dt);

std::ostream& operator<<(std::ostream &os, const DataTypeClass &dtc) {
    os << type_class_string(dtc);
    return os;
}

std::ostream& operator<<(std::ostream &os, const DataType &dt) {
    os << dt.string();
    return os;
}

static std::vector<int> generate_data(size_t size) {
    using value_type = int;
    // We use static in order to instantiate the random engine
    // and the distribution once only.
    // It may provoke some thread-safety issues.
    static std::uniform_int_distribution<value_type> distribution(
        std::numeric_limits<value_type>::min(),
        std::numeric_limits<value_type>::max());
    static std::default_random_engine generator;

    std::vector<value_type> data(size);
    std::generate(data.begin(), data.end(), []() { return distribution(generator); });
    return data;
}

int main() {
    const std::string filename("stl.h5");
    File file(filename, File::ReadWrite | File::Create | File::Truncate);

    std::vector<int> v10 = generate_data(10);
    std::vector<int> v20 = generate_data(20);
    std::vector<int> v30 = generate_data(30);
    std::cout << "v10" << std::endl;
    std::cout << v10 << std::endl;
    std::cout << "v20" << std::endl;
    std::cout << v20 << std::endl;
    std::cout << "v30" << std::endl;
    std::cout << v30 << std::endl;

    DataSet dset_0 = file.createDataSet("v0", v20);

    std::string attr_0_contents("v20");
    Attribute attr_0 = dset_0.createAttribute<std::string>("contents", DataSpace::From(attr_0_contents));
    attr_0.write(attr_0_contents);

    DataSet dset_1 = file.createDataSet("v1", v20);
    dset_1.write(v10);

    std::string attr_1_contents("v10");
    Attribute attr_1 = dset_1.createAttribute<std::string>("contents", DataSpace::From(attr_1_contents));
    attr_1.write(attr_1_contents);

    DataSet dset_2 = file.createDataSet("v2", v20);
    dset_2.write(v30);

    std::string attr_2_contents("v30");
    Attribute attr_2 = dset_2.createAttribute<std::string>("contents", DataSpace::From(attr_2_contents));
    attr_2.write(attr_2_contents);

    // DataSet dset_0_unlimited = file.createDataSet<int>("v0_unlimited", DataSpace(DataSpace::UNLIMITED));

    Interface iface(filename);

    iface.write("v0_iface", v20);

    const size_t dim = 5;
    arma::Col<double> a0(dim, arma::fill::randn);
    arma::Col<double> a1(dim, arma::fill::randn);
    arma::Col<std::complex<double>> ac01(a0, a1);
    std::vector<double> v0 = arma::conv_to<std::vector<double>>::from(a0);
    std::vector<std::complex<double>> vc01 = arma::conv_to<std::vector<std::complex<double>>>::from(ac01);
    a0.print("a0");
    a1.print("a1");
    ac01.print("ac01");

    const auto dt_int = get_dtype(v20);
    std::cout << "dt_int:  " << dt_int << std::endl;
    const auto dt_double = get_dtype(v0);
    std::cout << "dt_double:  " << dt_double << std::endl;
    const auto dt_cxdouble = get_dtype(vc01);
    std::cout << "dt_cxdouble:  " << dt_cxdouble << std::endl;

    return 0;
}

max_stars_repo_name: berquist/eg

max_issues_repo_name: berquist/eg

max_forks_repo_name: berquist/eg


text:
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/StdVector>
#include <Eigen/Geometry>

template<typename MatrixType>
void check_stdvector_matrix(const MatrixType& m)
{
  typename MatrixType::Index rows = m.rows();
  typename MatrixType::Index cols = m.cols();
  MatrixType x = MatrixType::Random(rows,cols), y = MatrixType::Random(rows,cols);
  std::vector<MatrixType,Eigen::aligned_allocator<MatrixType> > v(10, MatrixType(rows,cols)), w(20, y);
  v[5] = x;
  w[6] = v[5];
  VERIFY_IS_APPROX(w[6], v[5]);
  v = w;
  for(int i = 0; i < 20; i++)
  {
    VERIFY_IS_APPROX(w[i], v[i]);
  }

  v.resize(21);
  v[20] = x;
  VERIFY_IS_APPROX(v[20], x);
  v.resize(22,y);
  VERIFY_IS_APPROX(v[21], y);
  v.push_back(x);
  VERIFY_IS_APPROX(v[22], x);
  VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(MatrixType));

  // do a lot of push_back such that the vector gets internally resized
  // (with memory reallocation)
  MatrixType* ref = &w[0];
  for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
    v.push_back(w[i%w.size()]);
  for(unsigned int i=23; i<v.size(); ++i)
  {
    VERIFY(v[i]==w[(i-23)%w.size()]);
  }
}

template<typename TransformType>
void check_stdvector_transform(const TransformType&)
{
  typedef typename TransformType::MatrixType MatrixType;
  TransformType x(MatrixType::Random()), y(MatrixType::Random());
  std::vector<TransformType,Eigen::aligned_allocator<TransformType> > v(10), w(20, y);
  v[5] = x;
  w[6] = v[5];
  VERIFY_IS_APPROX(w[6], v[5]);
  v = w;
  for(int i = 0; i < 20; i++)
  {
    VERIFY_IS_APPROX(w[i], v[i]);
  }

  v.resize(21);
  v[20] = x;
  VERIFY_IS_APPROX(v[20], x);
  v.resize(22,y);
  VERIFY_IS_APPROX(v[21], y);
  v.push_back(x);
  VERIFY_IS_APPROX(v[22], x);
  VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(TransformType));

  // do a lot of push_back such that the vector gets internally resized
  // (with memory reallocation)
  TransformType* ref = &w[0];
  for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
    v.push_back(w[i%w.size()]);
  for(unsigned int i=23; i<v.size(); ++i)
  {
    VERIFY(v[i].matrix()==w[(i-23)%w.size()].matrix());
  }
}

template<typename QuaternionType>
void check_stdvector_quaternion(const QuaternionType&)
{
  typedef typename QuaternionType::Coefficients Coefficients;
  QuaternionType x(Coefficients::Random()), y(Coefficients::Random());
  std::vector<QuaternionType,Eigen::aligned_allocator<QuaternionType> > v(10), w(20, y);
  v[5] = x;
  w[6] = v[5];
  VERIFY_IS_APPROX(w[6], v[5]);
  v = w;
  for(int i = 0; i < 20; i++)
  {
    VERIFY_IS_APPROX(w[i], v[i]);
  }

  v.resize(21);
  v[20] = x;
  VERIFY_IS_APPROX(v[20], x);
  v.resize(22,y);
  VERIFY_IS_APPROX(v[21], y);
  v.push_back(x);
  VERIFY_IS_APPROX(v[22], x);
  VERIFY((size_t)&(v[22]) == (size_t)&(v[21]) + sizeof(QuaternionType));

  // do a lot of push_back such that the vector gets internally resized
  // (with memory reallocation)
  QuaternionType* ref = &w[0];
  for(int i=0; i<30 || ((ref==&w[0]) && i<300); ++i)
    v.push_back(w[i%w.size()]);
  for(unsigned int i=23; i<v.size(); ++i)
  {
    VERIFY(v[i].coeffs()==w[(i-23)%w.size()].coeffs());
  }
}

void test_stdvector()
{
  // some non vectorizable fixed sizes
  CALL_SUBTEST_1(check_stdvector_matrix(Vector2f()));
  CALL_SUBTEST_1(check_stdvector_matrix(Matrix3f()));
  CALL_SUBTEST_2(check_stdvector_matrix(Matrix3d()));

  // some vectorizable fixed sizes
  CALL_SUBTEST_1(check_stdvector_matrix(Matrix2f()));
  CALL_SUBTEST_1(check_stdvector_matrix(Vector4f()));
  CALL_SUBTEST_1(check_stdvector_matrix(Matrix4f()));
  CALL_SUBTEST_2(check_stdvector_matrix(Matrix4d()));

  // some dynamic sizes
  CALL_SUBTEST_3(check_stdvector_matrix(MatrixXd(1,1)));
  CALL_SUBTEST_3(check_stdvector_matrix(VectorXd(20)));
  CALL_SUBTEST_3(check_stdvector_matrix(RowVectorXf(20)));
  CALL_SUBTEST_3(check_stdvector_matrix(MatrixXcf(10,10)));

  // some Transform
  CALL_SUBTEST_4(check_stdvector_transform(Transform2f()));
  CALL_SUBTEST_4(check_stdvector_transform(Transform3f()));
  CALL_SUBTEST_4(check_stdvector_transform(Transform3d()));
  //CALL_SUBTEST(heck_stdvector_transform(Transform4d()));

  // some Quaternion
  CALL_SUBTEST_5(check_stdvector_quaternion(Quaternionf()));
  CALL_SUBTEST_5(check_stdvector_quaternion(Quaterniond()));
}


text:
//--------------------------------------------------------------------------
// Code generated by the SmartSoft MDSD Toolchain
// The SmartSoft Toolchain has been developed by:
//
// Service Robotics Research Center
// University of Applied Sciences Ulm
// Prittwitzstr. 10
// 89075 Ulm (Germany)
//
// Information about the SmartSoft MDSD Toolchain is available at:
// www.servicerobotik-ulm.de
//
// Please do not modify this file. It will be re-generated
// running the code generator.
//--------------------------------------------------------------------------
#include "CommLocalizationObjects/CommGpsFixCore.hh"

// serialization/deserialization operators
//#include "CommLocalizationObjects/CommGpsFixACE.hh"

// include the hash.idl containing the hash constant
#include "hash.hh"
#include <assert.h>
#include <cstring>
#include <iostream>

// SmartUtils used in from_xml method
#include "smartKnuthMorrisPratt.hh"

#ifdef ENABLE_HASH
	#include <boost/functional/hash.hpp>
#endif

namespace CommLocalizationObjects
{
	const char* CommGpsFixCore::getCompiledHash()
	{
		return CommLocalizationObjectsIDL::REPO_HASH;
	}

	void CommGpsFixCore::getAllHashValues(std::list<std::string> &hashes)
	{
		// get own hash value
		hashes.push_back(getCompiledHash());
	}

	void CommGpsFixCore::checkAllHashValues(std::list<std::string> &hashes)
	{
		// check own hash value
		if (strcmp(getCompiledHash(), hashes.front().c_str()) != 0)
		{
			std::cerr << "###################################################" << std::endl;
			std::cerr << "WARNING: HASHES OF COMMUNICATION OBJECTS MISSMATCH!" << std::endl;
			std::cerr << "CommGpsFixCore hash" << std::endl;
			std::cerr << "Expected: " << getCompiledHash() << std::endl;
			std::cerr << "Received: " << hashes.front() << std::endl;
			std::cerr << "###################################################" << std::endl;
		}
		assert(strcmp(getCompiledHash(), hashes.front().c_str()) == 0);
		hashes.pop_front();

	}

	#ifdef ENABLE_HASH
	size_t CommGpsFixCore::generateDataHash(const DATATYPE &data)
	{
		size_t seed = 0;

		boost::hash_combine(seed, data.gps_timestamp);
		boost::hash_combine(seed, data.is_2D);
		boost::hash_combine(seed, data.is_3D);
		boost::hash_combine(seed, data.satellites_visible);
		boost::hash_combine(seed, data.satellites_used);
		boost::hash_combine(seed, data.latitude);
		boost::hash_combine(seed, data.longitude);
		boost::hash_combine(seed, data.altitude);
		boost::hash_combine(seed, data.speed);
		boost::hash_combine(seed, data.climb);
		boost::hash_combine(seed, data.latitude_uncertainty);
		boost::hash_combine(seed, data.longitude_uncertainty);
		boost::hash_combine(seed, data.altitude_uncertainty);
		boost::hash_combine(seed, data.speed_uncertainty);
		boost::hash_combine(seed, data.climb_uncertainty);

		return seed;
	}
	#endif

	// default constructor
	CommGpsFixCore::CommGpsFixCore()
	:	idl_CommGpsFix()
	{
		setGps_timestamp(0.0);
		setIs_2D(false);
		setIs_3D(false);
		setSatellites_visible(0);
		setSatellites_used(0);
		setLatitude(0.0);
		setLongitude(0.0);
		setAltitude(0.0);
		setSpeed(0.0);
		setClimb(0.0);
		setLatitude_uncertainty(0.0);
		setLongitude_uncertainty(0.0);
		setAltitude_uncertainty(0.0);
		setSpeed_uncertainty(0.0);
		setClimb_uncertainty(0.0);
	}

	CommGpsFixCore::CommGpsFixCore(const DATATYPE &data)
	:	idl_CommGpsFix(data)
	{  }

	CommGpsFixCore::~CommGpsFixCore()
	{  }

	void CommGpsFixCore::to_ostream(std::ostream &os) const
	{
	  os << "CommGpsFix(";
	  os << getGps_timestamp() << " ";
	  os << getIs_2D() << " ";
	  os << getIs_3D() << " ";
	  os << getSatellites_visible() << " ";
	  os << getSatellites_used() << " ";
	  os << getLatitude() << " ";
	  os << getLongitude() << " ";
	  os << getAltitude() << " ";
	  os << getSpeed() << " ";
	  os << getClimb() << " ";
	  os << getLatitude_uncertainty() << " ";
	  os << getLongitude_uncertainty() << " ";
	  os << getAltitude_uncertainty() << " ";
	  os << getSpeed_uncertainty() << " ";
	  os << getClimb_uncertainty() << " ";
	  os << ") ";
	}

	// convert to xml stream
	void CommGpsFixCore::to_xml(std::ostream &os, const std::string &indent) const {
		os << indent << "<gps_timestamp>" << getGps_timestamp() << "</gps_timestamp>";
		os << indent << "<is_2D>" << getIs_2D() << "</is_2D>";
		os << indent << "<is_3D>" << getIs_3D() << "</is_3D>";
		os << indent << "<satellites_visible>" << getSatellites_visible() << "</satellites_visible>";
		os << indent << "<satellites_used>" << getSatellites_used() << "</satellites_used>";
		os << indent << "<latitude>" << getLatitude() << "</latitude>";
		os << indent << "<longitude>" << getLongitude() << "</longitude>";
		os << indent << "<altitude>" << getAltitude() << "</altitude>";
		os << indent << "<speed>" << getSpeed() << "</speed>";
		os << indent << "<climb>" << getClimb() << "</climb>";
		os << indent << "<latitude_uncertainty>" << getLatitude_uncertainty() << "</latitude_uncertainty>";
		os << indent << "<longitude_uncertainty>" << getLongitude_uncertainty() << "</longitude_uncertainty>";
		os << indent << "<altitude_uncertainty>" << getAltitude_uncertainty() << "</altitude_uncertainty>";
		os << indent << "<speed_uncertainty>" << getSpeed_uncertainty() << "</speed_uncertainty>";
		os << indent << "<climb_uncertainty>" << getClimb_uncertainty() << "</climb_uncertainty>";
	}

	// restore from xml stream
	void CommGpsFixCore::from_xml(std::istream &is) {
		static const Smart::KnuthMorrisPratt kmp_gps_timestamp("<gps_timestamp>");
		static const Smart::KnuthMorrisPratt kmp_is_2D("<is_2D>");
		static const Smart::KnuthMorrisPratt kmp_is_3D("<is_3D>");
		static const Smart::KnuthMorrisPratt kmp_satellites_visible("<satellites_visible>");
		static const Smart::KnuthMorrisPratt kmp_satellites_used("<satellites_used>");
		static const Smart::KnuthMorrisPratt kmp_latitude("<latitude>");
		static const Smart::KnuthMorrisPratt kmp_longitude("<longitude>");
		static const Smart::KnuthMorrisPratt kmp_altitude("<altitude>");
		static const Smart::KnuthMorrisPratt kmp_speed("<speed>");
		static const Smart::KnuthMorrisPratt kmp_climb("<climb>");
		static const Smart::KnuthMorrisPratt kmp_latitude_uncertainty("<latitude_uncertainty>");
		static const Smart::KnuthMorrisPratt kmp_longitude_uncertainty("<longitude_uncertainty>");
		static const Smart::KnuthMorrisPratt kmp_altitude_uncertainty("<altitude_uncertainty>");
		static const Smart::KnuthMorrisPratt kmp_speed_uncertainty("<speed_uncertainty>");
		static const Smart::KnuthMorrisPratt kmp_climb_uncertainty("<climb_uncertainty>");

		if(kmp_gps_timestamp.search(is)) {
			double gps_timestampItem;
			is >> gps_timestampItem;
			setGps_timestamp(gps_timestampItem);
		}
		if(kmp_is_2D.search(is)) {
			bool is_2DItem;
			is >> is_2DItem;
			setIs_2D(is_2DItem);
		}
		if(kmp_is_3D.search(is)) {
			bool is_3DItem;
			is >> is_3DItem;
			setIs_3D(is_3DItem);
		}
		if(kmp_satellites_visible.search(is)) {
			int satellites_visibleItem;
			is >> satellites_visibleItem;
			setSatellites_visible(satellites_visibleItem);
		}
		if(kmp_satellites_used.search(is)) {
			int satellites_usedItem;
			is >> satellites_usedItem;
			setSatellites_used(satellites_usedItem);
		}
		if(kmp_latitude.search(is)) {
			double latitudeItem;
			is >> latitudeItem;
			setLatitude(latitudeItem);
		}
		if(kmp_longitude.search(is)) {
			double longitudeItem;
			is >> longitudeItem;
			setLongitude(longitudeItem);
		}
		if(kmp_altitude.search(is)) {
			double altitudeItem;
			is >> altitudeItem;
			setAltitude(altitudeItem);
		}
		if(kmp_speed.search(is)) {
			double speedItem;
			is >> speedItem;
			setSpeed(speedItem);
		}
		if(kmp_climb.search(is)) {
			double climbItem;
			is >> climbItem;
			setClimb(climbItem);
		}
		if(kmp_latitude_uncertainty.search(is)) {
			double latitude_uncertaintyItem;
			is >> latitude_uncertaintyItem;
			setLatitude_uncertainty(latitude_uncertaintyItem);
		}
		if(kmp_longitude_uncertainty.search(is)) {
			double longitude_uncertaintyItem;
			is >> longitude_uncertaintyItem;
			setLongitude_uncertainty(longitude_uncertaintyItem);
		}
		if(kmp_altitude_uncertainty.search(is)) {
			double altitude_uncertaintyItem;
			is >> altitude_uncertaintyItem;
			setAltitude_uncertainty(altitude_uncertaintyItem);
		}
		if(kmp_speed_uncertainty.search(is)) {
			double speed_uncertaintyItem;
			is >> speed_uncertaintyItem;
			setSpeed_uncertainty(speed_uncertaintyItem);
		}
		if(kmp_climb_uncertainty.search(is)) {
			double climb_uncertaintyItem;
			is >> climb_uncertaintyItem;
			setClimb_uncertainty(climb_uncertaintyItem);
		}
	}

	/*
	void CommGpsFixCore::get(ACE_Message_Block *&msg) const
	{
		// start with a default internal buffer size(will automatically grow if needed)
		ACE_OutputCDR cdr(ACE_DEFAULT_CDR_BUFSIZE);

		CommLocalizationObjectsIDL::HashList hashes;
		getAllHashValues(hashes);
		cdr << static_cast<ACE_CDR::Long>(hashes.size());
		for(CommLocalizationObjectsIDL::HashList::const_iterator it=hashes.begin(); it!=hashes.end(); it++)
		{
			cdr << ACE_CString(it->c_str());
		}

		// Here the actual serialization takes place using the OutputCDR serialization operator<<
		// (see CommGpsFixACE.hh)
		cdr << idl_CommGpsFix;

	#ifdef ENABLE_HASH
		ACE_CDR::ULong data_hash = generateDataHash(idl_CommGpsFix);
		cdr << data_hash;
		// std::cout << "CommGpsFixCore: current data hash: " << data_hash << std::endl;
	#endif

		// return a shallow copy of the serialized message
		// (no data is actually copied, only the internal reference counter is incremented)
		// in order to prevent memory leaks the caller of this get(msg) method must
		// manually free the memory by calling the release() method of the message block msg
		msg = cdr.begin()->duplicate();
	}

	void CommGpsFixCore::set(const ACE_Message_Block *msg)
	{
		ACE_InputCDR cdr(msg);

		CommLocalizationObjectsIDL::HashList hashes;
		ACE_CDR::Long hashes_size;
		cdr >> hashes_size;
		for(int i=0; i<hashes_size; ++i)
		{
			ACE_CString hash;
			cdr >> hash;
			hashes.push_back(hash.c_str());
		}
		checkAllHashValues(hashes);

		// Here the actual de-serialization takes place using the InputCDR serialization operator>>
		// (see CommGpsFixACE.hh)
		cdr >> idl_CommGpsFix;

	#ifdef ENABLE_HASH
		ACE_CDR::Long data_hash;
		cdr >> data_hash;
		ACE_CDR::Long own_hash = generateDataHash(idl_CommGpsFix);
		assert(data_hash == own_hash);
		// std::cout << "CommGpsFixCore: own data hash: " << own_hash << "; received data hash: " << data_hash << std::endl;
	#endif
	}
	*/
} /* namespace CommLocalizationObjects */

ext: cc


text:
/**
 * Copyright (c) 2013-2015, Damian Vicino
 * Carleton University, Universite de Nice-Sophia Antipolis
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef BOOST_SIMULATION_PDEVS_BM_INFINITE_COUNTER_H
#define BOOST_SIMULATION_PDEVS_BM_INFINITE_COUNTER_H
#include <boost/simulation/pdevs/atomic.hpp>
#include <boost/any.hpp>

namespace boost {
namespace simulation {
namespace pdevs {
namespace basic_models {

/**
 * @brief InfiniteCounter PDEVS Model.
 *
 * InfiniteCounter PDEVS Model:
 * - X = N
 * - Y = N
 * - S = {passive, active} x R+ x N
 * - internal(phase, t, count) = (passive, t, count)
 * - external(passive, t, count, e, x)=
 *           (passive, t-e, count+1) if x != 0
 *           (active, 0, 0) otherwise
 * - confluence(*) = external(active, 0, internal(phase, t, count))
 * - out (active, t, count) = count
 * - advance(phase, t, count) = t
*/

template<class TIME, class MSG>
class infinite_counter : public atomic<TIME, MSG>
{
    //state
    TIME _next;
    int _counter;
public:
    /**
     * @brief InfiniteCounter constructor.
     */
    explicit infinite_counter() noexcept : atomic<TIME, MSG>(), _counter(0){
        _next = atomic<TIME, MSG>::infinity;
    }
    /**
     * @brief internal function
     *
     * The internal function resets the counter.
     */
    void internal() noexcept {
        _next = atomic<TIME, MSG>::infinity;
        _counter = 0;
    }
    /**
     * @brief advance function.
     * @return Time until next internal event.
     */
    TIME advance() const noexcept { return _next; }
    /**
     * @brief out function.
     * @return _counter
     */
    std::vector<MSG> out() const noexcept { return std::vector<MSG>{_counter}; }
    /**
     * @brief external function.
     *
     * If the external function receives any 0 trigger the output setting the ta to 0.
     * The function also increments the counter for each received message
     * @param mb bag of messages.
     * @param t time the external input is received.
     */
    void external(const std::vector<MSG>& mb, const TIME& t) noexcept {
        int zeros = count_if(mb.begin(), mb.end(),
                        [](const MSG& m){
                            if(0 == boost::any_cast<int>(m)) return true;
                            else return false;
                        });
         if ( zeros ){
            _next = TIME{0};
            _counter += mb.size() - zeros;

        } else {
            _counter += mb.size();
        }
    }

    /**
     * @brief confluence function.
     * Execute the internal first, it means someone already requested a counting result before.
     *
     * @param msg
     * @param t time the external input is confluent with an internal transition.
     */
    void confluence(const std::vector<MSG>& mb, const TIME& t) noexcept {
        internal();
        external(mb, t);
    }

};

}
}
}
}

#endif // BOOST_SIMULATION_PDEVS_BM_INFINITE_COUNTER_H

max_stars_repo_name: romancardenas/cdboost

max_issues_repo_name: romancardenas/cdboost

max_forks_repo_name: romancardenas/cdboost