<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
#ifndef IOX_HOOFS_UNITS_DURATION_HPP
#define IOX_HOOFS_UNITS_DURATION_HPP

#include "iceoryx_hoofs/cxx/expected.hpp"
#include "iceoryx_hoofs/platform/time.hpp" // required for QNX

#include <chrono>
#include <cmath>
#include <iostream>
#include <numeric>

namespace iox
{
namespace units
{
enum class TimeSpecReference : uint8_t
{
    None,
    Epoch,
    Monotonic
};

class Duration;

namespace duration_literals
{
/// @brief Constructs a new Duration object from nanoseconds
constexpr Duration operator"" _ns(unsigned long long int) noexcept; // PRQA S 48

/// @brief Constructs a new Duration object from microseconds
constexpr Duration operator"" _us(unsigned long long int) noexcept; // PRQA S 48

/// @brief Constructs a new Duration object from milliseconds
constexpr Duration operator"" _ms(unsigned long long int) noexcept; // PRQA S 48

/// @brief Constructs a new Duration object from seconds
constexpr Duration operator"" _s(unsigned long long int) noexcept; // PRQA S 48

/// @brief Constructs a new Duration object from minutes
constexpr Duration operator"" _m(unsigned long long int) noexcept; // PRQA S 48

/// @brief Constructs a new Duration object from hours
constexpr Duration operator"" _h(unsigned long long int) noexcept; // PRQA S 48

/// @brief Constructs a new Duration object from days
constexpr Duration operator"" _d(unsigned long long int) noexcept; // PRQA S 48
} // namespace duration_literals

/// @code
///   #include <iostream>
///   // ...
///   using namespace units;
///   using namespace units::duration_literals;
///   auto someDays = 2 * 7_d + 5_ns;
///   auto someSeconds = 42_s + 500_ms;
///   std::cout << someDays << std::endl;
///   std::cout << someDays.nanoSeconds<uint64_t>() << " ns" << std::endl;
///   std::cout << someSeconds.milliSeconds<int64_t>() << " ms" << std::endl;
/// @endcode
class Duration
{
  public:
    // BEGIN CREATION FROM STATIC FUNCTIONS

    /// @brief Constructs a new Duration object from nanoseconds
    /// @tparam T is an integer type for the value
    /// @param[in] value as nanoseconds
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromNanoseconds(const T value) noexcept;

    /// @brief Constructs a new Duration object from microseconds
    /// @tparam T is an integer type for the value
    /// @param[in] value as microseconds
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromMicroseconds(const T value) noexcept;

    /// @brief Constructs a new Duration object from milliseconds
    /// @tparam T is an integer type for the value
    /// @param[in] value as milliseconds
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromMilliseconds(const T value) noexcept;

    /// @brief Constructs a new Duration object from seconds
    /// @tparam T is an integer type for the value
    /// @param[in] value as seconds
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromSeconds(const T value) noexcept;

    /// @brief Constructs a new Duration object from minutes
    /// @tparam T is an integer type for the value
    /// @param[in] value as minutes
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromMinutes(const T value) noexcept;

    /// @brief Constructs a new Duration object from hours
    /// @tparam T is an integer type for the value
    /// @param[in] value as hours
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromHours(const T value) noexcept;

    /// @brief Constructs a new Duration object from days
    /// @tparam T is an integer type for the value
    /// @param[in] value as days
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromDays(const T value) noexcept;

    /// @brief Constructs a new Duration object of maximum allowed length. Useful for functions which should have an
    /// "infinite" timeout.
    static constexpr Duration max() noexcept;

    /// @brief Constructs a new Duration object with a duration of zero
    static constexpr Duration zero() noexcept;
    // END CREATION FROM STATIC FUNCTIONS

    // BEGIN CONSTRUCTORS AND ASSIGNMENT

    /// @brief Construct a Duration object from timeval
    /// @param[in] value as timeval
    constexpr explicit Duration(const struct timeval& value) noexcept;

    /// @brief Construct a Duration object from timespec
    /// @param[in] value as timespec
    constexpr explicit Duration(const struct timespec& value) noexcept;

    /// @brief Construct a Duration object from itimerspec
    /// @param[in] value as itimerspec
    /// @note only it_interval from the itimerspec is used
    constexpr explicit Duration(const struct itimerspec& value) noexcept;

    /// @brief Construct a Duration object from std::chrono::milliseconds
    /// @param[in] value as milliseconds
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    constexpr explicit Duration(const std::chrono::milliseconds& value) noexcept;

    /// @brief Construct a Duration object from std::chrono::nanoseconds
    /// @param[in] value as nanoseconds
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    constexpr explicit Duration(const std::chrono::nanoseconds& value) noexcept;

    /// @brief Assigns a std::chrono::milliseconds to an duration object
    /// @param[in] rhs is the right hand side of the assignment
    /// @return a reference to the Duration object with the assigned millisecond value
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    Duration& operator=(const std::chrono::milliseconds& rhs) noexcept;

    // END CONSTRUCTORS AND ASSIGNMENT

    // BEGIN COMPARISON

    /// @brief Equal to operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration equal to rhs
    constexpr bool operator==(const Duration& rhs) const noexcept;

    /// @brief Not equal to operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration not equal to rhs
    constexpr bool operator!=(const Duration& rhs) const noexcept;

    /// @brief Less than operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration is less than rhs
    constexpr bool operator<(const Duration& rhs) const noexcept;

    /// @brief Less than or equal to operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration is less than or equal to rhs
    constexpr bool operator<=(const Duration& rhs) const noexcept;

    /// @brief Greater than operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration is greater than rhs
    constexpr bool operator>(const Duration& rhs) const noexcept;

    /// @brief Greater than or equal to operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration is greater than or equal to rhs
    constexpr bool operator>=(const Duration& rhs) const noexcept;

    // END COMPARISON

    // BEGIN ARITHMETIC

    /// @brief Creates Duration object by addition. On overflow duration
    ///        saturates to Duration::max().
    /// @param[in] rhs is the second summand
    /// @return a new Duration object
    constexpr Duration operator+(const Duration& rhs) const noexcept;

    /// @brief Creates Duration object by subtraction. On underflow duration
    ///        saturates to Duration::zero().
    /// @param[in] rhs is the subtrahend
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    constexpr Duration operator-(const Duration& rhs) const noexcept;

    /// @brief Creates Duration object by multiplication.
    /// @tparam T is an arithmetic type for the multiplicator
    /// @param[in] rhs is the multiplicator
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    /// @note A duration of 0 will always result in 0, no matter if multiplied with NaN or +Inf
    /// @note There is no explicit division operator! This can be achieved by multiplication with the inverse of the
    /// divisor.
    /// @note Multiplication of a non-zero duration with NaN and +Inf results in a saturated max duration
    template <typename T>
    constexpr Duration operator*(const T& rhs) const noexcept;

    // END ARITHMETIC

    // BEGIN CONVERSION

    /// @brief returns the duration in nanoseconds
    /// @note If the duration in nanoseconds is larger than an uint64_t can represent, it will be clamped to the
    /// uint64_t max value.
    constexpr uint64_t toNanoseconds() const noexcept;

    /// @brief returns the duration in microseconds
    /// @note If the duration in microseconds is larger than an uint64_t can represent, it will be clamped to the
    /// uint64_t max value.
    /// @note The remaining nanoseconds are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toMicroseconds() const noexcept;

    /// @brief returns the duration in milliseconds
    /// @note If the duration in milliseconds is larger than an uint64_t can represent, it will be clamped to the
    /// uint64_t max value.
    /// @note The remaining microseconds are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toMilliseconds() const noexcept;

    /// @brief returns the duration in seconds
    /// @note The remaining milliseconds are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toSeconds() const noexcept;

    /// @brief returns the duration in minutes
    /// @note The remaining seconds are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toMinutes() const noexcept;

    /// @brief returns the duration in hours
    /// @note The remaining minutes are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toHours() const noexcept;

    /// @brief returns the duration in days
    /// @note The remaining hours are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toDays() const noexcept;

    /// @brief converts duration in a timespec c struct
    struct timespec timespec(const TimeSpecReference& reference = TimeSpecReference::None) const noexcept;

    /// @brief converts duration in a timeval c struct
    ///     timeval::tv_sec = seconds since the Epoch (01.01.1970)
    ///     timeval::tv_usec = microseconds
    constexpr struct timeval timeval() const noexcept;

    // END CONVERSION

    friend constexpr Duration duration_literals::operator"" _ns(unsigned long long int) noexcept; // PRQA S 48
    friend constexpr Duration duration_literals::operator"" _us(unsigned long long int) noexcept; // PRQA S 48
    friend constexpr Duration duration_literals::operator"" _ms(unsigned long long int) noexcept; // PRQA S 48
    friend constexpr Duration duration_literals::operator"" _s(unsigned long long int) noexcept;  // PRQA S 48
    friend constexpr Duration duration_literals::operator"" _m(unsigned long long int) noexcept;  // PRQA S 48
    friend constexpr Duration duration_literals::operator"" _h(unsigned long long int) noexcept;  // PRQA S 48
    friend constexpr Duration duration_literals::operator"" _d(unsigned long long int) noexcept;  // PRQA S 48

    template <typename T>
    friend constexpr Duration operator*(const T& lhs, const Duration& rhs) noexcept;

    friend std::ostream& operator<<(std::ostream& stream, const Duration& t) noexcept;

    static constexpr uint32_t SECS_PER_MINUTE{60U};
    static constexpr uint32_t SECS_PER_HOUR{3600U};
    static constexpr uint32_t HOURS_PER_DAY{24U};

    static constexpr uint32_t MILLISECS_PER_SEC{1000U};
    static constexpr uint32_t MICROSECS_PER_SEC{MILLISECS_PER_SEC * 1000U};

    static constexpr uint32_t NANOSECS_PER_MICROSEC{1000U};
    static constexpr uint32_t NANOSECS_PER_MILLISEC{NANOSECS_PER_MICROSEC * 1000U};
    static constexpr uint32_t NANOSECS_PER_SEC{NANOSECS_PER_MILLISEC * 1000U};

  protected:
    using Seconds_t = uint64_t;
    using Nanoseconds_t = uint32_t;

    /// @brief Constructs a Duration from seconds and nanoseconds
    /// @param[in] seconds portion of the duration
    /// @param[in] nanoseconds portion of the duration
    /// @note this is protected to be able to use it in unit tests
    constexpr Duration(const Seconds_t seconds, const Nanoseconds_t nanoseconds) noexcept;

    /// @note this is factory method is necessary to build with msvc due to issues calling a protected constexpr ctor
    /// from public methods
    static constexpr Duration createDuration(const Seconds_t seconds, const Nanoseconds_t nanoseconds) noexcept;

  private:
    template <typename T, typename String>
    static constexpr unsigned long long int positiveValueOrClampToZero(const T value, const String fromMethod) noexcept;

    template <typename T>
    constexpr Duration fromFloatingPointSeconds(const T floatingPointSeconds) const noexcept;
    template <typename From, typename To>
    constexpr bool wouldCastFromFloatingPointProbablyOverflow(const From floatingPoint) const noexcept;

    template <typename T>
    constexpr Duration multiplyWith(const std::enable_if_t<!std::is_floating_point<T>::value, T>& rhs) const noexcept;

    template <typename T>
    constexpr Duration multiplyWith(const std::enable_if_t<std::is_floating_point<T>::value, T>& rhs) const noexcept;

  private:
    Seconds_t m_seconds{0U};
    Nanoseconds_t m_nanoseconds{0U};
};

/// @brief creates Duration object by multiplying object T with a duration. On overflow
///        duration will saturate to Duration::max()
/// @tparam T is an arithmetic type for the multiplicator
/// @param[in] lhs is the multiplicator
/// @param[in] rhs is the multiplicant
/// @return a new Duration object
/// @attention Since negative durations are not allowed, the duration will be clamped to 0
template <typename T>
constexpr Duration operator*(const T& lhs, const Duration& rhs) noexcept;

/// @brief stream operator for the Duration class
std::ostream& operator<<(std::ostream& stream, const Duration& t) noexcept;

} // namespace units
} // namespace iox

#include "iceoryx_hoofs/internal/units/duration.inl"

#endif // IOX_HOOFS_UNITS_DURATION_HPP
<commit_msg>iox-#1196 Add paramenter name to function declaration<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
#ifndef IOX_HOOFS_UNITS_DURATION_HPP
#define IOX_HOOFS_UNITS_DURATION_HPP

#include "iceoryx_hoofs/cxx/expected.hpp"
#include "iceoryx_hoofs/platform/time.hpp" // required for QNX

#include <chrono>
#include <cmath>
#include <iostream>
#include <numeric>

namespace iox
{
namespace units
{
enum class TimeSpecReference : uint8_t
{
    None,
    Epoch,
    Monotonic
};

class Duration;

namespace duration_literals
{
/// @brief Constructs a new Duration object from nanoseconds
constexpr Duration operator"" _ns(unsigned long long int value) noexcept;

/// @brief Constructs a new Duration object from microseconds
constexpr Duration operator"" _us(unsigned long long int value) noexcept;

/// @brief Constructs a new Duration object from milliseconds
constexpr Duration operator"" _ms(unsigned long long int value) noexcept;

/// @brief Constructs a new Duration object from seconds
constexpr Duration operator"" _s(unsigned long long int value) noexcept;

/// @brief Constructs a new Duration object from minutes
constexpr Duration operator"" _m(unsigned long long int value) noexcept;

/// @brief Constructs a new Duration object from hours
constexpr Duration operator"" _h(unsigned long long int value) noexcept;

/// @brief Constructs a new Duration object from days
constexpr Duration operator"" _d(unsigned long long intvalue) noexcept;
} // namespace duration_literals

/// @code
///   #include <iostream>
///   // ...
///   using namespace units;
///   using namespace units::duration_literals;
///   auto someDays = 2 * 7_d + 5_ns;
///   auto someSeconds = 42_s + 500_ms;
///   std::cout << someDays << std::endl;
///   std::cout << someDays.nanoSeconds<uint64_t>() << " ns" << std::endl;
///   std::cout << someSeconds.milliSeconds<int64_t>() << " ms" << std::endl;
/// @endcode
class Duration
{
  public:
    // BEGIN CREATION FROM STATIC FUNCTIONS

    /// @brief Constructs a new Duration object from nanoseconds
    /// @tparam T is an integer type for the value
    /// @param[in] value as nanoseconds
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromNanoseconds(const T value) noexcept;

    /// @brief Constructs a new Duration object from microseconds
    /// @tparam T is an integer type for the value
    /// @param[in] value as microseconds
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromMicroseconds(const T value) noexcept;

    /// @brief Constructs a new Duration object from milliseconds
    /// @tparam T is an integer type for the value
    /// @param[in] value as milliseconds
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromMilliseconds(const T value) noexcept;

    /// @brief Constructs a new Duration object from seconds
    /// @tparam T is an integer type for the value
    /// @param[in] value as seconds
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromSeconds(const T value) noexcept;

    /// @brief Constructs a new Duration object from minutes
    /// @tparam T is an integer type for the value
    /// @param[in] value as minutes
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromMinutes(const T value) noexcept;

    /// @brief Constructs a new Duration object from hours
    /// @tparam T is an integer type for the value
    /// @param[in] value as hours
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromHours(const T value) noexcept;

    /// @brief Constructs a new Duration object from days
    /// @tparam T is an integer type for the value
    /// @param[in] value as days
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    template <typename T>
    static constexpr Duration fromDays(const T value) noexcept;

    /// @brief Constructs a new Duration object of maximum allowed length. Useful for functions which should have an
    /// "infinite" timeout.
    static constexpr Duration max() noexcept;

    /// @brief Constructs a new Duration object with a duration of zero
    static constexpr Duration zero() noexcept;
    // END CREATION FROM STATIC FUNCTIONS

    // BEGIN CONSTRUCTORS AND ASSIGNMENT

    /// @brief Construct a Duration object from timeval
    /// @param[in] value as timeval
    constexpr explicit Duration(const struct timeval& value) noexcept;

    /// @brief Construct a Duration object from timespec
    /// @param[in] value as timespec
    constexpr explicit Duration(const struct timespec& value) noexcept;

    /// @brief Construct a Duration object from itimerspec
    /// @param[in] value as itimerspec
    /// @note only it_interval from the itimerspec is used
    constexpr explicit Duration(const struct itimerspec& value) noexcept;

    /// @brief Construct a Duration object from std::chrono::milliseconds
    /// @param[in] value as milliseconds
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    constexpr explicit Duration(const std::chrono::milliseconds& value) noexcept;

    /// @brief Construct a Duration object from std::chrono::nanoseconds
    /// @param[in] value as nanoseconds
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    constexpr explicit Duration(const std::chrono::nanoseconds& value) noexcept;

    /// @brief Assigns a std::chrono::milliseconds to an duration object
    /// @param[in] rhs is the right hand side of the assignment
    /// @return a reference to the Duration object with the assigned millisecond value
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    Duration& operator=(const std::chrono::milliseconds& rhs) noexcept;

    // END CONSTRUCTORS AND ASSIGNMENT

    // BEGIN COMPARISON

    /// @brief Equal to operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration equal to rhs
    constexpr bool operator==(const Duration& rhs) const noexcept;

    /// @brief Not equal to operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration not equal to rhs
    constexpr bool operator!=(const Duration& rhs) const noexcept;

    /// @brief Less than operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration is less than rhs
    constexpr bool operator<(const Duration& rhs) const noexcept;

    /// @brief Less than or equal to operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration is less than or equal to rhs
    constexpr bool operator<=(const Duration& rhs) const noexcept;

    /// @brief Greater than operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration is greater than rhs
    constexpr bool operator>(const Duration& rhs) const noexcept;

    /// @brief Greater than or equal to operator
    /// @param[in] rhs is the right hand side of the comparison
    /// @return true if duration is greater than or equal to rhs
    constexpr bool operator>=(const Duration& rhs) const noexcept;

    // END COMPARISON

    // BEGIN ARITHMETIC

    /// @brief Creates Duration object by addition. On overflow duration
    ///        saturates to Duration::max().
    /// @param[in] rhs is the second summand
    /// @return a new Duration object
    constexpr Duration operator+(const Duration& rhs) const noexcept;

    /// @brief Creates Duration object by subtraction. On underflow duration
    ///        saturates to Duration::zero().
    /// @param[in] rhs is the subtrahend
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    constexpr Duration operator-(const Duration& rhs) const noexcept;

    /// @brief Creates Duration object by multiplication.
    /// @tparam T is an arithmetic type for the multiplicator
    /// @param[in] rhs is the multiplicator
    /// @return a new Duration object
    /// @attention Since negative durations are not allowed, the duration will be clamped to 0
    /// @note A duration of 0 will always result in 0, no matter if multiplied with NaN or +Inf
    /// @note There is no explicit division operator! This can be achieved by multiplication with the inverse of the
    /// divisor.
    /// @note Multiplication of a non-zero duration with NaN and +Inf results in a saturated max duration
    template <typename T>
    constexpr Duration operator*(const T& rhs) const noexcept;

    // END ARITHMETIC

    // BEGIN CONVERSION

    /// @brief returns the duration in nanoseconds
    /// @note If the duration in nanoseconds is larger than an uint64_t can represent, it will be clamped to the
    /// uint64_t max value.
    constexpr uint64_t toNanoseconds() const noexcept;

    /// @brief returns the duration in microseconds
    /// @note If the duration in microseconds is larger than an uint64_t can represent, it will be clamped to the
    /// uint64_t max value.
    /// @note The remaining nanoseconds are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toMicroseconds() const noexcept;

    /// @brief returns the duration in milliseconds
    /// @note If the duration in milliseconds is larger than an uint64_t can represent, it will be clamped to the
    /// uint64_t max value.
    /// @note The remaining microseconds are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toMilliseconds() const noexcept;

    /// @brief returns the duration in seconds
    /// @note The remaining milliseconds are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toSeconds() const noexcept;

    /// @brief returns the duration in minutes
    /// @note The remaining seconds are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toMinutes() const noexcept;

    /// @brief returns the duration in hours
    /// @note The remaining minutes are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toHours() const noexcept;

    /// @brief returns the duration in days
    /// @note The remaining hours are truncated, similar to the casting behavior of a float to an int.
    constexpr uint64_t toDays() const noexcept;

    /// @brief converts duration in a timespec c struct
    struct timespec timespec(const TimeSpecReference& reference = TimeSpecReference::None) const noexcept;

    /// @brief converts duration in a timeval c struct
    ///     timeval::tv_sec = seconds since the Epoch (01.01.1970)
    ///     timeval::tv_usec = microseconds
    constexpr struct timeval timeval() const noexcept;

    // END CONVERSION

    friend constexpr Duration duration_literals::operator"" _ns(unsigned long long int value) noexcept;
    friend constexpr Duration duration_literals::operator"" _us(unsigned long long int value) noexcept;
    friend constexpr Duration duration_literals::operator"" _ms(unsigned long long int value) noexcept;
    friend constexpr Duration duration_literals::operator"" _s(unsigned long long int value) noexcept;
    friend constexpr Duration duration_literals::operator"" _m(unsigned long long int value) noexcept;
    friend constexpr Duration duration_literals::operator"" _h(unsigned long long int value) noexcept;
    friend constexpr Duration duration_literals::operator"" _d(unsigned long long int value) noexcept;

    template <typename T>
    friend constexpr Duration operator*(const T& lhs, const Duration& rhs) noexcept;

    friend std::ostream& operator<<(std::ostream& stream, const Duration& t) noexcept;

    static constexpr uint32_t SECS_PER_MINUTE{60U};
    static constexpr uint32_t SECS_PER_HOUR{3600U};
    static constexpr uint32_t HOURS_PER_DAY{24U};

    static constexpr uint32_t MILLISECS_PER_SEC{1000U};
    static constexpr uint32_t MICROSECS_PER_SEC{MILLISECS_PER_SEC * 1000U};

    static constexpr uint32_t NANOSECS_PER_MICROSEC{1000U};
    static constexpr uint32_t NANOSECS_PER_MILLISEC{NANOSECS_PER_MICROSEC * 1000U};
    static constexpr uint32_t NANOSECS_PER_SEC{NANOSECS_PER_MILLISEC * 1000U};

  protected:
    using Seconds_t = uint64_t;
    using Nanoseconds_t = uint32_t;

    /// @brief Constructs a Duration from seconds and nanoseconds
    /// @param[in] seconds portion of the duration
    /// @param[in] nanoseconds portion of the duration
    /// @note this is protected to be able to use it in unit tests
    constexpr Duration(const Seconds_t seconds, const Nanoseconds_t nanoseconds) noexcept;

    /// @note this is factory method is necessary to build with msvc due to issues calling a protected constexpr ctor
    /// from public methods
    static constexpr Duration createDuration(const Seconds_t seconds, const Nanoseconds_t nanoseconds) noexcept;

  private:
    template <typename T, typename String>
    static constexpr unsigned long long int positiveValueOrClampToZero(const T value, const String fromMethod) noexcept;

    template <typename T>
    constexpr Duration fromFloatingPointSeconds(const T floatingPointSeconds) const noexcept;
    template <typename From, typename To>
    constexpr bool wouldCastFromFloatingPointProbablyOverflow(const From floatingPoint) const noexcept;

    template <typename T>
    constexpr Duration multiplyWith(const std::enable_if_t<!std::is_floating_point<T>::value, T>& rhs) const noexcept;

    template <typename T>
    constexpr Duration multiplyWith(const std::enable_if_t<std::is_floating_point<T>::value, T>& rhs) const noexcept;

  private:
    Seconds_t m_seconds{0U};
    Nanoseconds_t m_nanoseconds{0U};
};

/// @brief creates Duration object by multiplying object T with a duration. On overflow
///        duration will saturate to Duration::max()
/// @tparam T is an arithmetic type for the multiplicator
/// @param[in] lhs is the multiplicator
/// @param[in] rhs is the multiplicant
/// @return a new Duration object
/// @attention Since negative durations are not allowed, the duration will be clamped to 0
template <typename T>
constexpr Duration operator*(const T& lhs, const Duration& rhs) noexcept;

/// @brief stream operator for the Duration class
std::ostream& operator<<(std::ostream& stream, const Duration& t) noexcept;

} // namespace units
} // namespace iox

#include "iceoryx_hoofs/internal/units/duration.inl"

#endif // IOX_HOOFS_UNITS_DURATION_HPP
<|endoftext|>


<commit_before>#include "openlcb/If.hxx"
#include "address.h"

extern const openlcb::NodeID NODE_ID;
const openlcb::NodeID NODE_ID = 0x050101011400ULL | NODEID_LOW_BITS;
extern const uint16_t DEFAULT_ALIAS;
const uint16_t DEFAULT_ALIAS = 0x400 | NODEID_LOW_BITS;

#define BOOTLOADER_DATAGRAM
#include "openlcb/Bootloader.hxx"
<commit_msg>Adds support for nodeid high bits.<commit_after>#include "openlcb/If.hxx"
#include "address.h"

#ifndef NODEID_HIGH_BITS
#define NODEID_HIGH_BITS 0x18
#endif

extern const openlcb::NodeID NODE_ID;
const openlcb::NodeID NODE_ID = 0x050101010000ULL | (NODEID_HIGH_BITS << 8) | NODEID_LOW_BITS;
extern const uint16_t DEFAULT_ALIAS;
const uint16_t DEFAULT_ALIAS = 0x400 | NODEID_LOW_BITS;

#define BOOTLOADER_DATAGRAM
#include "openlcb/Bootloader.hxx"
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2013, Balazs Racz
 * 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.
 *
 * \file main.cxx
 *
 * Main file for the io board application on the Tiva Launchpad board.
 *
 * @author Balazs Racz
 * @date 5 Jun 2015
 */

#include "os/os.h"
#include "nmranet_config.h"

#include "nmranet/SimpleStack.hxx"
#include "nmranet/ConfiguredConsumer.hxx"
#include "nmranet/ConfiguredProducer.hxx"

#include "freertos_drivers/ti/TivaGPIO.hxx"
#include "freertos_drivers/common/BlinkerGPIO.hxx"
#include "config.hxx"
#include "hardware.hxx"

// These preprocessor symbols are used to select which physical connections
// will be enabled in the main(). See @ref appl_main below.
#define SNIFF_ON_SERIAL
//#define SNIFF_ON_USB
//#define HAVE_PHYSICAL_CAN_PORT

// Changes the default behavior by adding a newline after each gridconnect
// packet. Makes it easier for debugging the raw device.
OVERRIDE_CONST(gc_generate_newlines, 1);
// Specifies how much RAM (in bytes) we allocate to the stack of the main
// thread. Useful tuning parameter in case the application runs out of memory.
OVERRIDE_CONST(main_thread_stack_size, 2500);

// Specifies the 48-bit OpenLCB node identifier. This must be unique for every
// hardware manufactured, so in production this should be replaced by some
// easily incrementable method.
extern const nmranet::NodeID NODE_ID = 0x050101011412ULL;

// Sets up a comprehensive OpenLCB stack for a single virtual node. This stack
// contains everything needed for a usual peripheral node -- all
// CAN-bus-specific components, a virtual node, PIP, SNIP, Memory configuration
// protocol, ACDI, CDI, a bunch of memory spaces, etc.
nmranet::SimpleCanStack stack(NODE_ID);

// ConfigDef comes from config.hxx and is specific to the particular device and
// target. It defines the layout of the configuration memory space and is also
// used to generate the cdi.xml file. Here we instantiate the configuration
// layout. The argument of offset zero is ignored and will be removed later.
nmranet::ConfigDef cfg(0);
// Defines weak constants used by the stack to tell it which device contains
// the volatile configuration information. This device name appears in
// HwInit.cxx that creates the device drivers.
extern const char *const nmranet::CONFIG_FILENAME = "/dev/eeprom";
// The size of the memory space to export over the above device.
extern const size_t nmranet::CONFIG_FILE_SIZE =
    cfg.seg().size() + cfg.seg().offset();
static_assert(nmranet::CONFIG_FILE_SIZE <= 300, "Need to adjust eeprom size");
// The SNIP user-changeable information in also stored in the above eeprom
// device. In general this could come from different eeprom segments, but it is
// simpler to keep them together.
extern const char *const nmranet::SNIP_DYNAMIC_FILENAME =
    nmranet::CONFIG_FILENAME;

// Defines the GPIO ports used for the producers and the consumers.

// The first LED is driven by the blinker device from BlinkerGPIO.hxx. We just
// create an alias for symmetry.
typedef BLINKER_Pin LED_RED_Pin;

// Instantiates the actual producer and consumer objects for the given GPIO
// pins from above. The ConfiguredConsumer class takes care of most of the
// complicated setup and operation requirements. We need to give it the virtual
// node pointer, the configuration configuration from the CDI definition, and
// the hardware pin definition. The virtual node pointer comes from the stack
// object. The configuration structure comes from the CDI definition object,
// segment 'seg', in which there is a repeated group 'consumers', and we assign
// the individual entries to the individual consumers. Each consumer gets its
// own GPIO pin.
nmranet::ConfiguredConsumer consumer_red(
    stack.node(), cfg.seg().consumers().entry<0>(), LED_RED_Pin());
nmranet::ConfiguredConsumer consumer_green(
    stack.node(), cfg.seg().consumers().entry<1>(), LED_GREEN_Pin());
nmranet::ConfiguredConsumer consumer_blue(
    stack.node(), cfg.seg().consumers().entry<2>(), LED_BLUE_Pin());

// Similar syntax for the producers.
nmranet::ConfiguredProducer producer_sw1(
    stack.node(), cfg.seg().producers().entry<0>(), SW1_Pin());
nmranet::ConfiguredProducer producer_sw2(
    stack.node(), cfg.seg().producers().entry<1>(), SW2_Pin());

// The producers need to be polled repeatedly for changes and to execute the
// debouncing algorithm. This class instantiates a refreshloop and adds the two
// producers to it.
nmranet::RefreshLoop loop(
    stack.node(), {producer_sw1.polling(), producer_sw2.polling()});

/** Entry point to application.
 * @param argc number of command line arguments
 * @param argv array of command line arguments
 * @return 0, should never return
 */
int appl_main(int argc, char *argv[])
{
    // The necessary physical ports must be added to the stack.
    //
    // It is okay to enable multiple physical ports, in which case the stack
    // will behave as a bridge between them. For example enabling both the
    // physical CAN port and the USB port will make this firmware act as an
    // USB-CAN adapter in addition to the producers/consumers created above.
    //
    // If a port is enabled, it must be functional or else the stack will
    // freeze waiting for that port to send the packets out.
#if defined(HAVE_PHYSICAL_CAN_PORT)
    stack.add_can_port_select("/dev/can0");
#endif
#if defined(SNIFF_ON_USB)
    stack.add_gridconnect_port("/dev/serUSB0");
#endif
#if defined(SNIFF_ON_SERIAL)
    stack.add_gridconnect_port("/dev/ser0");
#endif

    // This command donates the main thread to the operation of the
    // stack. Alternatively the stack could be started in a separate stack and
    // then application-specific business logic could be executed ion a busy
    // loop in the main thread.
    stack.loop_executor();
    return 0;
}
<commit_msg>Updates io_board target tm4c123 to use the MultiConfiguredConsumer object.<commit_after>/** \copyright
 * Copyright (c) 2013, Balazs Racz
 * 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.
 *
 * \file main.cxx
 *
 * Main file for the io board application on the Tiva Launchpad board.
 *
 * @author Balazs Racz
 * @date 5 Jun 2015
 */

#include "os/os.h"
#include "nmranet_config.h"

#include "nmranet/SimpleStack.hxx"
#include "nmranet/ConfiguredConsumer.hxx"
#include "nmranet/MultiConfiguredConsumer.hxx"
#include "nmranet/ConfiguredProducer.hxx"

#include "freertos_drivers/ti/TivaGPIO.hxx"
#include "freertos_drivers/common/BlinkerGPIO.hxx"
#include "config.hxx"
#include "hardware.hxx"

// These preprocessor symbols are used to select which physical connections
// will be enabled in the main(). See @ref appl_main below.
#define SNIFF_ON_SERIAL
//#define SNIFF_ON_USB
//#define HAVE_PHYSICAL_CAN_PORT

// Changes the default behavior by adding a newline after each gridconnect
// packet. Makes it easier for debugging the raw device.
OVERRIDE_CONST(gc_generate_newlines, 1);
// Specifies how much RAM (in bytes) we allocate to the stack of the main
// thread. Useful tuning parameter in case the application runs out of memory.
OVERRIDE_CONST(main_thread_stack_size, 2500);

// Specifies the 48-bit OpenLCB node identifier. This must be unique for every
// hardware manufactured, so in production this should be replaced by some
// easily incrementable method.
extern const nmranet::NodeID NODE_ID = 0x050101011412ULL;

// Sets up a comprehensive OpenLCB stack for a single virtual node. This stack
// contains everything needed for a usual peripheral node -- all
// CAN-bus-specific components, a virtual node, PIP, SNIP, Memory configuration
// protocol, ACDI, CDI, a bunch of memory spaces, etc.
nmranet::SimpleCanStack stack(NODE_ID);

// ConfigDef comes from config.hxx and is specific to the particular device and
// target. It defines the layout of the configuration memory space and is also
// used to generate the cdi.xml file. Here we instantiate the configuration
// layout. The argument of offset zero is ignored and will be removed later.
nmranet::ConfigDef cfg(0);
// Defines weak constants used by the stack to tell it which device contains
// the volatile configuration information. This device name appears in
// HwInit.cxx that creates the device drivers.
extern const char *const nmranet::CONFIG_FILENAME = "/dev/eeprom";
// The size of the memory space to export over the above device.
extern const size_t nmranet::CONFIG_FILE_SIZE =
    cfg.seg().size() + cfg.seg().offset();
static_assert(nmranet::CONFIG_FILE_SIZE <= 300, "Need to adjust eeprom size");
// The SNIP user-changeable information in also stored in the above eeprom
// device. In general this could come from different eeprom segments, but it is
// simpler to keep them together.
extern const char *const nmranet::SNIP_DYNAMIC_FILENAME =
    nmranet::CONFIG_FILENAME;

// Defines the GPIO ports used for the producers and the consumers.

// The first LED is driven by the blinker device from BlinkerGPIO.hxx. We just
// create an alias for symmetry.
typedef BLINKER_Pin LED_RED_Pin;

// List of GPIO objects that will be used for the output pins. You should keep
// the constexpr declaration, because it will produce a compile error in case
// the list of pointers cannot be compiled into a compiler constant and thus
// would be placed into RAM instead of ROM.
constexpr const Gpio *const kOutputGpio[] = {LED_RED_Pin::instance(),
                                             LED_GREEN_Pin::instance(),
                                             LED_BLUE_Pin::instance()};

// Instantiates the actual producer and consumer objects for the given GPIO
// pins from above. The MultiConfiguredConsumer class takes care of most of the
// complicated setup and operation requirements. We need to give it the virtual
// node pointer, the hardware pin definition and the configuration from the CDI
// definition. The virtual node pointer comes from the stack object. The
// configuration structure comes from the CDI definition object, segment 'seg',
// in which there is a repeated group 'consumers'. The GPIO pins get assigned
// to the repetitions in the group in order.
nmranet::MultiConfiguredConsumer consumers(kOutputGpio, ARRAYSIZE(kOutputGpio),
                                           cfg.seg().consumers());

// Similar syntax for the producers.
nmranet::ConfiguredProducer producer_sw1(
    stack.node(), cfg.seg().producers().entry<0>(), SW1_Pin());
nmranet::ConfiguredProducer producer_sw2(
    stack.node(), cfg.seg().producers().entry<1>(), SW2_Pin());

// The producers need to be polled repeatedly for changes and to execute the
// debouncing algorithm. This class instantiates a refreshloop and adds the two
// producers to it.
nmranet::RefreshLoop loop(
    stack.node(), {producer_sw1.polling(), producer_sw2.polling()});

/** Entry point to application.
 * @param argc number of command line arguments
 * @param argv array of command line arguments
 * @return 0, should never return
 */
int appl_main(int argc, char *argv[])
{
    // The necessary physical ports must be added to the stack.
    //
    // It is okay to enable multiple physical ports, in which case the stack
    // will behave as a bridge between them. For example enabling both the
    // physical CAN port and the USB port will make this firmware act as an
    // USB-CAN adapter in addition to the producers/consumers created above.
    //
    // If a port is enabled, it must be functional or else the stack will
    // freeze waiting for that port to send the packets out.
#if defined(HAVE_PHYSICAL_CAN_PORT)
    stack.add_can_port_select("/dev/can0");
#endif
#if defined(SNIFF_ON_USB)
    stack.add_gridconnect_port("/dev/serUSB0");
#endif
#if defined(SNIFF_ON_SERIAL)
    stack.add_gridconnect_port("/dev/ser0");
#endif

    // This command donates the main thread to the operation of the
    // stack. Alternatively the stack could be started in a separate stack and
    // then application-specific business logic could be executed ion a busy
    // loop in the main thread.
    stack.loop_executor();
    return 0;
}
<|endoftext|>


<commit_before>
// Author: Enric Tejedor CERN  08/2019

/*************************************************************************
 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TMemoryRegulator.h"

#include "ProxyWrappers.h"
#include "CPPInstance.h"
#include "CPPInstance.h"

using namespace CPyCppyy;

PyROOT::ObjectMap_t PyROOT::TMemoryRegulator::fObjectMap = PyROOT::ObjectMap_t();

////////////////////////////////////////////////////////////////////////////
/// \brief Constructor. Registers the hooks to run on Cppyy's object
///        construction and destruction
PyROOT::TMemoryRegulator::TMemoryRegulator()
{
   MemoryRegulator::SetRegisterHook(PyROOT::TMemoryRegulator::RegisterHook);
   MemoryRegulator::SetUnregisterHook(PyROOT::TMemoryRegulator::UnregisterHook);
}

////////////////////////////////////////////////////////////////////////////
/// \brief Register a hook that Cppyy runs when constructing an object.
/// \param[in] cppobj Address of the object.
/// \param[in] klass Class id of the object.
/// \return Pair of two booleans. First indicates success, second tells
///         Cppyy if we want to continue running RegisterPyObject
std::pair<bool, bool> PyROOT::TMemoryRegulator::RegisterHook(Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass)
{
   static Cppyy::TCppType_t tobjectTypeID = (Cppyy::TCppType_t)Cppyy::GetScope("TObject");

   if (Cppyy::IsSubtype(klass, tobjectTypeID)) {
      ObjectMap_t::iterator ppo = fObjectMap.find(cppobj);
      if (ppo == fObjectMap.end()) {
         fObjectMap.insert({cppobj, klass});
      }
   }

   return {true, true};
}

////////////////////////////////////////////////////////////////////////////
/// \brief Register a hook that Cppyy runs when deleting an object.
/// \param[in] cppobj Address of the object.
/// \param[in] klass Class id of the object.
/// \return Pair of two booleans. First indicates success, second tells
///         Cppyy if we want to continue running UnRegisterPyObject
std::pair<bool, bool> PyROOT::TMemoryRegulator::UnregisterHook(Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass)
{
   static Cppyy::TCppType_t tobjectTypeID = (Cppyy::TCppType_t)Cppyy::GetScope("TObject");

   if (Cppyy::IsSubtype(klass, tobjectTypeID)) {
      ObjectMap_t::iterator ppo = fObjectMap.find(cppobj);
      if (ppo != fObjectMap.end()) {
         fObjectMap.erase(ppo);
      }
   }

   return {true, true};
}

////////////////////////////////////////////////////////////////////////////
/// \brief Get the class id of the TObject being deleted and run Cppyy's
///        RecursiveRemove.
/// \param[in] object Object being destructed.
void PyROOT::TMemoryRegulator::RecursiveRemove(TObject *object)
{
   auto cppobj = (Cppyy::TCppObject_t)object;
   Cppyy::TCppType_t klass = 0;

   ObjectMap_t::iterator ppo = fObjectMap.find(cppobj);
   if (ppo != fObjectMap.end()) {
      klass = ppo->second;
      MemoryRegulator::RecursiveRemove(cppobj, klass);
      fObjectMap.erase(ppo);
   }
}

////////////////////////////////////////////////////////////////////////////
/// \brief Clean up all tracked objects.
void PyROOT::TMemoryRegulator::ClearProxiedObjects()
{
   while (!fObjectMap.empty()) {
      auto elem = fObjectMap.begin();
      auto cppobj = elem->first;
      auto klassid = elem->second;
      auto pyclass = CreateScopeProxy(klassid);
      auto pyobj = (CPPInstance *)MemoryRegulator::RetrievePyObject(cppobj, pyclass);

      if (pyobj && (pyobj->fFlags & CPPInstance::kIsOwner)) {
         // Only delete the C++ object if the Python proxy owns it.
         // Invoke RecursiveRemove on it first so that proxy cleanup is done
         auto o = static_cast<TObject *>(cppobj);
         RecursiveRemove(o);
         delete o;
      }
      else {
         // Non-owning proxy, just unregister to clean tables.
         // The proxy deletion by Python will have no effect on C++, so all good
         MemoryRegulator::UnregisterPyObject(pyobj, pyclass);
      }
   }
}
<commit_msg>[Exp PyROOT][ROOT-9516] Do not delete proxied object if cppyy does it<commit_after>
// Author: Enric Tejedor CERN  08/2019

/*************************************************************************
 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TMemoryRegulator.h"

#include "ProxyWrappers.h"
#include "CPPInstance.h"
#include "CPPInstance.h"

using namespace CPyCppyy;

PyROOT::ObjectMap_t PyROOT::TMemoryRegulator::fObjectMap = PyROOT::ObjectMap_t();

////////////////////////////////////////////////////////////////////////////
/// \brief Constructor. Registers the hooks to run on Cppyy's object
///        construction and destruction
PyROOT::TMemoryRegulator::TMemoryRegulator()
{
   MemoryRegulator::SetRegisterHook(PyROOT::TMemoryRegulator::RegisterHook);
   MemoryRegulator::SetUnregisterHook(PyROOT::TMemoryRegulator::UnregisterHook);
}

////////////////////////////////////////////////////////////////////////////
/// \brief Register a hook that Cppyy runs when constructing an object.
/// \param[in] cppobj Address of the object.
/// \param[in] klass Class id of the object.
/// \return Pair of two booleans. First indicates success, second tells
///         Cppyy if we want to continue running RegisterPyObject
std::pair<bool, bool> PyROOT::TMemoryRegulator::RegisterHook(Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass)
{
   static Cppyy::TCppType_t tobjectTypeID = (Cppyy::TCppType_t)Cppyy::GetScope("TObject");

   if (Cppyy::IsSubtype(klass, tobjectTypeID)) {
      ObjectMap_t::iterator ppo = fObjectMap.find(cppobj);
      if (ppo == fObjectMap.end()) {
         fObjectMap.insert({cppobj, klass});
      }
   }

   return {true, true};
}

////////////////////////////////////////////////////////////////////////////
/// \brief Register a hook that Cppyy runs when deleting an object.
/// \param[in] cppobj Address of the object.
/// \param[in] klass Class id of the object.
/// \return Pair of two booleans. First indicates success, second tells
///         Cppyy if we want to continue running UnRegisterPyObject
std::pair<bool, bool> PyROOT::TMemoryRegulator::UnregisterHook(Cppyy::TCppObject_t cppobj, Cppyy::TCppType_t klass)
{
   static Cppyy::TCppType_t tobjectTypeID = (Cppyy::TCppType_t)Cppyy::GetScope("TObject");

   if (Cppyy::IsSubtype(klass, tobjectTypeID)) {
      ObjectMap_t::iterator ppo = fObjectMap.find(cppobj);
      if (ppo != fObjectMap.end()) {
         fObjectMap.erase(ppo);
      }
   }

   return {true, true};
}

////////////////////////////////////////////////////////////////////////////
/// \brief Get the class id of the TObject being deleted and run Cppyy's
///        RecursiveRemove.
/// \param[in] object Object being destructed.
void PyROOT::TMemoryRegulator::RecursiveRemove(TObject *object)
{
   auto cppobj = (Cppyy::TCppObject_t)object;
   Cppyy::TCppType_t klass = 0;

   ObjectMap_t::iterator ppo = fObjectMap.find(cppobj);
   if (ppo != fObjectMap.end()) {
      klass = ppo->second;
      MemoryRegulator::RecursiveRemove(cppobj, klass);
      fObjectMap.erase(ppo);
   }
}

////////////////////////////////////////////////////////////////////////////
/// \brief Clean up all tracked objects.
void PyROOT::TMemoryRegulator::ClearProxiedObjects()
{
   while (!fObjectMap.empty()) {
      auto elem = fObjectMap.begin();
      auto cppobj = elem->first;
      auto klassid = elem->second;
      auto pyclass = CreateScopeProxy(klassid);
      auto pyobj = (CPPInstance *)MemoryRegulator::RetrievePyObject(cppobj, pyclass);

      if (pyobj && (pyobj->fFlags & CPPInstance::kIsOwner)) {
         // Only delete the C++ object if the Python proxy owns it.
         // If it is a value, cppyy deletes it in RecursiveRemove as part of
         // the proxy cleanup.
         auto o = static_cast<TObject *>(cppobj);
         bool isValue = pyobj->fFlags & CPPInstance::kIsValue;
         RecursiveRemove(o);
         if (!isValue)
            delete o;
      }
      else {
         // Non-owning proxy, just unregister to clean tables.
         // The proxy deletion by Python will have no effect on C++, so all good
         MemoryRegulator::UnregisterPyObject(pyobj, pyclass);
      }
   }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010, Willow Garage, Inc.
 * 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.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * 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 OWNER 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.
 */

#include <stdio.h>

#include <tf2/buffer_core.h>
#include "tf2/time.h"
#include <boost/lexical_cast.hpp>
#include <chrono>

using std::chrono::system_clock;
using std::chrono::steady_clock;
using std::chrono::high_resolution_clock;

int main(int argc, char** argv)
{
  uint32_t num_levels = 10;
  // if (argc > 1)
  // {
  //   num_levels = boost::lexical_cast<uint32_t>(argv[1]);
  // }

  tf2::BufferCore bc;
  geometry_msgs::TransformStamped t;
  t.header.stamp = 1;
  t.header.frame_id = "root";
  t.child_frame_id = "0";
  t.transform.translation.x = 1;
  t.transform.rotation.w = 1.0;
  bc.setTransform(t, "me");
  t.header.stamp = 2;
  bc.setTransform(t, "me");

  for (uint32_t i = 1; i < num_levels/2; ++i)
  {
    for (uint32_t j = 1; j < 3; ++j)
    {
      std::stringstream parent_ss;
      parent_ss << (i - 1);
      std::stringstream child_ss;
      child_ss << i;

      t.header.stamp = tf2::Time(j);
      t.header.frame_id = parent_ss.str();
      t.child_frame_id = child_ss.str();
      bc.setTransform(t, "me");
    }
  }

  t.header.frame_id = "root";
  std::stringstream ss;
  ss << num_levels/2;
  t.header.stamp = 1;
  t.child_frame_id = ss.str();
  bc.setTransform(t, "me");
  t.header.stamp = 2;
  bc.setTransform(t, "me");

  for (uint32_t i = num_levels/2 + 1; i < num_levels; ++i)
  {
    for (uint32_t j = 1; j < 3; ++j)
    {
      std::stringstream parent_ss;
      parent_ss << (i - 1);
      std::stringstream child_ss;
      child_ss << i;

      t.header.stamp = tf2::Time(j);
      t.header.frame_id = parent_ss.str();
      t.child_frame_id = child_ss.str();
      bc.setTransform(t, "me");
    }
  }

  //logInfo_STREAM(bc.allFramesAsYAML());

  std::string v_frame0 = boost::lexical_cast<std::string>(num_levels - 1);
  std::string v_frame1 = boost::lexical_cast<std::string>(num_levels/2 - 1);
  printf("%s to %s\n", v_frame0.c_str(), v_frame1.c_str());
  geometry_msgs::TransformStamped out_t;

  const uint32_t count = 1000000;
  printf("Doing %d %d-level tests\n", count, num_levels);

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      out_t = bc.lookupTransform(v_frame1, v_frame0, 0);
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("lookupTransform at Time(0) took: %f (secs) for an average of: %.9f (secs)\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      out_t = bc.lookupTransform(v_frame1, v_frame0, tf2::Time(1));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("lookupTransform at Time(1) took: %f for an average of: %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      out_t = bc.lookupTransform(v_frame1, v_frame0, tf2::Time(1.5));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("lookupTransform at Time(1.5) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      out_t = bc.lookupTransform(v_frame1, v_frame0, tf2::Time(2));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("lookupTransform at Time(2) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      bc.canTransform(v_frame1, v_frame0, tf2::Time(0));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("canTransform at Time(0) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      bc.canTransform(v_frame1, v_frame0, tf2::Time(1));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("canTransform at Time(1) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      bc.canTransform(v_frame1, v_frame0, tf2::Time(1.5 * 1e9));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("canTransform at Time(1.5) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      bc.canTransform(v_frame1, v_frame0, tf2::Time(2));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("canTransform at Time(2) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif
}
<commit_msg>third_party: fix tf2 invalid printf arg type<commit_after>/*
 * Copyright (c) 2010, Willow Garage, Inc.
 * 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.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * 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 OWNER 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.
 */

#include <stdio.h>

#include <tf2/buffer_core.h>
#include "tf2/time.h"
#include <boost/lexical_cast.hpp>
#include <chrono>

using std::chrono::system_clock;
using std::chrono::steady_clock;
using std::chrono::high_resolution_clock;

int main(int argc, char** argv)
{
  int num_levels = 10;
  // if (argc > 1)
  // {
  //   num_levels = boost::lexical_cast<uint32_t>(argv[1]);
  // }

  tf2::BufferCore bc;
  geometry_msgs::TransformStamped t;
  t.header.stamp = 1;
  t.header.frame_id = "root";
  t.child_frame_id = "0";
  t.transform.translation.x = 1;
  t.transform.rotation.w = 1.0;
  bc.setTransform(t, "me");
  t.header.stamp = 2;
  bc.setTransform(t, "me");

  for (uint32_t i = 1; i < num_levels/2; ++i)
  {
    for (uint32_t j = 1; j < 3; ++j)
    {
      std::stringstream parent_ss;
      parent_ss << (i - 1);
      std::stringstream child_ss;
      child_ss << i;

      t.header.stamp = tf2::Time(j);
      t.header.frame_id = parent_ss.str();
      t.child_frame_id = child_ss.str();
      bc.setTransform(t, "me");
    }
  }

  t.header.frame_id = "root";
  std::stringstream ss;
  ss << num_levels/2;
  t.header.stamp = 1;
  t.child_frame_id = ss.str();
  bc.setTransform(t, "me");
  t.header.stamp = 2;
  bc.setTransform(t, "me");

  for (uint32_t i = num_levels/2 + 1; i < num_levels; ++i)
  {
    for (uint32_t j = 1; j < 3; ++j)
    {
      std::stringstream parent_ss;
      parent_ss << (i - 1);
      std::stringstream child_ss;
      child_ss << i;

      t.header.stamp = tf2::Time(j);
      t.header.frame_id = parent_ss.str();
      t.child_frame_id = child_ss.str();
      bc.setTransform(t, "me");
    }
  }

  //logInfo_STREAM(bc.allFramesAsYAML());

  std::string v_frame0 = boost::lexical_cast<std::string>(num_levels - 1);
  std::string v_frame1 = boost::lexical_cast<std::string>(num_levels/2 - 1);
  printf("%s to %s\n", v_frame0.c_str(), v_frame1.c_str());
  geometry_msgs::TransformStamped out_t;

  const int count = 1000000;
  printf("Doing %d %d-level tests\n", count, num_levels);

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      out_t = bc.lookupTransform(v_frame1, v_frame0, 0);
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("lookupTransform at Time(0) took: %f (secs) for an average of: %.9f (secs)\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      out_t = bc.lookupTransform(v_frame1, v_frame0, tf2::Time(1));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("lookupTransform at Time(1) took: %f for an average of: %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      out_t = bc.lookupTransform(v_frame1, v_frame0, tf2::Time(1.5));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("lookupTransform at Time(1.5) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      out_t = bc.lookupTransform(v_frame1, v_frame0, tf2::Time(2));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("lookupTransform at Time(2) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      bc.canTransform(v_frame1, v_frame0, tf2::Time(0));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("canTransform at Time(0) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      bc.canTransform(v_frame1, v_frame0, tf2::Time(1));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("canTransform at Time(1) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      bc.canTransform(v_frame1, v_frame0, tf2::Time(1.5 * 1e9));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("canTransform at Time(1.5) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif

#if 01
  {
    steady_clock::time_point start = steady_clock::now();
    for (uint32_t i = 0; i < count; ++i)
    {
      bc.canTransform(v_frame1, v_frame0, tf2::Time(2));
    }
    steady_clock::time_point end = steady_clock::now();
    double dur = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
    printf("canTransform at Time(2) took %f for an average of %.9f\n", dur, dur / (double)count);
  }
#endif
}
<|endoftext|>


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

#pragma once

#include <thrust/detail/segmented_storage.h>
#include <thrust/for_each.h>
#include <thrust/reduce.h>
#include <functional>

namespace thrust
{

namespace detail
{

template<typename T, typename Allocator>
  segmented_storage<T,Allocator>
    ::segmented_storage(void)
      :m_storage(choose_number_of_segments())
{
  ;
} // end segmented_storage::segmented_storage()

template<typename T, typename Allocator>
  segmented_storage<T,Allocator>
    ::segmented_storage(size_type n)
      :m_storage(choose_number_of_segments())
{
  allocate(n);
} // end segmented_storage::segmented_storage()

template<typename T, typename Allocator>
  segmented_storage<T,Allocator>
    ::~segmented_storage(void)
{
  deallocate();
} // end segmented_storage::~segmented_storage()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::size_type
    segmented_storage<T,Allocator>
      ::size(void) const
{
  // return the sum of the sizes of the individual storages
  return thrust::reduce(m_storage.begin(), m_storage.end(), std::mem_fun_ref(&storage_type::size));
} // end segmented_storage::size()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::size_type
    segmented_storage<T,Allocator>
      ::max_size(void) const
{
  // return the sum of the max_sizes of the individual storages
  return thrust::reduce(m_storage.begin(), m_storage.end(), std::mem_fun_ref(&storage_type::max_size));
} // end segmented_storage::max_size()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::iterator
    segmented_storage<T,Allocator>
      ::begin(void)
{
  return thrust::detail::make_segmented_iterator(m_storage.begin(), m_storage.end());
} // end segmented_storage::begin()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::const_iterator
    segmented_storage<T,Allocator>
      ::begin(void) const
{
  return thrust::detail::make_segmented_iterator(m_storage.begin(), m_storage.end());
} // end segmented_storage::begin()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::iterator
    segmented_storage<T,Allocator>
      ::end(void)
{
  return thrust::detail::make_segmented_iterator(m_storage.end(), m_storage.end());
} // end segmented_storage::end()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::const_iterator
    segmented_storage<T,Allocator>
      ::end(void) const
{
  return thrust::detail::make_segmented_iterator(m_storage.end(), m_storage.end());
} // end segmented_storage::end()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::allocator_type
    segmented_storage<T,Allocator>
      ::get_allocator(void) const
{
  // return the first storage's allocator i guess
  return m_storage[0].get_allocator();
} // end segmented_storage::get_allocator()

template<typename T, typename Allocator>
  void segmented_storage<T,Allocator>
    ::allocate(size_type n)
{
  const size_type m = m_storage.size();

  // break up n into m chunks of n/m (except possibly the last one)
  // if n is small, just give it all to the first segment
  const size_type size_per_segment = (n > m) ? (n / m) : n;

  // if there are leftovers, give them to the first segment
  size_type num_leftover = 0;
  if(n > m * size_per_segment)
  {
    num_leftover = n - (m * size_per_segment);
  }

  // XXX might want to parallelize this with for_each
  size_type i = 0;
  while(n > 0)
  {
    // XXX don't use thrust::min here to avoid bringing in all of extrema.h
    const size_type size_to_allocate = ((size_per_segment < n) ? size_per_segment : n) + num_leftover;

    m_storage[i].allocate(size_to_allocate);

    n -= size_to_allocate;
    ++i;
    num_leftover = 0;
  } // end while
} // segmented_storage::allocate()

template<typename T, typename Allocator>
  void segmented_storage<T,Allocator>
    ::deallocate(void)
{
  thrust::for_each(m_storage.begin(), m_storage.end(), std::mem_fun_ref(&storage_type::deallocate));
} // end segmented_storage::deallocate();

template<typename T, typename Allocator>
  void segmented_storage<T,Allocator>
    ::swap(segmented_storage &x)
{
  thrust::swap(m_storage, x.m_storage);
} // end segmented_storage::swap()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::size_type
    segmented_storage<T,Allocator>
      ::choose_number_of_segments(void)
{
  return 2;
} // end segmented_storage::choose_number_of_segments()

} // end detail

} // end thrust

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

#pragma once

#include <thrust/detail/segmented_storage.h>
#include <thrust/for_each.h>
#include <thrust/reduce.h>
#include <functional>

namespace thrust
{

namespace detail
{

template<typename T, typename Allocator>
  segmented_storage<T,Allocator>
    ::segmented_storage(void)
      :m_storage(choose_number_of_segments())
{
  ;
} // end segmented_storage::segmented_storage()

template<typename T, typename Allocator>
  segmented_storage<T,Allocator>
    ::segmented_storage(size_type n)
      :m_storage(choose_number_of_segments())
{
  std::cout << "Allocator: " << typeid(Allocator).name() << std::endl;
  allocate(n);
} // end segmented_storage::segmented_storage()

template<typename T, typename Allocator>
  segmented_storage<T,Allocator>
    ::~segmented_storage(void)
{
  deallocate();
} // end segmented_storage::~segmented_storage()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::size_type
    segmented_storage<T,Allocator>
      ::size(void) const
{
  // return the sum of the sizes of the individual storages
  return thrust::reduce(m_storage.begin(), m_storage.end(), std::mem_fun_ref(&storage_type::size));
} // end segmented_storage::size()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::size_type
    segmented_storage<T,Allocator>
      ::max_size(void) const
{
  // return the sum of the max_sizes of the individual storages
  return thrust::reduce(m_storage.begin(), m_storage.end(), std::mem_fun_ref(&storage_type::max_size));
} // end segmented_storage::max_size()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::iterator
    segmented_storage<T,Allocator>
      ::begin(void)
{
  return thrust::detail::make_segmented_iterator(m_storage.begin(), m_storage.end());
} // end segmented_storage::begin()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::const_iterator
    segmented_storage<T,Allocator>
      ::begin(void) const
{
  return thrust::detail::make_segmented_iterator(m_storage.begin(), m_storage.end());
} // end segmented_storage::begin()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::iterator
    segmented_storage<T,Allocator>
      ::end(void)
{
  return thrust::detail::make_segmented_iterator(m_storage.end(), m_storage.end());
} // end segmented_storage::end()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::const_iterator
    segmented_storage<T,Allocator>
      ::end(void) const
{
  return thrust::detail::make_segmented_iterator(m_storage.end(), m_storage.end());
} // end segmented_storage::end()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::allocator_type
    segmented_storage<T,Allocator>
      ::get_allocator(void) const
{
  // return the first storage's allocator i guess
  return m_storage[0].get_allocator();
} // end segmented_storage::get_allocator()

template<typename T, typename Allocator>
  void segmented_storage<T,Allocator>
    ::allocate(size_type n)
{
  const size_type m = m_storage.size();

  // break up n into m chunks of n/m (except possibly the last one)
  // if n is small, just give it all to the first segment
  const size_type size_per_segment = (n > m) ? (n / m) : n;

  // if there are leftovers, give them to the first segment
  size_type num_leftover = 0;
  if(n > m * size_per_segment)
  {
    num_leftover = n - (m * size_per_segment);
  }

  // XXX might want to parallelize this with for_each
  size_type i = 0;
  while(n > 0)
  {
    // XXX don't use thrust::min here to avoid bringing in all of extrema.h
    const size_type size_to_allocate = ((size_per_segment < n) ? size_per_segment : n) + num_leftover;

    m_storage[i].allocate(size_to_allocate);

    n -= size_to_allocate;
    ++i;
    num_leftover = 0;
  } // end while
} // segmented_storage::allocate()

template<typename T, typename Allocator>
  void segmented_storage<T,Allocator>
    ::deallocate(void)
{
  thrust::for_each(m_storage.begin(), m_storage.end(), std::mem_fun_ref(&storage_type::deallocate));
} // end segmented_storage::deallocate();

template<typename T, typename Allocator>
  void segmented_storage<T,Allocator>
    ::swap(segmented_storage &x)
{
  thrust::swap(m_storage, x.m_storage);
} // end segmented_storage::swap()

template<typename T, typename Allocator>
  typename segmented_storage<T,Allocator>::size_type
    segmented_storage<T,Allocator>
      ::choose_number_of_segments(void)
{
  return 2;
} // end segmented_storage::choose_number_of_segments()

} // end detail

} // end thrust

<|endoftext|>