<commit_before>/*
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

#pragma once
#ifndef _INCLUDE__YAJR__YAJR_HPP
#define _INCLUDE__YAJR__YAJR_HPP

#include <string>
#include <uv.h>

namespace yajr {

int  initLoop(uv_loop_t * loop);
void finiLoop(uv_loop_t * loop);

namespace StateChange {
    enum To {
        CONNECT,
        DISCONNECT,
        FAILURE,
        DELETE,
    };
};

/**
 * @brief A yajr communication peer.
 */
struct Peer {

  public:

    /**
     * @brief Typedef for a Peer state change callback
     *
     * Callback type for a Peer State Change. The callback is invoked when a
     * Peer becomes CONNECT'ed, or DISCONNECT'ed or when a FAILURE occurs for the
     * Peer. These three states are represented by the \p stateChange parameter.
     *
     * When \p stateChange is FAILURE, \p error carries a non-zero value, which
     * is to be interpreted as a libuv error code.
     *
     * When \p stateChange is DELETE, the Peer is about to be deleted. It's a
     * good time to release any resources such as the memory reachable via the
     * \p data pointer.
     */
    typedef void (*StateChangeCb)(
            yajr::Peer            *,
                                    /**< [in] the Peer the callback refers to */
            void                  * data,
                                         /**< [in] Callback data for the Peer */
            yajr::StateChange::To   stateChange,
                                                 /**< [in] New state for Peer */
            int                     error
                                               /**< [in] libuv error for Peer */
    );

    /**
     * @brief Typedef for a uv_loop selector
     *
     * Function pointer type for the uv_loop selector method to be used to
     * select which particular uv_loop to assign a peer to.
     *
     * @return a pointer to the desired uv_loop.
     */
    typedef uv_loop_t * (*UvLoopSelector)(
            void * data
                                         /**< [in] Callback data for the Peer */
    );

    /**
     * @brief Factory for an active yajr communication Peer.
     *
     * This static class method creates a communication Peer and connects it
     * to the desired \p host and \p service at the very next opportunity.
     *
     * Upon successful connect, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::CONNECT, and an error value of 0 (success).
     *
     * Upon an error, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::FAILURE, and a non-zero error value. If the Peer had
     * managed to connect before the failure, the callback will get invoked once
     * again shortly after, with a state of DISCONNECT.
     *
     * Upon disconnect, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::DISCONNECT, and possibly a non-zero error value. If the
     * disconnect is due to a failure, the callback will have just been invoked
     * with a FAILURE state immediately before this time.
     *
     * If \p data was allocated by the caller, \p connectionHandler should be
     * releasing \p data upon DISCONNECT.
     *
     * @return a pointer to the Peer created
     **/
    static Peer * create(
            std::string const     & host,
                                         /**< [in] the hostname to connect to */
            std::string const     & service,
                                               /**< [in] service name or port */
            StateChangeCb           connectionHandler,
                                              /**< [in] state change callback */
            void                  * data              = NULL,
                                                      /**< [in] callback data */
            UvLoopSelector          uvLoopSelector    = NULL
                                     /**< [in] uv_loop selector for this Peer */
    );

    /**
     * @brief perform an asynchronous delete
     *
     * Perform an asynchronous delete of this communication peer, disconnecting
     * it if still connected and destroying it as soon as no more callbacks are
     * pending for this Peer.
     */
    virtual void destroy() = 0;

    /**
     * @brief retrieves the pointer to the opaque data associated with this peer
     *
     * @return a pointer to the opaque data for this peer, the same pointer that
     * is provided to the State Change callback
     */
    virtual void * getData() const = 0;

    /**
     * @brief start performing periodic keep-alive
     *
     * start performing periodic keep-alive exchanges via the json-rpc
     * "echo" method. Abort the connection after 2 times interval worth of
     * silence from the other end.
     */
    virtual void startKeepAlive(
            uint64_t                begin             = 100,
            uint64_t                repeat            = 1250,
            uint64_t                interval          = 2500
    ) = 0;

    /**
     * @brief stop performing periodic keep-alive
     */
    virtual void stopKeepAlive() = 0;

  protected:
    Peer() {}
    ~Peer() {}
};

struct Listener {

  public:

    /**
     * @brief Typedef for an Accept callback
     *
     * Callback type for an Accept callback. The callback is invoked when a
     * Peer is ACCEPT'ed.
     *
     * @return void pointer to callback data for the StateChange callback for
     * the accepted passive peer, or NULL if error != 0.
     */
    typedef void * (*AcceptCb)(
            Listener               *,
                                /**< [in] the Listener the callback refers to */
            void                   * data,
                                     /**< [in] Callback data for the Listener */
            int                      error
                                               /**< [in] libuv error for Peer */
    );

    /**
     * @brief Factory for a passive yajr Listener.
     *
     * This static class method creates a yajr Listener and binds it to
     * the desired \p ip and \p port at the very next opportunity. Upon
     * accept'ing a client, a passive peer gets created with \p connectionHandler
     * as a state change callback, and the callback data returned by the
     * \p acceptHandler callback.
     *
     * The \p acceptHandler callback gets invoked upon accept'ing a client. It
     * get invoked with the following parameters: the Listener pointer, the
     * \p data pointer supplied to Listener::create(), and an \p error value.
     * The \p error value will be 0 in case of a successful accept, or a libuv
     * error value otherwise. If \p error is 0, \p acceptHandler is expected to
     * return a void pointer to the callback \p data to be associated with the
     * passive peer that is being accepted, and to be passed by that peer to its
     * \p connectionHandler. If \p error is non-zero, \p acceptHandler is
     * expected to return NULL, since no passive peer is being created. If the
     * \p acceptHandler callback is allocating memory, the \p connectionHandler
     * callback should be releasing that memory when invoked with a state of
     * DISCONNECTED.
     *
     * Upon an error, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::FAILURE, and a non-zero error value. If the Peer had
     * managed to connect before the failure, the callback will get invoked once
     * again shortly after, with a state of DISCONNECT.
     *
     * Upon disconnect, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::DICONNECT, and possibly a non-zero error value. If the
     * disconnect is due to a failure, the callback will have just been invoked
     * with a FAILURE state immediately before this time.
     *
     * @return a pointer to the Peer created
     **/
    static Listener * create(
        char const                 * ip_address,
                /**< [in] the ip address to bind to, or "0.0.0.0" to bind all */
        uint16_t                     port,
                                                /**< [in] the port to bind to */
        Peer::StateChangeCb          connectionHandler,
               /**< [in] state change callback for the accepted passive peers */
        AcceptCb                     acceptHandler     = NULL,
                                  /**< [in] accept callback for this listener */
        void                       * data              = NULL,
                              /**< [in] callback data for the accept callback */
        uv_loop_t                  * listenerUvLoop    = NULL,
                                       /**< [in] libuv loop for this Listener */
        Peer::UvLoopSelector         uvLoopSelector    = NULL
                 /**< [in] libuv loop selector for the accepted passive peers */
    );

    /**
     * @brief perform an asynchronous delete
     *
     * Perform an asynchronous delete of this Listener, destroying it as soon as
     * no more callbacks are pending for it.
     */
    virtual void destroy() = 0;

  protected:
    Listener() {}
    ~Listener() {}
};

}

#endif /* _INCLUDE__YAJR__YAJR_HPP */
<commit_msg>fix small inaccuracy in documentation<commit_after>/*
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

#pragma once
#ifndef _INCLUDE__YAJR__YAJR_HPP
#define _INCLUDE__YAJR__YAJR_HPP

#include <string>
#include <uv.h>

namespace yajr {

int  initLoop(uv_loop_t * loop);
void finiLoop(uv_loop_t * loop);

namespace StateChange {
    enum To {
        CONNECT,
        DISCONNECT,
        FAILURE,
        DELETE,
    };
};

/**
 * @brief A yajr communication peer.
 */
struct Peer {

  public:

    /**
     * @brief Typedef for a Peer state change callback
     *
     * Callback type for a Peer State Change. The callback is invoked when a
     * Peer becomes CONNECT'ed, or DISCONNECT'ed or when a FAILURE occurs for the
     * Peer. These three states are represented by the \p stateChange parameter.
     *
     * When \p stateChange is FAILURE, \p error carries a non-zero value, which
     * is to be interpreted as a libuv error code.
     *
     * When \p stateChange is DELETE, the Peer is about to be deleted. It's a
     * good time to release any resources such as the memory reachable via the
     * \p data pointer.
     */
    typedef void (*StateChangeCb)(
            yajr::Peer            *,
                                    /**< [in] the Peer the callback refers to */
            void                  * data,
                                         /**< [in] Callback data for the Peer */
            yajr::StateChange::To   stateChange,
                                                 /**< [in] New state for Peer */
            int                     error
                                               /**< [in] libuv error for Peer */
    );

    /**
     * @brief Typedef for a uv_loop selector
     *
     * Function pointer type for the uv_loop selector method to be used to
     * select which particular uv_loop to assign a peer to.
     *
     * @return a pointer to the desired uv_loop.
     */
    typedef uv_loop_t * (*UvLoopSelector)(
            void * data
                                         /**< [in] Callback data for the Peer */
    );

    /**
     * @brief Factory for an active yajr communication Peer.
     *
     * This static class method creates a communication Peer and connects it
     * to the desired \p host and \p service at the very next opportunity.
     *
     * Upon successful connect, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::CONNECT, and an error value of 0 (success).
     *
     * Upon an error, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::FAILURE, and a non-zero error value. If the Peer had
     * managed to connect before the failure, the callback will get invoked once
     * again shortly after, with a state of DISCONNECT.
     *
     * Upon disconnect, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::DISCONNECT, and possibly a non-zero error value. If the
     * disconnect is due to a failure, the callback will have just been invoked
     * with a FAILURE state immediately before this time.
     *
     * If \p data was allocated by the caller, \p connectionHandler should be
     * releasing \p data upon StateChange::To::DELETE.
     *
     * @return a pointer to the Peer created
     **/
    static Peer * create(
            std::string const     & host,
                                         /**< [in] the hostname to connect to */
            std::string const     & service,
                                               /**< [in] service name or port */
            StateChangeCb           connectionHandler,
                                              /**< [in] state change callback */
            void                  * data              = NULL,
                                                      /**< [in] callback data */
            UvLoopSelector          uvLoopSelector    = NULL
                                     /**< [in] uv_loop selector for this Peer */
    );

    /**
     * @brief perform an asynchronous delete
     *
     * Perform an asynchronous delete of this communication peer, disconnecting
     * it if still connected and destroying it as soon as no more callbacks are
     * pending for this Peer.
     */
    virtual void destroy() = 0;

    /**
     * @brief retrieves the pointer to the opaque data associated with this peer
     *
     * @return a pointer to the opaque data for this peer, the same pointer that
     * is provided to the State Change callback
     */
    virtual void * getData() const = 0;

    /**
     * @brief start performing periodic keep-alive
     *
     * start performing periodic keep-alive exchanges via the json-rpc
     * "echo" method. Abort the connection after 2 times interval worth of
     * silence from the other end.
     */
    virtual void startKeepAlive(
            uint64_t                begin             = 100,
            uint64_t                repeat            = 1250,
            uint64_t                interval          = 2500
    ) = 0;

    /**
     * @brief stop performing periodic keep-alive
     */
    virtual void stopKeepAlive() = 0;

  protected:
    Peer() {}
    ~Peer() {}
};

struct Listener {

  public:

    /**
     * @brief Typedef for an Accept callback
     *
     * Callback type for an Accept callback. The callback is invoked when a
     * Peer is ACCEPT'ed.
     *
     * @return void pointer to callback data for the StateChange callback for
     * the accepted passive peer, or NULL if error != 0.
     */
    typedef void * (*AcceptCb)(
            Listener               *,
                                /**< [in] the Listener the callback refers to */
            void                   * data,
                                     /**< [in] Callback data for the Listener */
            int                      error
                                               /**< [in] libuv error for Peer */
    );

    /**
     * @brief Factory for a passive yajr Listener.
     *
     * This static class method creates a yajr Listener and binds it to
     * the desired \p ip and \p port at the very next opportunity. Upon
     * accept'ing a client, a passive peer gets created with \p connectionHandler
     * as a state change callback, and the callback data returned by the
     * \p acceptHandler callback.
     *
     * The \p acceptHandler callback gets invoked upon accept'ing a client. It
     * get invoked with the following parameters: the Listener pointer, the
     * \p data pointer supplied to Listener::create(), and an \p error value.
     * The \p error value will be 0 in case of a successful accept, or a libuv
     * error value otherwise. If \p error is 0, \p acceptHandler is expected to
     * return a void pointer to the callback \p data to be associated with the
     * passive peer that is being accepted, and to be passed by that peer to its
     * \p connectionHandler. If \p error is non-zero, \p acceptHandler is
     * expected to return NULL, since no passive peer is being created. If the
     * \p acceptHandler callback is allocating memory, the \p connectionHandler
     * callback should be releasing that memory when invoked with a state of
     * DISCONNECTED.
     *
     * Upon an error, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::FAILURE, and a non-zero error value. If the Peer had
     * managed to connect before the failure, the callback will get invoked once
     * again shortly after, with a state of DISCONNECT.
     *
     * Upon disconnect, the \p connectionHandler callback gets invoked
     * with the Peer pointer, the \p data pointer supplied to Peer::create(),
     * StateChange::To::DICONNECT, and possibly a non-zero error value. If the
     * disconnect is due to a failure, the callback will have just been invoked
     * with a FAILURE state immediately before this time.
     *
     * @return a pointer to the Peer created
     **/
    static Listener * create(
        char const                 * ip_address,
                /**< [in] the ip address to bind to, or "0.0.0.0" to bind all */
        uint16_t                     port,
                                                /**< [in] the port to bind to */
        Peer::StateChangeCb          connectionHandler,
               /**< [in] state change callback for the accepted passive peers */
        AcceptCb                     acceptHandler     = NULL,
                                  /**< [in] accept callback for this listener */
        void                       * data              = NULL,
                              /**< [in] callback data for the accept callback */
        uv_loop_t                  * listenerUvLoop    = NULL,
                                       /**< [in] libuv loop for this Listener */
        Peer::UvLoopSelector         uvLoopSelector    = NULL
                 /**< [in] libuv loop selector for the accepted passive peers */
    );

    /**
     * @brief perform an asynchronous delete
     *
     * Perform an asynchronous delete of this Listener, destroying it as soon as
     * no more callbacks are pending for it.
     */
    virtual void destroy() = 0;

  protected:
    Listener() {}
    ~Listener() {}
};

}

#endif /* _INCLUDE__YAJR__YAJR_HPP */
<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2017-2018 Artur Wyszyński, aljen at hitomi dot pl
//
// 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 "shared_library.h"

// clang-format off
#if defined(_WIN64) || defined(_WIN32)
# include <Windows.h>
#elif defined(__unix__)
# include <dlfcn.h>
#endif
// clang-format on
#include "spaghetti/logger.h"

namespace spaghetti {

SharedLibrary::SharedLibrary(fs::path a_file, std::error_code &a_errorCode)
  : m_filename{ a_file.string() }
{
  log::info("[shared_library]: Opening {}", m_filename);

  if (!fs::exists(a_file)) {
    log::error("{} don't exist!", m_filename);
    a_errorCode = std::error_code(ENOENT, std::system_category());
    return;
  }

#if defined(_WIN64) || defined(_WIN32)
  if (a_file.extension() != ".dll") {
#else
  if (a_file.extension() != ".so") {
#endif
    log::debug("{} is not shared library!", m_filename);
    a_errorCode = std::error_code(EINVAL, std::system_category());
    return;
  }

#if defined(_WIN64) || defined(_WIN32)
  m_handle = LoadLibrary(a_file.c_str());
  if (m_handle == nullptr) {
    auto const ERROR_CODE = GetLastError();
    LPSTR buffer{};
    size_t const SIZE{ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
      NULL, ERROR_CODE, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPSTR>(&buffer), 0, nullptr) };
    std::string const MESSAGE(buffer, SIZE);
    LocalFree(buffer);
    log::error("LoadLibrary error: {}", MESSAGE);
    a_errorCode = std::error_code(ERROR_CODE, std::system_category());
  }
#elif defined(__unix__)
  m_handle = dlopen(a_file.c_str(), RTLD_NOW);
  if (m_handle == nullptr) {
    log::error("{}", dlerror());
    a_errorCode = std::error_code(EINVAL, std::system_category());
    return;
  }
#endif

  a_errorCode = std::error_code(0, std::system_category());
}

SharedLibrary::~SharedLibrary()
{
  log::info("[shared_library]: Closing {}", m_filename);
#if defined(_WIN64) || defined(_WIN32)
  if (m_handle) FreeLibrary(static_cast<HMODULE>(m_handle));
#elif defined(__unix__)
  if (m_handle) dlclose(m_handle);
#endif
}

bool SharedLibrary::has(std::string_view a_signature) const
{
  log::info("[shared_library]: Checking if symbol {} exists in {}", a_signature.data(), m_filename);

  if (m_handle == nullptr) return false;

#if defined(_WIN64) || defined(_WIN32)
  return GetProcAddress(static_cast<HMODULE>(m_handle), a_signature.data()) != nullptr;
#elif defined(__unix__)
  return dlsym(m_handle, a_signature.data()) != nullptr;
#endif
}

void *SharedLibrary::getSymbol(std::string_view a_signature)
{
  log::info("[shared_library]: Getting symbol {} from {}", a_signature.data(), m_filename);

#if defined(_WIN64) || defined(_WIN32)
  return GetProcAddress(static_cast<HMODULE>(m_handle), a_signature.data());
#elif defined(__unix__)
  return dlsym(m_handle, a_signature.data());
#endif
}

} // namespace spaghetti
<commit_msg>Reformat shared_library.cc<commit_after>// MIT License
//
// Copyright (c) 2017-2018 Artur Wyszyński, aljen at hitomi dot pl
//
// 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 "shared_library.h"

// clang-format off
#if defined(_WIN64) || defined(_WIN32)
# include <Windows.h>
#elif defined(__unix__)
# include <dlfcn.h>
#endif
// clang-format on
#include "spaghetti/logger.h"

namespace spaghetti {

SharedLibrary::SharedLibrary(fs::path a_file, std::error_code &a_errorCode)
  : m_filename{ a_file.string() }
{
  log::info("[shared_library]: Opening {}", m_filename);

  if (!fs::exists(a_file)) {
    log::error("{} don't exist!", m_filename);
    a_errorCode = std::error_code(ENOENT, std::system_category());
    return;
  }

#if defined(_WIN64) || defined(_WIN32)
  if (a_file.extension() != ".dll") {
#else
  if (a_file.extension() != ".so") {
#endif
    log::debug("{} is not shared library!", m_filename);
    a_errorCode = std::error_code(EINVAL, std::system_category());
    return;
  }

#if defined(_WIN64) || defined(_WIN32)
  m_handle = LoadLibrary(a_file.c_str());
  if (m_handle == nullptr) {
    auto const ERROR_CODE = GetLastError();
    LPSTR buffer{};
    size_t const SIZE{ FormatMessageA(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ERROR_CODE,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPSTR>(&buffer), 0, nullptr) };
    std::string const MESSAGE(buffer, SIZE);
    LocalFree(buffer);
    log::error("LoadLibrary error: {}", MESSAGE);
    a_errorCode = std::error_code(ERROR_CODE, std::system_category());
  }
#elif defined(__unix__)
  m_handle = dlopen(a_file.c_str(), RTLD_NOW);
  if (m_handle == nullptr) {
    log::error("{}", dlerror());
    a_errorCode = std::error_code(EINVAL, std::system_category());
    return;
  }
#endif

  a_errorCode = std::error_code(0, std::system_category());
}

SharedLibrary::~SharedLibrary()
{
  log::info("[shared_library]: Closing {}", m_filename);
#if defined(_WIN64) || defined(_WIN32)
  if (m_handle) FreeLibrary(static_cast<HMODULE>(m_handle));
#elif defined(__unix__)
  if (m_handle) dlclose(m_handle);
#endif
}

bool SharedLibrary::has(std::string_view a_signature) const
{
  log::info("[shared_library]: Checking if symbol {} exists in {}", a_signature.data(), m_filename);

  if (m_handle == nullptr) return false;

#if defined(_WIN64) || defined(_WIN32)
  return GetProcAddress(static_cast<HMODULE>(m_handle), a_signature.data()) != nullptr;
#elif defined(__unix__)
  return dlsym(m_handle, a_signature.data()) != nullptr;
#endif
}

void *SharedLibrary::getSymbol(std::string_view a_signature)
{
  log::info("[shared_library]: Getting symbol {} from {}", a_signature.data(), m_filename);

#if defined(_WIN64) || defined(_WIN32)
  return GetProcAddress(static_cast<HMODULE>(m_handle), a_signature.data());
#elif defined(__unix__)
  return dlsym(m_handle, a_signature.data());
#endif
}

} // namespace spaghetti
<|endoftext|>


<commit_before>// Copyright 2016 Dawid Kurek. All Rights Reserved.

#include "chip/chip8.hpp"

#include <atomic>
#include <fstream>
#include <stdexcept>
#include <string>
#include <thread>

#include "chip/executor.hpp"
#include "chip/memory.hpp"
#include "chip/opcode.hpp"

namespace chip {

Chip8::Chip8(Byte const &clock)
  : _cycleDuration{1000 / clock}
  , _memory{}
  , _execute{}
  , _getKey{[]() { return 0; }}
  , _redraw{[]() {}}
  , _running{false}
  , _worker{} {}

Chip8::~Chip8() {
  stop();
}

void Chip8::getKey(GetKey const &callback) {
  _getKey = callback;
}

void Chip8::redraw(Redraw const &callback) {
  _redraw = callback;
}

FileChoosen Chip8::fileChoosenCallback() {
  return [this](std::string const &file) { load(file); };
}

KeyEvent Chip8::keyEventCallback() {
  return [this](char const key, bool const isPressed) {};
}

Byte const *const Chip8::getDisplay() {
  return _memory.Display;
}

void Chip8::load(std::string const &file) {
  stop();

  size_t position = 0x200;
  for (std::ifstream input{file, std::ios::binary}; input.good();) {
    if (position > 0x1000) {
      throw std::runtime_error{"Input file is too big, max size is " +
                               std::to_string(0x1000 - 0x200)};
    }

    _memory.Raw[position++] = input.get();
  }

  start();
}

void Chip8::start() {
  _running = true;
  _memory.PC = 0x200;
  _worker = std::thread{&Chip8::main, this};
}

void Chip8::stop() {
  _running = false;
  if (_worker.joinable()) {
    _worker.join();
  }
}

void Chip8::main() {
  while (_running) {
    auto const opcode = fetch();
    tick();
    _execute(Opcode{opcode}, _memory, _getKey);
    wait();
  }
}

Word Chip8::fetch() {
  return _memory.Raw[_memory.PC] << 8 | _memory.Raw[_memory.PC + 1];
}

void Chip8::tick() {
  _memory.PC += 2;
  if (_memory.ST > 0) {
    --_memory.ST;
  }
  if (_memory.DT > 0) {
    --_memory.DT;
  }
  _redraw();
}

void Chip8::wait() {
  std::this_thread::sleep_for(std::chrono::milliseconds(16));
}

}  // namespace chip
<commit_msg>Fix cycle sleep<commit_after>// Copyright 2016 Dawid Kurek. All Rights Reserved.

#include "chip/chip8.hpp"

#include <atomic>
#include <fstream>
#include <stdexcept>
#include <string>
#include <thread>

#include "chip/executor.hpp"
#include "chip/memory.hpp"
#include "chip/opcode.hpp"

namespace chip {

Chip8::Chip8(Byte const &clock)
  : _cycleDuration{1000 / clock}
  , _memory{}
  , _execute{}
  , _getKey{[]() { return 0; }}
  , _redraw{[]() {}}
  , _running{false}
  , _worker{} {}

Chip8::~Chip8() {
  stop();
}

void Chip8::getKey(GetKey const &callback) {
  _getKey = callback;
}

void Chip8::redraw(Redraw const &callback) {
  _redraw = callback;
}

FileChoosen Chip8::fileChoosenCallback() {
  return [this](std::string const &file) { load(file); };
}

KeyEvent Chip8::keyEventCallback() {
  return [this](char const key, bool const isPressed) {};
}

Byte const *const Chip8::getDisplay() {
  return _memory.Display;
}

void Chip8::load(std::string const &file) {
  stop();

  size_t position = 0x200;
  for (std::ifstream input{file, std::ios::binary}; input.good();) {
    if (position > 0x1000) {
      throw std::runtime_error{"Input file is too big, max size is " +
                               std::to_string(0x1000 - 0x200)};
    }

    _memory.Raw[position++] = input.get();
  }

  start();
}

void Chip8::start() {
  _running = true;
  _memory.PC = 0x200;
  _worker = std::thread{&Chip8::main, this};
}

void Chip8::stop() {
  _running = false;
  if (_worker.joinable()) {
    _worker.join();
  }
}

void Chip8::main() {
  while (_running) {
    auto const opcode = fetch();
    tick();
    _execute(Opcode{opcode}, _memory, _getKey);
    wait();
  }
}

Word Chip8::fetch() {
  return _memory.Raw[_memory.PC] << 8 | _memory.Raw[_memory.PC + 1];
}

void Chip8::tick() {
  _memory.PC += 2;
  if (_memory.ST > 0) {
    --_memory.ST;
  }
  if (_memory.DT > 0) {
    --_memory.DT;
  }
  _redraw();
}

void Chip8::wait() {
  static auto lastEntry = std::chrono::system_clock::now();

  auto const newEntry = std::chrono::system_clock::now();
  auto const lastCycleDuration = newEntry - lastEntry;

  if (lastCycleDuration < _cycleDuration) {
    std::this_thread::sleep_for(_cycleDuration - lastCycleDuration);
  }

  lastEntry = newEntry;
}

}  // namespace chip
<|endoftext|>


<commit_before>#include <cmath>
#include <string>
#include <coodinate_system.hpp>
#include <tle.hpp>
#include <orbit.hpp>
#include <ctime>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include "mathematic_utils.hpp"

using namespace Eigen;

// 地心直交座標系で、
//  射点位置(P0)
//  衛星位置(P1)
//  軌道接平面法線(N)
// から、
//  楕円体(E(O,R)) 面上の着弾点を得る
Vector3dSet find_impact_point(
    const Vector3d& P0, const Vector3d& P1, const Vector3d& N,
    const Vector3d& O, const Vector3d& R)
{
  Vector3d v1 = P1 - P0;                   // 発射ビームの向き
  Vector3d v2 = reflect(v1,N);             // 反射ビームの向き
  Vector3dSet Q = intersection(P1,v2,O,R); // 着弾点候補
  Vector3dSet X = neighoring(P1,Q);        // 着弾点候補のうちP1に近い点

  return X;
}

// 測地座標系で、
//  射点位置(P)
//  使う人工衛星のTLE
//  現在時刻 t
// から、地上の着弾点を得る
bool find_impact(const polar& P, polar* X,
                 const std::string& tle_str, const time_t* t)
{
  // TLE読み込み
  TLE tle;
  std::string tle_str1 = tle_str.substr(0,69);
  std::string tle_str2 = tle_str.substr(69,69);
  tle.set(tle_str1,tle_str2);

  // 地心赤道直交座標系での射点座標
  ::polar Po = P;
  Po.latitude  *= M_PI / 180.; // degree -> radian
  Po.longitude *= M_PI / 180.; // degree -> radian
  rectangular Pr = Po.toEquatorial(t).toRectangular();
  Eigen::Vector3d P0(Pr.X, Pr.Y, Pr.Z);

  // 軌道
  orbit orb;
  orb.setTLE(&tle);
  double since_day = orb.elapsed_day(t);
  double since_min = since_day * 1440.;
  double since_sec = since_day * 86400.;

  double motion = tle.motion; // revolutions per day
  double dayp6  = 1. / (6. * motion); // day for 1/6 revolution.
  double minp6  = dayp6 * 1440.;
  double secp6  = dayp6 * 86400.;

  // 人工衛星の所在地
  double position0[3],position1[3],position2[3];
  double velocity0[3],velocity1[3],velocity2[3];
  orb.sgp(position0,velocity0,since_min - minp6);
  orb.sgp(position1,velocity1,since_min);
  orb.sgp(position2,velocity2,since_min + minp6);

  Eigen::Vector3d p0(position0);
  Eigen::Vector3d p1(position1); // 人工衛星の現在地の位置ベクトル
  Eigen::Vector3d p2(position2);
  Eigen::Vector3d v1(velocity1);

  Eigen::Vector3d n0 = normalize((p1-p0).cross(p2-p1)); // 軌道面の法線ベクトル
  Eigen::Vector3d n1 = n0.cross(normalize(v1));         // 反射面の法線ベクトル

  Eigen::Vector3d O(0.,0.,0.);
  Eigen::Vector3d R(6378.137,6378.137,6356.752); // 地球楕円体
  Vector3dSet Q = find_impact_point(P0,p1,n1,O,R);

  rectangular Xr;
  bool f = (Q.size() != 0);
  if (f) {
    Eigen::Vector3d q = Q[0];
    Xr.X = q[0];
    Xr.Y = q[1];
    Xr.Z = q[2];
  } else {
    Xr.X = 0.0;
    Xr.Y = 0.0;
    Xr.Z = 0.0;
  }

  ::polar x = Xr.toPolar();
  *X = Xr.toPolar().toGeodetic(t); // 測地座標系に変換
  X->latitude  *= 180. / M_PI;     // radian -> degree
  X->longitude *= 180. / M_PI;     // radian -> degree
  if ( X->latitude >  180.)  X->latitude  -= 180.;
  if ( X->latitude < -180.)  X->latitude  += 180.;
  if ( X->longitude >  180.) X->longitude -= 180.;
  if ( X->longitude < -180.) X->longitude += 180.;

  return f;
}

<commit_msg>着弾点の緯度経度が180度を越えたときの補正方法を修正<commit_after>#include <cmath>
#include <string>
#include <coodinate_system.hpp>
#include <tle.hpp>
#include <orbit.hpp>
#include <ctime>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include "mathematic_utils.hpp"

using namespace Eigen;

// 地心直交座標系で、
//  射点位置(P0)
//  衛星位置(P1)
//  軌道接平面法線(N)
// から、
//  楕円体(E(O,R)) 面上の着弾点を得る
Vector3dSet find_impact_point(
    const Vector3d& P0, const Vector3d& P1, const Vector3d& N,
    const Vector3d& O, const Vector3d& R)
{
  Vector3d v1 = P1 - P0;                   // 発射ビームの向き
  Vector3d v2 = reflect(v1,N);             // 反射ビームの向き
  Vector3dSet Q = intersection(P1,v2,O,R); // 着弾点候補
  Vector3dSet X = neighoring(P1,Q);        // 着弾点候補のうちP1に近い点

  return X;
}

// 測地座標系で、
//  射点位置(P)
//  使う人工衛星のTLE
//  現在時刻 t
// から、地上の着弾点を得る
bool find_impact(const polar& P, polar* X,
                 const std::string& tle_str, const time_t* t)
{
  // TLE読み込み
  TLE tle;
  std::string tle_str1 = tle_str.substr(0,69);
  std::string tle_str2 = tle_str.substr(69,69);
  tle.set(tle_str1,tle_str2);

  // 地心赤道直交座標系での射点座標
  ::polar Po = P;
  Po.latitude  *= M_PI / 180.; // degree -> radian
  Po.longitude *= M_PI / 180.; // degree -> radian
  rectangular Pr = Po.toEquatorial(t).toRectangular();
  Eigen::Vector3d P0(Pr.X, Pr.Y, Pr.Z);

  // 軌道
  orbit orb;
  orb.setTLE(&tle);
  double since_day = orb.elapsed_day(t);
  double since_min = since_day * 1440.;
  double since_sec = since_day * 86400.;

  double motion = tle.motion; // revolutions per day
  double dayp6  = 1. / (6. * motion); // day for 1/6 revolution.
  double minp6  = dayp6 * 1440.;
  double secp6  = dayp6 * 86400.;

  // 人工衛星の所在地
  double position0[3],position1[3],position2[3];
  double velocity0[3],velocity1[3],velocity2[3];
  orb.sgp(position0,velocity0,since_min - minp6);
  orb.sgp(position1,velocity1,since_min);
  orb.sgp(position2,velocity2,since_min + minp6);

  Eigen::Vector3d p0(position0);
  Eigen::Vector3d p1(position1); // 人工衛星の現在地の位置ベクトル
  Eigen::Vector3d p2(position2);
  Eigen::Vector3d v1(velocity1);

  Eigen::Vector3d n0 = normalize((p1-p0).cross(p2-p1)); // 軌道面の法線ベクトル
  Eigen::Vector3d n1 = n0.cross(normalize(v1));         // 反射面の法線ベクトル

  Eigen::Vector3d O(0.,0.,0.);
  Eigen::Vector3d R(6378.137,6378.137,6356.752); // 地球楕円体
  Vector3dSet Q = find_impact_point(P0,p1,n1,O,R);

  rectangular Xr;
  bool f = (Q.size() != 0);
  if (f) {
    Eigen::Vector3d q = Q[0];
    Xr.X = q[0];
    Xr.Y = q[1];
    Xr.Z = q[2];
  } else {
    Xr.X = 0.0;
    Xr.Y = 0.0;
    Xr.Z = 0.0;
  }

  ::polar x = Xr.toPolar();
  *X = Xr.toPolar().toGeodetic(t); // 測地座標系に変換
  X->latitude  *= 180. / M_PI;     // radian -> degree
  X->longitude *= 180. / M_PI;     // radian -> degree
  if      ( X->latitude  >  180.) X->latitude  -= 360.;
  else if ( X->latitude  < -180.) X->latitude  += 360.;
  if      ( X->longitude >  180.) X->longitude -= 360.;
  else if ( X->longitude < -180.) X->longitude += 360.;

  return f;
}

<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "maze.h"

TEST (Location, DefaultValueOfHome)
{
  location_t loc = Home();
  EXPECT_EQ (0, loc.row);
  EXPECT_EQ (0, loc.col);
}

TEST (Location, InitialisingGoal_SetToRow7Col8)
{
  location_t loc = Goal();
  EXPECT_EQ (7, loc.row);
  EXPECT_EQ (7, loc.col);
}

TEST (Location, Width_DefaultReturnsMAZE_COLS)
{
  EXPECT_EQ (MAZE_COLS, MazeWidth());
}

TEST (Location, Height_DefaultReturnsMAZE_ROWS)
{
  EXPECT_EQ (MAZE_ROWS, MazeHeight());
}

TEST (Location, SetAndFetchFGoal_SetGoal_ReturnGoal)
{
  location_t newGoal;
  newGoal.row = 3;
  newGoal.col = 4;
  location_t goal;
  SetGoal (newGoal);
  goal = Goal();
  EXPECT_EQ (newGoal.row, goal.row);
  EXPECT_EQ (newGoal.col, goal.col);
}

TEST (Location, FindNeighbour_SeekNORTHNeighbour_GetRowPlus1)
{
  location_t loc;
  loc.row = 5;
  loc.col = 8;
  location_t neighbour;
  neighbour = Neighbour (loc, NORTH);
  EXPECT_EQ (loc.row + 1, neighbour.row);
  EXPECT_EQ (loc.col, neighbour.col);
}

TEST (Location, FindNeighbour_SeekEASTNeighbour_GetColPlus1)
{
  location_t loc;
  loc.row = 5;
  loc.col = 8;
  location_t neighbour;
  neighbour = Neighbour (loc, EAST);
  EXPECT_EQ (loc.row, neighbour.row);
  EXPECT_EQ (loc.col + 1, neighbour.col);
}

TEST (Location, FindNeighbour_SeekSOUTHNeighbour_GetRowMinus1)
{
  location_t loc;
  loc.row = 5;
  loc.col = 8;
  location_t neighbour;
  neighbour = Neighbour (loc, SOUTH);
  EXPECT_EQ (loc.row - 1, neighbour.row);
  EXPECT_EQ (loc.col, neighbour.col);
}

TEST (Location, FindNeighbour_SeekWESTNeighbour_GetColMinus1)
{
  location_t loc;
  loc.row = 5;
  loc.col = 8;
  location_t neighbour;
  neighbour = Neighbour (loc, WEST);
  EXPECT_EQ (loc.row, neighbour.row);
  EXPECT_EQ (loc.col - 1, neighbour.col);
}

TEST (Location, LocationInGoal)
{
  location_t goal = {12, 13};
  SetGoal (goal);
  location_t inGoal = goal;
  location_t notInGoal = {0, 0};
  EXPECT_TRUE (IsGoal (inGoal));
  EXPECT_FALSE (IsGoal (notInGoal));
}

TEST (Location, LocationInHome)
{
  location_t inHome = {0, 0};
  location_t notInHome = {0, 1};
  EXPECT_TRUE (IsHome (inHome));
  EXPECT_FALSE (IsHome (notInHome));
}

TEST (Location, Neighbour_WrapAroundEdges)
{
  location_t loc;
  location_t neighbour;
  loc.col = MazeWidth() - 1;
  loc.row = MazeHeight() - 1;
  EXPECT_EQ (0, Neighbour (loc, NORTH).row);
  EXPECT_EQ (0, Neighbour (loc, EAST).col);
  loc.col = 0;
  loc.row = 0;
  EXPECT_EQ (MazeHeight() - 1, Neighbour (loc, SOUTH).row);
  EXPECT_EQ (MazeWidth() - 1, Neighbour (loc, WEST).col);
}

<commit_msg>Added a test for boundary cases in calculating neighbour locations<commit_after>#include "gtest/gtest.h"
#include "maze.h"

TEST (Location, DefaultValueOfHome)
{
  location_t loc = Home();
  EXPECT_EQ (0, loc.row);
  EXPECT_EQ (0, loc.col);
}

TEST (Location, InitialisingGoal_SetToRow7Col8)
{
  location_t loc = Goal();
  EXPECT_EQ (7, loc.row);
  EXPECT_EQ (7, loc.col);
}

TEST (Location, Width_DefaultReturnsMAZE_COLS)
{
  EXPECT_EQ (MAZE_COLS, MazeWidth());
}

TEST (Location, Height_DefaultReturnsMAZE_ROWS)
{
  EXPECT_EQ (MAZE_ROWS, MazeHeight());
}

TEST (Location, SetAndFetchFGoal_SetGoal_ReturnGoal)
{
  location_t newGoal;
  newGoal.row = 3;
  newGoal.col = 4;
  location_t goal;
  SetGoal (newGoal);
  goal = Goal();
  EXPECT_EQ (newGoal.row, goal.row);
  EXPECT_EQ (newGoal.col, goal.col);
}

TEST (Location, FindNeighbour_SeekNORTHNeighbour_GetRowPlus1)
{
  location_t loc;
  loc.row = 5;
  loc.col = 8;
  location_t neighbour;
  neighbour = Neighbour (loc, NORTH);
  EXPECT_EQ (loc.row + 1, neighbour.row);
  EXPECT_EQ (loc.col, neighbour.col);
}

TEST (Location, FindNeighbour_SeekEASTNeighbour_GetColPlus1)
{
  location_t loc;
  loc.row = 5;
  loc.col = 8;
  location_t neighbour;
  neighbour = Neighbour (loc, EAST);
  EXPECT_EQ (loc.row, neighbour.row);
  EXPECT_EQ (loc.col + 1, neighbour.col);
}

TEST (Location, FindNeighbour_SeekSOUTHNeighbour_GetRowMinus1)
{
  location_t loc;
  loc.row = 5;
  loc.col = 8;
  location_t neighbour;
  neighbour = Neighbour (loc, SOUTH);
  EXPECT_EQ (loc.row - 1, neighbour.row);
  EXPECT_EQ (loc.col, neighbour.col);
}

TEST (Location, FindNeighbour_SeekWESTNeighbour_GetColMinus1)
{
  location_t loc;
  loc.row = 5;
  loc.col = 8;
  location_t neighbour;
  neighbour = Neighbour (loc, WEST);
  EXPECT_EQ (loc.row, neighbour.row);
  EXPECT_EQ (loc.col - 1, neighbour.col);
}

TEST (Location, LocationInGoal)
{
  location_t goal = {12, 13};
  SetGoal (goal);
  location_t inGoal = goal;
  location_t notInGoal = {0, 0};
  EXPECT_TRUE (IsGoal (inGoal));
  EXPECT_FALSE (IsGoal (notInGoal));
}

TEST (Location, LocationInHome)
{
  location_t inHome = {0, 0};
  location_t notInHome = {0, 1};
  EXPECT_TRUE (IsHome (inHome));
  EXPECT_FALSE (IsHome (notInHome));
}

TEST (Location, Neighbour_WrapAroundEdges)
{
  location_t loc;
  location_t neighbour;
  loc.col = MazeWidth() - 1;
  loc.row = MazeHeight() - 1;
  EXPECT_EQ (0, Neighbour (loc, NORTH).row);
  EXPECT_EQ (0, Neighbour (loc, EAST).col);
  loc.col = 0;
  loc.row = 0;
  EXPECT_EQ (MazeHeight() - 1, Neighbour (loc, SOUTH).row);
  EXPECT_EQ (MazeWidth() - 1, Neighbour (loc, WEST).col);
}

TEST (Location, Neighbour_BoundaryCases)
{
  location_t loc;
  location_t neighbour;
  int lastColumn = MazeWidth() -1;
  int lastRow = MazeWidth() -1;
  loc.col = lastColumn - 1;
  loc.row = lastRow - 1;
  EXPECT_EQ (lastRow, Neighbour (loc, NORTH).row);
  EXPECT_EQ (lastColumn, Neighbour (loc, EAST).col);
  loc.col = 1;
  loc.row = 1;
  EXPECT_EQ (0, Neighbour (loc, SOUTH).row);
  EXPECT_EQ (0, Neighbour (loc, WEST).col);
}

<|endoftext|>


<commit_before>#ifndef STAN_TEST_OPENCL_UTIL_HPP
#define STAN_TEST_OPENCL_UTIL_HPP

#include <stan/math.hpp>
#include <stan/math/opencl/rev/opencl.hpp>
#include <test/unit/math/expect_near_rel.hpp>
#include <test/unit/pretty_print_types.hpp>
#include <gtest/gtest.h>
#include <utility>
#include <string>
#include <tuple>

namespace stan {
namespace math {
namespace test {

namespace internal {

template <typename T, require_stan_scalar_t<T>* = nullptr>
T opencl_argument(T&& x) {
  return x;
}
template <typename T, require_not_stan_scalar_t<T>* = nullptr>
auto opencl_argument(const T& x) {
  return to_matrix_cl(x);
}

template <typename T, require_st_same<T, int>* = nullptr>
T var_argument(T&& x) {
  return x;
}
template <typename T, require_not_st_same<T, int>* = nullptr>
auto var_argument(T&& x) {
  return to_var(x);
}

template <typename T, require_arithmetic_t<T>* = nullptr>
void expect_eq(T a, T b, const char* msg) {
  stan::test::expect_near_rel(msg, a, b);
}
void expect_eq(math::var a, math::var b, const char* msg) {
  stan::test::expect_near_rel(msg, a.val(), b.val());
}
template <typename T1, typename T2, require_all_eigen_t<T1, T2>* = nullptr,
          require_all_not_st_var<T1, T2>* = nullptr>
void expect_eq(const T1& a, const T2& b, const char* msg) {
  EXPECT_EQ(a.rows(), b.rows()) << msg;
  EXPECT_EQ(a.cols(), b.cols()) << msg;
  const auto& a_ref = math::to_ref(a);
  const auto& b_ref = math::to_ref(b);
  for (int i = 0; i < a.rows(); i++) {
    for (int j = 0; j < a.cols(); j++) {
      expect_eq(a_ref(i, j), b_ref(i, j), msg);
    }
  }
}
template <typename T1, typename T2, require_all_rev_matrix_t<T1, T2>* = nullptr>
void expect_eq(const T1& a, const T2& b, const char* msg) {
  expect_eq(a.val(), b.val(), msg);
}
template <typename T>
void expect_eq(const std::vector<T>& a, const std::vector<T>& b,
               const char* msg) {
  EXPECT_EQ(a.size(), b.size());
  for (int i = 0; i < a.size(); i++) {
    expect_eq(a[i], b[i], msg);
  }
}
template <typename T1, typename T2,
          require_nonscalar_prim_or_rev_kernel_expression_t<T1>* = nullptr>
void expect_eq(const T1& a, const T2& b, const char* msg) {
  expect_eq(from_matrix_cl(a), b, msg);
}
template <typename T1, typename T2,
          require_nonscalar_prim_or_rev_kernel_expression_t<T2>* = nullptr>
void expect_eq(const T1& a, const T2& b, const char* msg) {
  expect_eq(a, from_matrix_cl(b), msg);
}

template <typename T>
auto recursive_sum(const T& a) {
  return math::sum(a);
}
template <typename T>
auto recursive_sum(const std::vector<T>& a) {
  scalar_type_t<T> res = recursive_sum(a[0]);
  for (int i = 0; i < a.size(); i++) {
    res += recursive_sum(a[i]);
  }
  return res;
}

template <typename T, require_not_st_var<T>* = nullptr>
void expect_adj_near(const T& a, const T& b, const char* msg) {}
void expect_adj_near(var a, var b, const char* msg) {
  stan::test::expect_near_rel(msg, a.adj(), b.adj());
}
template <typename T1, typename T2, require_all_eigen_t<T1, T2>* = nullptr,
          require_vt_same<T1, T2>* = nullptr>
void expect_adj_near(const T1& a, const T2& b, const char* msg) {
  EXPECT_EQ(a.rows(), b.rows()) << msg;
  EXPECT_EQ(a.cols(), b.cols()) << msg;
  const auto& a_ref = math::to_ref(a);
  const auto& b_ref = math::to_ref(b);
  stan::test::expect_near_rel(msg, a_ref.adj(), b_ref.adj());
}
template <typename T>
void expect_adj_near(const std::vector<T>& a, const std::vector<T>& b,
                     const char* msg) {
  EXPECT_EQ(a.size(), b.size()) << msg;
  for (int i = 0; i < a.size(); i++) {
    expect_adj_near(a[i], b[i], msg);
  }
}

template <typename Functor>
void prim_rev_argument_combinations(Functor f) {
  f(std::make_tuple(), std::make_tuple());
}
template <typename Functor, typename Arg0, typename... Args>
void prim_rev_argument_combinations(const Functor& f, const Arg0& arg0,
                                    const Args&... args) {
  prim_rev_argument_combinations(
      [&f, &arg0](auto args_for_cpu, auto args_for_opencl) {
        constexpr size_t Size
            = std::tuple_size<std::decay_t<decltype(args_for_cpu)>>::value;
        return index_apply<Size>([&](auto... Is) {
          return f(
              std::forward_as_tuple(arg0, std::get<Is>(args_for_cpu)...),
              std::forward_as_tuple(arg0, std::get<Is>(args_for_opencl)...));
        });
      },
      args...);
  prim_rev_argument_combinations(
      [&](const auto& args_for_cpu, const auto& args_for_opencl) {
        constexpr size_t Size
            = std::tuple_size<std::decay_t<decltype(args_for_cpu)>>::value;
        return index_apply<Size>([&](auto... Is) {
          return f(std::make_tuple(var_argument(arg0),
                                   std::get<Is>(args_for_cpu)...),
                   std::make_tuple(var_argument(arg0),
                                   std::get<Is>(args_for_opencl)...));
        });
      },
      args...);
}

template <typename Functor, std::size_t... Is, typename... Args>
void compare_cpu_opencl_prim_rev_impl(const Functor& functor,
                                      std::index_sequence<Is...>,
                                      const Args&... args) {
  prim_rev_argument_combinations(
      [&functor](auto args_for_cpu, auto args_for_opencl) {
        auto res_cpu = functor(std::get<Is>(args_for_cpu)...);
        auto res_opencl
            = functor(opencl_argument(std::get<Is>(args_for_opencl))...);
        std::string signature = type_name<decltype(args_for_cpu)>().data();
        expect_eq(res_opencl, res_cpu,
                  ("CPU and OpenCL return values do not match for signature "
                   + signature + "!")
                      .c_str());
        var(recursive_sum(res_cpu) + recursive_sum(res_opencl)).grad();

        static_cast<void>(std::initializer_list<int>{
            (expect_adj_near(
                 std::get<Is>(args_for_opencl), std::get<Is>(args_for_cpu),
                 ("CPU and OpenCL adjoints do not match for argument "
                  + std::to_string(Is) + " for signature " + signature + "!")
                     .c_str()),
             0)...});

        set_zero_all_adjoints();
      },
      args...);
}

}  // namespace internal

/**
 * Tests that given functor calculates same values and adjoints when given
 * arguments on CPU and OpenCL device.
 *
 * @tparam Functor type of the functor
 * @tparam Args types of the arguments
 * @param fucntor functor to test
 * @param args arguments to test the functor with. These should be just values
 * in CPU memory (no vars, no arguments on the OpenCL device).
 */
template <typename Functor, typename... Args>
void compare_cpu_opencl_prim_rev(const Functor& functor, const Args&... args) {
  internal::compare_cpu_opencl_prim_rev_impl(
      functor, std::make_index_sequence<sizeof...(args)>{}, args...);
}

}  // namespace test
}  // namespace math
}  // namespace stan

#endif
<commit_msg>wake up jenkins<commit_after>#ifndef STAN_TEST_OPENCL_UTIL_HPP
#define STAN_TEST_OPENCL_UTIL_HPP

#include <stan/math.hpp>
#include <stan/math/opencl/rev/opencl.hpp>
#include <test/unit/math/expect_near_rel.hpp>
#include <test/unit/pretty_print_types.hpp>
#include <gtest/gtest.h>
#include <utility>
#include <string>
#include <tuple>

namespace stan {
namespace math {
namespace test {

namespace internal {

template <typename T, require_stan_scalar_t<T>* = nullptr>
T opencl_argument(T&& x) {
  return x;
}
template <typename T, require_not_stan_scalar_t<T>* = nullptr>
auto opencl_argument(const T& x) {
  return to_matrix_cl(x);
}

template <typename T, require_st_same<T, int>* = nullptr>
T var_argument(T&& x) {
  return x;
}
template <typename T, require_not_st_same<T, int>* = nullptr>
auto var_argument(T&& x) {
  return to_var(x);
}

template <typename T, require_arithmetic_t<T>* = nullptr>
void expect_eq(T a, T b, const char* msg) {
  stan::test::expect_near_rel(msg, a, b);
}
void expect_eq(math::var a, math::var b, const char* msg) {
  stan::test::expect_near_rel(msg, a.val(), b.val());
}
template <typename T1, typename T2, require_all_eigen_t<T1, T2>* = nullptr,
          require_all_not_st_var<T1, T2>* = nullptr>
void expect_eq(const T1& a, const T2& b, const char* msg) {
  EXPECT_EQ(a.rows(), b.rows()) << msg;
  EXPECT_EQ(a.cols(), b.cols()) << msg;
  const auto& a_ref = math::to_ref(a);
  const auto& b_ref = math::to_ref(b);
  for (int i = 0; i < a.rows(); i++) {
    for (int j = 0; j < a.cols(); j++) {
      expect_eq(a_ref(i, j), b_ref(i, j), msg);
    }
  }
}
template <typename T1, typename T2, require_all_rev_matrix_t<T1, T2>* = nullptr>
void expect_eq(const T1& a, const T2& b, const char* msg) {
  expect_eq(a.val(), b.val(), msg);
}
template <typename T>
void expect_eq(const std::vector<T>& a, const std::vector<T>& b,
               const char* msg) {
  EXPECT_EQ(a.size(), b.size());
  for (int i = 0; i < a.size(); i++) {
    expect_eq(a[i], b[i], msg);
  }
}
template <typename T1, typename T2,
          require_nonscalar_prim_or_rev_kernel_expression_t<T1>* = nullptr>
void expect_eq(const T1& a, const T2& b, const char* msg) {
  expect_eq(from_matrix_cl(a), b, msg);
}
template <typename T1, typename T2,
          require_nonscalar_prim_or_rev_kernel_expression_t<T2>* = nullptr>
void expect_eq(const T1& a, const T2& b, const char* msg) {
  expect_eq(a, from_matrix_cl(b), msg);
}

template <typename T>
auto recursive_sum(const T& a) {
  return math::sum(a);
}
template <typename T>
auto recursive_sum(const std::vector<T>& a) {
  scalar_type_t<T> res = recursive_sum(a[0]);
  for (int i = 0; i < a.size(); i++) {
    res += recursive_sum(a[i]);
  }
  return res;
}

template <typename T, require_not_st_var<T>* = nullptr>
void expect_adj_near(const T& a, const T& b, const char* msg) {}
void expect_adj_near(var a, var b, const char* msg) {
  stan::test::expect_near_rel(msg, a.adj(), b.adj());
}
template <typename T1, typename T2, require_all_eigen_t<T1, T2>* = nullptr,
          require_vt_same<T1, T2>* = nullptr>
void expect_adj_near(const T1& a, const T2& b, const char* msg) {
  EXPECT_EQ(a.rows(), b.rows()) << msg;
  EXPECT_EQ(a.cols(), b.cols()) << msg;
  const auto& a_ref = math::to_ref(a);
  const auto& b_ref = math::to_ref(b);
  stan::test::expect_near_rel(msg, a_ref.adj(), b_ref.adj());
}
template <typename T>
void expect_adj_near(const std::vector<T>& a, const std::vector<T>& b,
                     const char* msg) {
  EXPECT_EQ(a.size(), b.size()) << msg;
  for (int i = 0; i < a.size(); i++) {
    expect_adj_near(a[i], b[i], msg);
  }
}

template <typename Functor>
void prim_rev_argument_combinations(Functor f) {
  f(std::make_tuple(), std::make_tuple());
}
template <typename Functor, typename Arg0, typename... Args>
void prim_rev_argument_combinations(const Functor& f, const Arg0& arg0,
                                    const Args&... args) {
  prim_rev_argument_combinations(
      [&f, &arg0](auto args_for_cpu, auto args_for_opencl) {
        constexpr size_t Size
            = std::tuple_size<std::decay_t<decltype(args_for_cpu)>>::value;
        return index_apply<Size>([&](auto... Is) {
          return f(
              std::forward_as_tuple(arg0, std::get<Is>(args_for_cpu)...),
              std::forward_as_tuple(arg0, std::get<Is>(args_for_opencl)...));
        });
      },
      args...);
  prim_rev_argument_combinations(
      [&](const auto& args_for_cpu, const auto& args_for_opencl) {
        constexpr size_t Size
            = std::tuple_size<std::decay_t<decltype(args_for_cpu)>>::value;
        return index_apply<Size>([&](auto... Is) {
          return f(std::make_tuple(var_argument(arg0),
                                   std::get<Is>(args_for_cpu)...),
                   std::make_tuple(var_argument(arg0),
                                   std::get<Is>(args_for_opencl)...));
        });
      },
      args...);
}

template <typename Functor, std::size_t... Is, typename... Args>
void compare_cpu_opencl_prim_rev_impl(const Functor& functor,
                                      std::index_sequence<Is...>,
                                      const Args&... args) {
  prim_rev_argument_combinations(
      [&functor](auto args_for_cpu, auto args_for_opencl) {
        auto res_cpu = functor(std::get<Is>(args_for_cpu)...);
        auto res_opencl
            = functor(opencl_argument(std::get<Is>(args_for_opencl))...);
        std::string signature = type_name<decltype(args_for_cpu)>().data();
        expect_eq(res_opencl, res_cpu,
                  ("CPU and OpenCL return values do not match for signature "
                   + signature + "!")
                      .c_str());
        var(recursive_sum(res_cpu) + recursive_sum(res_opencl)).grad();

        static_cast<void>(std::initializer_list<int>{
            (expect_adj_near(
                 std::get<Is>(args_for_opencl), std::get<Is>(args_for_cpu),
                 ("CPU and OpenCL adjoints do not match for argument "
                  + std::to_string(Is) + " for signature " + signature + "!")
                     .c_str()),
             0)...});

        set_zero_all_adjoints();
      },
      args...);
}
}  // namespace internal

/**
 * Tests that given functor calculates same values and adjoints when given
 * arguments on CPU and OpenCL device.
 *
 * @tparam Functor type of the functor
 * @tparam Args types of the arguments
 * @param fucntor functor to test
 * @param args arguments to test the functor with. These should be just values
 * in CPU memory (no vars, no arguments on the OpenCL device).
 */
template <typename Functor, typename... Args>
void compare_cpu_opencl_prim_rev(const Functor& functor, const Args&... args) {
  internal::compare_cpu_opencl_prim_rev_impl(
      functor, std::make_index_sequence<sizeof...(args)>{}, args...);
}

}  // namespace test
}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>// Create command

#include "SAMdisk.h"

bool CreateImage (const std::string &path, Range range)
{
	auto disk = std::make_shared<Disk>();

	ValidateRange(range, NORMAL_TRACKS, NORMAL_SIDES);

	Format fmt;
	fmt.cyls = range.cyls();
	fmt.heads = range.heads();

	// Are we allowed to format?
	if (!opt.noformat)
	{
		// Set up the format for ProDos or MGT, with automatic gap3 size
		fmt = opt.cpm ? RegularFormat::ProDos : RegularFormat::MGT;
		fmt.gap3 = 0;

		// Prevent CP/M wrapping during image write
		opt.cpm = 0;

		// Set the disk label, if supplied
//		if (opt.label)
//			disk->strDiskLabel = opt.label;

		// To ensure it fits by default, halve the sector count in FM mode
		if (opt.fm == 1) fmt.sectors >>= 1;

		// Allow everything about the format to be overridden
		OverrideFormat(fmt, true);

		// Check sector count and size
		ValidateGeometry(1, 1, fmt.sectors, fmt.size, 7);

		disk->format(fmt);
	}

	// Write to the output disk image
	WriteImage(path, disk);

	auto cyls = disk->cyls();
	auto heads = disk->heads();

	// Report the new disk parameters
	if (opt.noformat)
		util::cout << util::fmt("Created %2u cyl%s, %u head%s, unformatted.\n", cyls, (cyls == 1) ? "" : "s", heads, (heads == 1) ? "" : "s");
	else
	{
		util::cout << util::fmt("Created %2u cyl%s, %u head%s, %2u sector%s/track, %4u bytes/sector\n",
								cyls, (cyls == 1) ? "" : "s", heads, (heads == 1) ? "" : "s",
								fmt.sectors, (fmt.sectors == 1) ? "" : "s", fmt.sector_size());
	}

	return true;
}

bool CreateHddImage (const std::string &path, int nSizeMB_)
{
	bool f = false;

	// If no sector count is specified, use the size parameter
	int64_t llSize = (opt.sectors == -1) ? nSizeMB_ << 20 : opt.sectors << 9;
	if (llSize < 4 * 1024 * 1024)
		throw util::exception("needs image size in MB (>=4) or sector count with -s");

	// Create the specified HDD image, ensuring we don't overwrite any existing file
	auto hdd = HDD::CreateDisk(path, llSize, nullptr, false);
	if (!hdd)
		Error("create");
	else
	{
		// Zero-fill up to the required sector count
		f = hdd->Copy(nullptr, hdd->total_sectors, 0, 0, 0, "Creating");

		// If anything went wrong, remove the new file
		if (!f)
			unlink(path.c_str());
	}

	return f;
}
<commit_msg>Fixed HDF creation clipping size to 32-bit<commit_after>// Create command

#include "SAMdisk.h"

bool CreateImage (const std::string &path, Range range)
{
	auto disk = std::make_shared<Disk>();

	ValidateRange(range, NORMAL_TRACKS, NORMAL_SIDES);

	Format fmt;
	fmt.cyls = range.cyls();
	fmt.heads = range.heads();

	// Are we allowed to format?
	if (!opt.noformat)
	{
		// Set up the format for ProDos or MGT, with automatic gap3 size
		fmt = opt.cpm ? RegularFormat::ProDos : RegularFormat::MGT;
		fmt.gap3 = 0;

		// Prevent CP/M wrapping during image write
		opt.cpm = 0;

		// Set the disk label, if supplied
//		if (opt.label)
//			disk->strDiskLabel = opt.label;

		// To ensure it fits by default, halve the sector count in FM mode
		if (opt.fm == 1) fmt.sectors >>= 1;

		// Allow everything about the format to be overridden
		OverrideFormat(fmt, true);

		// Check sector count and size
		ValidateGeometry(1, 1, fmt.sectors, fmt.size, 7);

		disk->format(fmt);
	}

	// Write to the output disk image
	WriteImage(path, disk);

	auto cyls = disk->cyls();
	auto heads = disk->heads();

	// Report the new disk parameters
	if (opt.noformat)
		util::cout << util::fmt("Created %2u cyl%s, %u head%s, unformatted.\n", cyls, (cyls == 1) ? "" : "s", heads, (heads == 1) ? "" : "s");
	else
	{
		util::cout << util::fmt("Created %2u cyl%s, %u head%s, %2u sector%s/track, %4u bytes/sector\n",
								cyls, (cyls == 1) ? "" : "s", heads, (heads == 1) ? "" : "s",
								fmt.sectors, (fmt.sectors == 1) ? "" : "s", fmt.sector_size());
	}

	return true;
}

bool CreateHddImage (const std::string &path, int nSizeMB_)
{
	bool f = false;

	// If no sector count is specified, use the size parameter
	auto total_size = (opt.sectors == -1) ?
		static_cast<int64_t>(nSizeMB_) << 20 :
		static_cast<int64_t>(opt.sectors) << 9;

	if (total_size < 4 * 1024 * 1024)
		throw util::exception("needs image size in MB (>=4) or sector count with -s");

	// Create the specified HDD image, ensuring we don't overwrite any existing file
	auto hdd = HDD::CreateDisk(path, total_size, nullptr, false);
	if (!hdd)
		Error("create");
	else
	{
		// Zero-fill up to the required sector count
		f = hdd->Copy(nullptr, hdd->total_sectors, 0, 0, 0, "Creating");

		// If anything went wrong, remove the new file
		if (!f)
			unlink(path.c_str());
	}

	return f;
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2015-2017, Deutsches Forschungszentrum für Künstliche Intelligenz GmbH.
// Copyright (c) 2015-2017, University of Bremen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * 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.
//
#define BOOST_TEST_MODULE VizTest
#include <boost/test/included/unit_test.hpp>
#include <boost/archive/polymorphic_binary_oarchive.hpp>

#include <Eigen/Geometry>

#include "StandaloneVisualizer.hpp"
#include <maps/grid/MLSMap.hpp>

#include <maps/operations/CoverageMapGeneration.hpp>

using namespace ::maps::grid;

template<class MLSMap>
static void show_MLS(const MLSMap& mls)
{
    std::cout << "update finish" << std::endl;
    StandaloneVisualizer app;
    app.updateData(mls);

    while (app.wait(1000))
    {
    }
}

BOOST_AUTO_TEST_CASE(mls_loop)
{
    //    GridConfig conf(150, 150, 0.1, 0.1, -7.5, -7.5);
    Eigen::Vector2d res(0.1, 0.1);
    Vector2ui numCells(150, 150);

    MLSConfig mls_config;
    mls_config.updateModel = MLSConfig::KALMAN;
    mls_config.gapSize = 0.05f;
    mls_config.useNegativeInformation = false;
    float R = 5.0f, r=2.05f;
    MLSMapKalman mls(numCells, res, mls_config);

    maps::operations::CoverageTracker coverage;

    mls.getLocalFrame().translation() << 0.5*mls.getSize(), 0;

    coverage.setFrame(mls);

    StandaloneVisualizer app;

    Eigen::ArrayXXd ranges;
    PointCloud pointcloud;
    base::Pose trafo;
    int loop = 0;
    while (app.wait(1000))
    {
        if(++loop & 1023) continue;
        trafo.position +=Eigen::Vector3d::Random() * 0.5;
        Eigen::Quaterniond q; q.coeffs().setRandom(); q.normalize();
        trafo.orientation = q;

        coverage.addCoverage(2.0, base::AngleSegment(), trafo);

        app.updateData(coverage.getCoverage());
    }
}

<commit_msg>fix warnings and renamed test case<commit_after>//
// Copyright (c) 2015-2017, Deutsches Forschungszentrum für Künstliche Intelligenz GmbH.
// Copyright (c) 2015-2017, University of Bremen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// * 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.
//
#define BOOST_TEST_MODULE VizTest
#include <boost/test/included/unit_test.hpp>
#include <boost/archive/polymorphic_binary_oarchive.hpp>

#include <Eigen/Geometry>

#include "StandaloneVisualizer.hpp"
#include <maps/grid/MLSMap.hpp>

#include <maps/operations/CoverageMapGeneration.hpp>

using namespace ::maps::grid;

template<class MLSMap>
static void show_MLS(const MLSMap& mls)
{
    std::cout << "update finish" << std::endl;
    StandaloneVisualizer app;
    app.updateData(mls);

    while (app.wait(1000))
    {
    }
}

BOOST_AUTO_TEST_CASE(mls_coverage)
{
    //    GridConfig conf(150, 150, 0.1, 0.1, -7.5, -7.5);
    Eigen::Vector2d res(0.1, 0.1);
    Vector2ui numCells(150, 150);

    MLSConfig mls_config;
    mls_config.updateModel = MLSConfig::KALMAN;
    mls_config.gapSize = 0.05f;
    mls_config.useNegativeInformation = false;
    MLSMapKalman mls(numCells, res, mls_config);

    maps::operations::CoverageTracker coverage;

    mls.getLocalFrame().translation() << 0.5*mls.getSize(), 0;

    coverage.setFrame(mls);

    StandaloneVisualizer app;

    Eigen::ArrayXXd ranges;
    PointCloud pointcloud;
    base::Pose trafo;
    int loop = 0;
    while (app.wait(1000))
    {
        if(++loop & 1023) continue;
        trafo.position +=Eigen::Vector3d::Random() * 0.5;
        Eigen::Quaterniond q; q.coeffs().setRandom(); q.normalize();
        trafo.orientation = q;

        coverage.addCoverage(2.0, base::AngleSegment(), trafo);

        app.updateData(coverage.getCoverage());
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2015
// Ravi Peters -- r.y.peters@tudelft.nl
// All rights reserved
// This file is part of masbcpp.
//
// masbcpp is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// masbcpp is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with masbcpp.  If not, see <http://www.gnu.org/licenses/>.

// #define VERBOSEPRINT 1;
// #define WITH_OPENMP 1;

#include <iostream>
#include <fstream>
#include <string>

// OpenMP
#ifdef WITH_OPENMP
    #ifdef CLANG_OMP
        #include <libiomp/omp.h>
    #else
        #include <omp.h>
    #endif
#endif

// Vrui
#include <vrui/Geometry/ComponentArray.h>
#include <vrui/Math/Math.h>
#include <vrui/Misc/Timer.h>
// kdtree2
#include <kdtree2/kdtree2.hpp>
// cnpy
#include <cnpy/cnpy.h>
// tclap
#include <tclap/CmdLine.h>

// typedefs
#include "types.h"

// globals
Scalar initial_radius;
double denoise_preserve;
double denoise_planar;
const Scalar delta_convergance = 1E-5;
const uint iteration_limit = 30;

inline Scalar compute_radius(Point &p, Vector &n, Point &q)
{
    // this is basic goniometry
    double d = Geometry::mag(p-q);
    Scalar cos_theta = ( n * (p-q) ) / d;
    return d/(2*cos_theta);
}

inline Scalar cos_angle(Vector p, Vector q)
{
    // Calculate the cosine of angle between vector p and q, see http://en.wikipedia.org/wiki/Law_of_cosines#Vector_formulation
    Scalar result = p*q / ( Geometry::mag(p) * Geometry::mag(q) );
    if( result > 1 ) return 1;
    else if( result < -1 ) return -1;
    return result;
}

Point sb_point(Point &p, Vector &n, kdtree2::KDTree* kd_tree)
{
    uint j=0;
    Scalar r, r_previous = 0;
    Point q, c_next;
    Point c = p - n * initial_radius;

    while (1)
    {
        #ifdef VERBOSEPRINT
        std::cout << "\nloop iteration: " << j << ", p = (" << p[0] << "," << p[1] << "," << p[2] << ", n = (" << n[0] << "," << n[1] << "," << n[2] << ") \n";

        std::cout << "c = (" << c[0] << "," << c[1] << "," << c[2] << ")\n";
        #endif

        // find closest point to c
        kdtree2::KDTreeResultVector result;
        kd_tree->n_nearest(c,2,result);
        q = kd_tree->the_data[ result[0].idx ];

        #ifdef VERBOSEPRINT
        std::cout << "q = (" << q[0] << "," << q[1] << "," << q[2] << ")\n";
        #endif

        // handle case when q==p
        if( q == p )
        {
            // 1) if r_previous==SuperR, apparantly no other points on the halfspace spanned by -n => that's an infinite ball
            if( r_previous == initial_radius )
            {
                r = initial_radius;
                break;
            // 2) otherwise just pick the second closest point
            } else {
                q = kd_tree->the_data[ result[1].idx ];
            }
        }

        // compute radius
        r = compute_radius(p,n,q);

        #ifdef VERBOSEPRINT
        std::cout << "r = " << r << "\n";
        #endif

        // if r < 0 closest point was on the wrong side of plane with normal n => start over with SuperRadius on the right side of that plane
        if( r < 0 )
            r = initial_radius;
        // if r > SuperR, stop now because otherwise in case of planar surface point configuration, we end up in an infinite loop
        else if( r > initial_radius )
        {
            r = initial_radius;
            break;
        }

        // compute next ball center
        c_next = p - n * r;

        // denoising
        if( denoise_preserve or denoise_planar )
        {
            Scalar a = cos_angle(p-c_next, q-c_next);
            Scalar separation_angle = Math::acos(a);

            if( denoise_preserve and ( separation_angle < denoise_preserve and j>0 and r > Geometry::mag(q-p) ) )
            {
                // keep previous radius:
                r = r_previous;
                break;
            }
            if( denoise_planar and ( separation_angle < denoise_planar and j==0 ) )
            {
                r = initial_radius;
                break;
            }
        }

        // stop iteration if r has converged
        if( Math::abs(r_previous-r) < delta_convergance )
            break;

        // stop iteration if this looks like an infinite loop:
        if( j > iteration_limit )
            break;

        r_previous = r;
        c = c_next;
        j++;

    }

    return c;
}

PointList sb_points(PointList &points, VectorList &normals, kdtree2::KDTree* kd_tree, bool inner=1)
{
    PointList ma_coords(points.size());
    Point p;
    Vector n;

    #pragma omp parallel for private(p, n)
    for( uint i=0; i<points.size(); i++ )
    {
        p = points[i];
        if( inner )
            n = normals[i];
        else
            n = -normals[i];
        ma_coords[i] = sb_point(p, n, kd_tree);
    }
    return ma_coords;
}

int main(int argc, char **argv)
{
    // parse command line arguments
    try {
        TCLAP::CmdLine cmd("Computes a MAT point approximation", ' ', "0.1");

        TCLAP::UnlabeledValueArg<std::string> inputArg( "input", "path to directory with inside it a 'coords.npy' and a 'normals.npy' file", true, "", "input dir", cmd);
        TCLAP::UnlabeledValueArg<std::string> outputArg( "ouput", "path to output directory", true, "", "output dir", cmd);

        TCLAP::ValueArg<double> denoise_preserveArg("d","preserve","denoise preserve threshold",false,20,"double", cmd);
        TCLAP::ValueArg<double> denoise_planarArg("p","planar","denoise planar threshold",false,32,"double", cmd);
        TCLAP::ValueArg<double> initial_radiusArg("r","radius","initial ball radius",false,200,"double", cmd);

        cmd.parse(argc,argv);

        initial_radius = initial_radiusArg.getValue();
        denoise_preserve = (3.1415/180) * denoise_preserveArg.getValue();
        denoise_planar = (3.1415/180) * denoise_planarArg.getValue();

        std::string input_coords_path = inputArg.getValue()+"/coords.npy";
        std::string input_normals_path = inputArg.getValue()+"/normals.npy";

        // check for proper in-output arguments
        {
            std::ifstream infile(input_coords_path.c_str());
            if(!infile)
                throw TCLAP::ArgParseException("invalid filepath", inputArg.getValue());
        }
        {
            std::ifstream infile(input_normals_path.c_str());
            if(!infile)
                throw TCLAP::ArgParseException("invalid filepath", inputArg.getValue());
        }
        {
            std::string output_path = outputArg.getValue()+"/ma_coords_in.npy";
            std::ofstream outfile(output_path.c_str());
            if(!outfile)
                throw TCLAP::ArgParseException("invalid filepath", outputArg.getValue());
        }

        std::cout << "Parameters: denoise_preserve="<<denoise_preserve<<", denoise_planar="<<denoise_planar<<", initial_radius="<<initial_radius<<"\n";

        cnpy::NpyArray coords_npy = cnpy::npy_load( input_coords_path.c_str() );
        float* coords_carray = reinterpret_cast<float*>(coords_npy.data);

        uint num_points = coords_npy.shape[0];
        uint dim = coords_npy.shape[1];
        PointList coords(num_points);
        for ( int i=0; i<num_points; i++) coords[i] = Point(&coords_carray[i*3]);
        coords_npy.destruct();

        cnpy::NpyArray normals_npy = cnpy::npy_load( input_normals_path.c_str() );
        float* normals_carray = reinterpret_cast<float*>(normals_npy.data);
        VectorList normals(normals_npy.shape[0]);
        for ( int i=0; i<num_points; i++) normals[i] = Vector(&normals_carray[i*3]);
        normals_npy.destruct();

        Misc::Timer t0;
        kdtree2::KDTree* kd_tree;
        kd_tree = new kdtree2::KDTree(coords,true);
        kd_tree->sort_results = true;
        t0.elapse();
        std::cout<<"Constructed kd-tree in "<<t0.getTime()*1000.0<<" ms"<<std::endl;

        // omp_set_num_threads(4);

        {
            Scalar* ma_coords_in_carray = new Scalar[num_points*3];
            Misc::Timer t1;
            PointList ma_coords_in = sb_points(coords, normals, kd_tree, 1);
            t1.elapse();
            std::cout<<"Done shrinking interior balls, took "<<t1.getTime()*1000.0<<" ms"<<std::endl;

            for (int i=0; i<ma_coords_in.size(); i++)
                for (int j=0; j<3; j++)
                    ma_coords_in_carray[i*3+j] = ma_coords_in[i][j];

            const unsigned int c_size = ma_coords_in.size();
            const unsigned int shape[] = {c_size,3};
            cnpy::npy_save((outputArg.getValue()+"/ma_coords_in.npy").c_str(), ma_coords_in_carray, shape, 2, "w");
        }

        {
            Scalar* ma_coords_out_carray = new Scalar[num_points*3];
            Misc::Timer t2;
            PointList ma_coords_out = sb_points(coords, normals, kd_tree, 0);
            t2.elapse();
            std::cout<<"Done shrinking exterior balls, took "<<t2.getTime()*1000.0<<" ms"<<std::endl;

            for (int i=0; i<ma_coords_out.size(); i++)
                for (int j=0; j<3; j++)
                    ma_coords_out_carray[i*3+j] = ma_coords_out[i][j];

            const unsigned int c_size = ma_coords_out.size();
            const unsigned int shape[] = {c_size,3};
            cnpy::npy_save((outputArg.getValue()+"/ma_coords_out.npy").c_str(), ma_coords_out_carray, shape, 2, "w");
        }

    } catch (TCLAP::ArgException &e) { std::cerr << "Error: " << e.error() << " for " << e.argId() << std::endl; }

    return 0;
}
<commit_msg>handle invalid MA points properly with float nan's<commit_after>// Copyright (c) 2015
// Ravi Peters -- r.y.peters@tudelft.nl
// All rights reserved
// This file is part of masbcpp.
//
// masbcpp is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// masbcpp is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with masbcpp.  If not, see <http://www.gnu.org/licenses/>.

// #define VERBOSEPRINT 1;
// #define WITH_OPENMP 1;

#include <iostream>
#include <fstream>
#include <string>
#include <limits>

// OpenMP
#ifdef WITH_OPENMP
    #ifdef CLANG_OMP
        #include <libiomp/omp.h>
    #else
        #include <omp.h>
    #endif
#endif

// Vrui
#include <vrui/Geometry/ComponentArray.h>
#include <vrui/Math/Math.h>
#include <vrui/Misc/Timer.h>
// kdtree2
#include <kdtree2/kdtree2.hpp>
// cnpy
#include <cnpy/cnpy.h>
// tclap
#include <tclap/CmdLine.h>

// typedefs
#include "types.h"

// globals
Scalar initial_radius;
double denoise_preserve;
double denoise_planar;
const Scalar delta_convergance = 1E-5;
const uint iteration_limit = 30;
const Point nanPoint( std::numeric_limits<Scalar>::quiet_NaN() );

inline Scalar compute_radius(Point &p, Vector &n, Point &q)
{
    // this is basic goniometry
    double d = Geometry::mag(p-q);
    Scalar cos_theta = ( n * (p-q) ) / d;
    return d/(2*cos_theta);
}

inline Scalar cos_angle(Vector p, Vector q)
{
    // Calculate the cosine of angle between vector p and q, see http://en.wikipedia.org/wiki/Law_of_cosines#Vector_formulation
    Scalar result = p*q / ( Geometry::mag(p) * Geometry::mag(q) );
    if( result > 1 ) return 1;
    else if( result < -1 ) return -1;
    return result;
}

Point sb_point(Point &p, Vector &n, kdtree2::KDTree* kd_tree)
{
    uint j=0;
    Scalar r, r_previous = 0;
    Point q, c_next;
    Point c = p - n * initial_radius;

    while (1)
    {
        #ifdef VERBOSEPRINT
        std::cout << "\nloop iteration: " << j << ", p = (" << p[0] << "," << p[1] << "," << p[2] << ", n = (" << n[0] << "," << n[1] << "," << n[2] << ") \n";

        std::cout << "c = (" << c[0] << "," << c[1] << "," << c[2] << ")\n";
        #endif

        // find closest point to c
        kdtree2::KDTreeResultVector result;
        kd_tree->n_nearest(c,2,result);
        q = kd_tree->the_data[ result[0].idx ];

        #ifdef VERBOSEPRINT
        std::cout << "q = (" << q[0] << "," << q[1] << "," << q[2] << ")\n";
        #endif

        // handle case when q==p
        if( q == p )
        {
            // 1) if r_previous==SuperR, apparantly no other points on the halfspace spanned by -n => that's an infinite ball
            if( r_previous == initial_radius )
            {
                r = initial_radius;
                c = nanPoint;
                break;
            // 2) otherwise just pick the second closest point
            } else {
                q = kd_tree->the_data[ result[1].idx ];
            }
        }

        // compute radius
        r = compute_radius(p,n,q);

        #ifdef VERBOSEPRINT
        std::cout << "r = " << r << "\n";
        #endif

        // if r < 0 closest point was on the wrong side of plane with normal n => start over with SuperRadius on the right side of that plane
        if( r < 0 )
            r = initial_radius;
        // if r > SuperR, stop now because otherwise in case of planar surface point configuration, we end up in an infinite loop
        else if( r > initial_radius )
        {
            r = initial_radius;
            c = nanPoint;
            break;
        }

        // compute next ball center
        c_next = p - n * r;

        // denoising
        if( denoise_preserve or denoise_planar )
        {
            Scalar a = cos_angle(p-c_next, q-c_next);
            Scalar separation_angle = Math::acos(a);

            if( denoise_preserve and ( separation_angle < denoise_preserve and j>0 and r > Geometry::mag(q-p) ) )
            {
                // keep previous radius:
                r = r_previous;
                break;
            }
            if( denoise_planar and ( separation_angle < denoise_planar and j==0 ) )
            {
                r = initial_radius;
                c = nanPoint;
                break;
            }
        }

        // stop iteration if r has converged
        if( Math::abs(r_previous-r) < delta_convergance )
            break;

        // stop iteration if this looks like an infinite loop:
        if( j > iteration_limit )
            break;

        r_previous = r;
        c = c_next;
        j++;
    }

    return c;
}

PointList sb_points(PointList &points, VectorList &normals, kdtree2::KDTree* kd_tree, bool inner=1)
{
    PointList ma_coords(points.size());
    Point p;
    Vector n;

    #pragma omp parallel for private(p, n)
    for( uint i=0; i<points.size(); i++ )
    {
        p = points[i];
        if( inner )
            n = normals[i];
        else
            n = -normals[i];
        ma_coords[i] = sb_point(p, n, kd_tree);
    }
    return ma_coords;
}

int main(int argc, char **argv)
{
    // parse command line arguments
    try {
        TCLAP::CmdLine cmd("Computes a MAT point approximation", ' ', "0.1");

        TCLAP::UnlabeledValueArg<std::string> inputArg( "input", "path to directory with inside it a 'coords.npy' and a 'normals.npy' file", true, "", "input dir", cmd);
        TCLAP::UnlabeledValueArg<std::string> outputArg( "ouput", "path to output directory", true, "", "output dir", cmd);

        TCLAP::ValueArg<double> denoise_preserveArg("d","preserve","denoise preserve threshold",false,20,"double", cmd);
        TCLAP::ValueArg<double> denoise_planarArg("p","planar","denoise planar threshold",false,32,"double", cmd);
        TCLAP::ValueArg<double> initial_radiusArg("r","radius","initial ball radius",false,200,"double", cmd);

        cmd.parse(argc,argv);

        initial_radius = initial_radiusArg.getValue();
        denoise_preserve = (3.1415/180) * denoise_preserveArg.getValue();
        denoise_planar = (3.1415/180) * denoise_planarArg.getValue();

        std::string input_coords_path = inputArg.getValue()+"/coords.npy";
        std::string input_normals_path = inputArg.getValue()+"/normals.npy";

        // check for proper in-output arguments
        {
            std::ifstream infile(input_coords_path.c_str());
            if(!infile)
                throw TCLAP::ArgParseException("invalid filepath", inputArg.getValue());
        }
        {
            std::ifstream infile(input_normals_path.c_str());
            if(!infile)
                throw TCLAP::ArgParseException("invalid filepath", inputArg.getValue());
        }
        {
            std::string output_path = outputArg.getValue()+"/ma_coords_in.npy";
            std::ofstream outfile(output_path.c_str());
            if(!outfile)
                throw TCLAP::ArgParseException("invalid filepath", outputArg.getValue());
        }

        std::cout << "Parameters: denoise_preserve="<<denoise_preserve<<", denoise_planar="<<denoise_planar<<", initial_radius="<<initial_radius<<"\n";

        cnpy::NpyArray coords_npy = cnpy::npy_load( input_coords_path.c_str() );
        float* coords_carray = reinterpret_cast<float*>(coords_npy.data);

        uint num_points = coords_npy.shape[0];
        uint dim = coords_npy.shape[1];
        PointList coords(num_points);
        for ( int i=0; i<num_points; i++) coords[i] = Point(&coords_carray[i*3]);
        coords_npy.destruct();

        cnpy::NpyArray normals_npy = cnpy::npy_load( input_normals_path.c_str() );
        float* normals_carray = reinterpret_cast<float*>(normals_npy.data);
        VectorList normals(normals_npy.shape[0]);
        for ( int i=0; i<num_points; i++) normals[i] = Vector(&normals_carray[i*3]);
        normals_npy.destruct();

        Misc::Timer t0;
        kdtree2::KDTree* kd_tree;
        kd_tree = new kdtree2::KDTree(coords,true);
        kd_tree->sort_results = true;
        t0.elapse();
        std::cout<<"Constructed kd-tree in "<<t0.getTime()*1000.0<<" ms"<<std::endl;

        // omp_set_num_threads(4);

        {
            Scalar* ma_coords_in_carray = new Scalar[num_points*3];
            Misc::Timer t1;
            PointList ma_coords_in = sb_points(coords, normals, kd_tree, 1);
            t1.elapse();
            std::cout<<"Done shrinking interior balls, took "<<t1.getTime()*1000.0<<" ms"<<std::endl;

            for (int i=0; i<ma_coords_in.size(); i++)
                for (int j=0; j<3; j++)
                    ma_coords_in_carray[i*3+j] = ma_coords_in[i][j];

            const unsigned int c_size = ma_coords_in.size();
            const unsigned int shape[] = {c_size,3};
            cnpy::npy_save((outputArg.getValue()+"/ma_coords_in.npy").c_str(), ma_coords_in_carray, shape, 2, "w");
        }

        {
            Scalar* ma_coords_out_carray = new Scalar[num_points*3];
            Misc::Timer t2;
            PointList ma_coords_out = sb_points(coords, normals, kd_tree, 0);
            t2.elapse();
            std::cout<<"Done shrinking exterior balls, took "<<t2.getTime()*1000.0<<" ms"<<std::endl;

            for (int i=0; i<ma_coords_out.size(); i++)
                for (int j=0; j<3; j++)
                    ma_coords_out_carray[i*3+j] = ma_coords_out[i][j];

            const unsigned int c_size = ma_coords_out.size();
            const unsigned int shape[] = {c_size,3};
            cnpy::npy_save((outputArg.getValue()+"/ma_coords_out.npy").c_str(), ma_coords_out_carray, shape, 2, "w");
        }

    } catch (TCLAP::ArgException &e) { std::cerr << "Error: " << e.error() << " for " << e.argId() << std::endl; }

    return 0;
}
<|endoftext|>


<commit_before>//===-- shm.cpp -----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Save/restore via shared memory to survive exec*()
//
//===----------------------------------------------------------------------===//

#include "shm.h"

#include "ipcreg_internal.h"
#include "magic_socket_nums.h"
#include "real.h"
#include "rename_fd.h"

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define UC(ret, msg) \
  unixCheck(ret, msg, __FILE__, __LINE__, __PRETTY_FUNCTION__);

void unixCheck(int ret, const char *msg, const char *file, unsigned line,
               const char *func, int err = errno) {
  if (ret == -1) {
    ipclog("Unix call failed in %s at %s:%u: %s - %s\n", func, file, line, msg,
           strerror(err));
    abort();
  }
}

static char buf[100];
const char *getShmName() {
  sprintf(buf, "/ipcd.%d\n", getpid());
  return buf;
}

int get_shm(int flags, mode_t mode) {
  int fd = shm_open(getShmName(), flags, mode);
  if (fd == -1 && errno == EEXIST) {
    ipclog("Shared memory segment exists, attempting to remove it...\n");
    int ret = shm_unlink(getShmName());
    UC(ret, "Closing existing shm");

    // Okay, let's try this again
    fd = shm_open(getShmName(), flags, mode);
  }
  UC(fd, "shm_open");
  UC(fchmod(fd, mode), "fchmod on shared memory segment");
  return fd;
}

void shm_state_save() {
  // Create shared memory segment
  int fd = get_shm(O_RDWR | O_CREAT | O_EXCL, 0777);
  UC(fd, "get_shm");

  bool success = rename_fd(fd, MAGIC_SHM_FD, /* cloexec */ false);
  assert(success && "Failed to rename SHM fd!");

  // Do *not* close on exec! :)
  int flags = __real_fcntl(MAGIC_SHM_FD, F_GETFD, /* kludge */ 0);
  assert(flags >= 0);
  flags &= ~FD_CLOEXEC;
  int ret = __real_fcntl_int(MAGIC_SHM_FD, F_SETFD, flags);
  UC(ret, "fcntl CLOEXEC on shared memory segment");

  // Size the memory segment:
  ret = ftruncate(MAGIC_SHM_FD, sizeof(libipc_state));
  UC(ret, "ftruncate on shm");

  void *stateptr = mmap(NULL, sizeof(libipc_state), PROT_READ | PROT_WRITE,
                  MAP_SHARED, MAGIC_SHM_FD, 0);
  assert(stateptr != MAP_FAILED);

  // Copy state to shared memory segment
  *(libipc_state*)stateptr = state;

  // Unmap, but don't unlink the shared memory
  ret = munmap(stateptr, sizeof(libipc_state));
  UC(ret, "unmap shm");

  ipclog("State saved!\n");
}

bool is_valid_fd(int fd) {
  return __real_fcntl(fd, F_GETFD, /* kludge */ 0) >= 0;
}

void shm_state_restore() {
  // If we have memory to restore, it'll be in our magic FD!
  if (!is_valid_fd(MAGIC_SHM_FD))
    return;

  ipclog("Inherited ipc state FD, starting state restoration...\n");

  void *stateptr = mmap(NULL, sizeof(libipc_state), PROT_READ | PROT_WRITE,
                        MAP_SHARED, MAGIC_SHM_FD, 0);
  // If our FD is still open, the memory better still be there!
  assert(stateptr != MAP_FAILED);

  // Copy state to shared memory segment
  // Copy state from shared memory segment
  state = *(libipc_state*)stateptr;

  int ret = munmap(stateptr, sizeof(libipc_state));
  UC(ret, "unmap shm");

  // Done with the shared segment, thank you!
  ret = __real_close(MAGIC_SHM_FD);
  UC(ret, "close shm");
  ret = shm_unlink(getShmName());
  UC(ret, "shm_unlink after close");

  ipclog("State restored!\n");
}

void shm_state_destroy() {
  // If we have memory to restore, it'll be in our magic FD!
  assert(is_valid_fd(MAGIC_SHM_FD));

  int ret = __real_close(MAGIC_SHM_FD);
  assert(ret == 0);

  ret = shm_unlink(getShmName());
  UC(ret, "shm_unlink");

  ipclog("Destroyed saved state!\n");
}
<commit_msg>libipc: Issue shm_unlink while still open, hopefully fix perm issues.<commit_after>//===-- shm.cpp -----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Save/restore via shared memory to survive exec*()
//
//===----------------------------------------------------------------------===//

#include "shm.h"

#include "ipcreg_internal.h"
#include "magic_socket_nums.h"
#include "real.h"
#include "rename_fd.h"

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define UC(ret, msg) \
  unixCheck(ret, msg, __FILE__, __LINE__, __PRETTY_FUNCTION__);

void unixCheck(int ret, const char *msg, const char *file, unsigned line,
               const char *func, int err = errno) {
  if (ret == -1) {
    ipclog("Unix call failed in %s at %s:%u: %s - %s\n", func, file, line, msg,
           strerror(err));
    abort();
  }
}

static char buf[100];
const char *getShmName() {
  sprintf(buf, "/ipcd.%d\n", getpid());
  return buf;
}

int get_shm(int flags, mode_t mode) {
  int fd = shm_open(getShmName(), flags, mode);
  if (fd == -1 && errno == EEXIST) {
    ipclog("Shared memory segment exists, attempting to remove it...\n");
    int ret = shm_unlink(getShmName());
    UC(ret, "Closing existing shm");

    // Okay, let's try this again
    fd = shm_open(getShmName(), flags, mode);
  }
  UC(fd, "shm_open");
  UC(fchmod(fd, mode), "fchmod on shared memory segment");
  return fd;
}

void shm_state_save() {
  // Create shared memory segment
  int fd = get_shm(O_RDWR | O_CREAT | O_EXCL, 0400);
  UC(fd, "get_shm");

  bool success = rename_fd(fd, MAGIC_SHM_FD, /* cloexec */ false);
  assert(success && "Failed to rename SHM fd!");

  // Do *not* close on exec! :)
  int flags = __real_fcntl(MAGIC_SHM_FD, F_GETFD, /* kludge */ 0);
  assert(flags >= 0);
  flags &= ~FD_CLOEXEC;
  int ret = __real_fcntl_int(MAGIC_SHM_FD, F_SETFD, flags);
  UC(ret, "fcntl CLOEXEC on shared memory segment");

  // Size the memory segment:
  ret = ftruncate(MAGIC_SHM_FD, sizeof(libipc_state));
  UC(ret, "ftruncate on shm");

  void *stateptr = mmap(NULL, sizeof(libipc_state), PROT_READ | PROT_WRITE,
                  MAP_SHARED, MAGIC_SHM_FD, 0);
  assert(stateptr != MAP_FAILED);

  // Copy state to shared memory segment
  *(libipc_state*)stateptr = state;

  // Unmap memory, we're done with it
  ret = munmap(stateptr, sizeof(libipc_state));
  UC(ret, "unmap shm");

  // Issue request to unlink the memory,
  // but this won't occur until our fd is closed.
  // (which we leave open intentionally)
  ret = shm_unlink(getShmName());
  UC(ret, "eager shm_unlink");

  ipclog("State saved!\n");
}

bool is_valid_fd(int fd) {
  return __real_fcntl(fd, F_GETFD, /* kludge */ 0) >= 0;
}

void shm_state_restore() {
  // If we have memory to restore, it'll be in our magic FD!
  if (!is_valid_fd(MAGIC_SHM_FD))
    return;

  ipclog("Inherited ipc state FD, starting state restoration...\n");

  void *stateptr = mmap(NULL, sizeof(libipc_state), PROT_READ | PROT_WRITE,
                        MAP_SHARED, MAGIC_SHM_FD, 0);
  // If our FD is still open, the memory better still be there!
  assert(stateptr != MAP_FAILED);

  // Copy state to shared memory segment
  // Copy state from shared memory segment
  state = *(libipc_state*)stateptr;

  int ret = munmap(stateptr, sizeof(libipc_state));
  UC(ret, "unmap shm");

  // Done with the shared segment, thank you!
  ret = __real_close(MAGIC_SHM_FD);
  UC(ret, "close shm");

  ipclog("State restored!\n");
}

void shm_state_destroy() {
  // If we have memory to restore, it'll be in our magic FD!
  assert(is_valid_fd(MAGIC_SHM_FD));

  int ret = __real_close(MAGIC_SHM_FD);
  assert(ret == 0);

  ipclog("Destroyed saved state!\n");
}
<|endoftext|>


<commit_before><commit_msg>A friend declaration is not an actual declaration of the function. icc seem 'mean' about it.<commit_after><|endoftext|>