count.hpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright 2019 Hans Dembinski
  2. //
  3. // Distributed under the Boost Software License, version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_HISTOGRAM_ACCUMULATORS_COUNT_HPP
  7. #define BOOST_HISTOGRAM_ACCUMULATORS_COUNT_HPP
  8. #include <boost/core/nvp.hpp>
  9. #include <boost/histogram/detail/atomic_number.hpp>
  10. #include <boost/histogram/fwd.hpp> // for count<>
  11. #include <type_traits> // for std::common_type
  12. namespace boost {
  13. namespace histogram {
  14. namespace accumulators {
  15. /**
  16. Wraps a C++ arithmetic type with optionally thread-safe increments and adds.
  17. This adaptor optionally uses atomic operations to make concurrent increments and
  18. additions thread-safe for the stored arithmetic value, which can be integral or
  19. floating point. For small histograms, the performance will still be poor because of
  20. False Sharing, see https://en.wikipedia.org/wiki/False_sharing for details.
  21. Warning: Assignment is not thread-safe in this implementation, so don't assign
  22. concurrently.
  23. This wrapper class can be used as a base class by users to add arbitrary metadata to
  24. each bin of a histogram.
  25. When weighted samples are accumulated and high precision is required, use
  26. `accumulators::sum` instead (at the cost of lower performance). If a local variance
  27. estimate for the weight distribution should be computed as well (generally needed for a
  28. detailed statistical analysis), use `accumulators::weighted_sum`.
  29. @tparam T C++ builtin arithmetic type (integer or floating point).
  30. @tparam ThreadSafe Set to true to make increments and adds thread-safe.
  31. */
  32. template <class ValueType, bool ThreadSafe>
  33. class count {
  34. using internal_type =
  35. std::conditional_t<ThreadSafe, detail::atomic_number<ValueType>, ValueType>;
  36. public:
  37. using value_type = ValueType;
  38. using const_reference = const value_type&;
  39. count() noexcept = default;
  40. /// Initialize count to value and allow implicit conversion
  41. count(const_reference value) noexcept : value_{value} {}
  42. /// Allow implicit conversion from other count
  43. template <class T, bool B>
  44. count(const count<T, B>& c) noexcept : count{c.value()} {}
  45. /// Increment count by one
  46. count& operator++() noexcept {
  47. ++value_;
  48. return *this;
  49. }
  50. /// Increment count by value
  51. count& operator+=(const_reference value) noexcept {
  52. value_ += value;
  53. return *this;
  54. }
  55. /// Add another count
  56. count& operator+=(const count& s) noexcept {
  57. value_ += s.value_;
  58. return *this;
  59. }
  60. /// Scale by value
  61. count& operator*=(const_reference value) noexcept {
  62. value_ *= value;
  63. return *this;
  64. }
  65. bool operator==(const count& rhs) const noexcept { return value_ == rhs.value_; }
  66. bool operator!=(const count& rhs) const noexcept { return !operator==(rhs); }
  67. /// Return count
  68. value_type value() const noexcept { return value_; }
  69. // conversion to value_type must be explicit
  70. explicit operator value_type() const noexcept { return value_; }
  71. template <class Archive>
  72. void serialize(Archive& ar, unsigned /* version */) {
  73. auto v = value();
  74. ar& make_nvp("value", v);
  75. value_ = v;
  76. }
  77. static constexpr bool thread_safe() noexcept { return ThreadSafe; }
  78. // begin: extra operators to make count behave like a regular number
  79. count& operator*=(const count& rhs) noexcept {
  80. value_ *= rhs.value_;
  81. return *this;
  82. }
  83. count operator*(const count& rhs) const noexcept {
  84. count x = *this;
  85. x *= rhs;
  86. return x;
  87. }
  88. count& operator/=(const count& rhs) noexcept {
  89. value_ /= rhs.value_;
  90. return *this;
  91. }
  92. count operator/(const count& rhs) const noexcept {
  93. count x = *this;
  94. x /= rhs;
  95. return x;
  96. }
  97. bool operator<(const count& rhs) const noexcept { return value_ < rhs.value_; }
  98. bool operator>(const count& rhs) const noexcept { return value_ > rhs.value_; }
  99. bool operator<=(const count& rhs) const noexcept { return value_ <= rhs.value_; }
  100. bool operator>=(const count& rhs) const noexcept { return value_ >= rhs.value_; }
  101. friend bool operator==(const_reference x, const count& rhs) noexcept {
  102. return x == rhs.value_;
  103. }
  104. friend bool operator!=(const_reference x, const count& rhs) noexcept {
  105. return x != rhs.value_;
  106. }
  107. friend bool operator<(const_reference x, const count& rhs) noexcept {
  108. return x < rhs.value_;
  109. }
  110. friend bool operator>(const_reference x, const count& rhs) noexcept {
  111. return x > rhs.value_;
  112. }
  113. friend bool operator<=(const_reference x, const count& rhs) noexcept {
  114. return x <= rhs.value_;
  115. }
  116. friend bool operator>=(const_reference x, const count& rhs) noexcept {
  117. return x >= rhs.value_;
  118. }
  119. // end: extra operators
  120. private:
  121. internal_type value_{};
  122. };
  123. } // namespace accumulators
  124. } // namespace histogram
  125. } // namespace boost
  126. #ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
  127. namespace std {
  128. template <class T, class U, bool B1, bool B2>
  129. struct common_type<boost::histogram::accumulators::count<T, B1>,
  130. boost::histogram::accumulators::count<U, B2>> {
  131. using type = boost::histogram::accumulators::count<common_type_t<T, U>, (B1 || B2)>;
  132. };
  133. } // namespace std
  134. #endif
  135. #endif