MTUtils.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. ///|/ Copyright (c) Prusa Research 2018 - 2023 Tomáš Mészáros @tamasmeszaros, Lukáš Matěna @lukasmatena
  2. ///|/
  3. ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
  4. ///|/
  5. #ifndef MTUTILS_HPP
  6. #define MTUTILS_HPP
  7. #include <atomic> // for std::atomic_flag and memory orders
  8. #include <mutex> // for std::lock_guard
  9. #include <functional> // for std::function
  10. #include <utility> // for std::forward
  11. #include <vector>
  12. #include <algorithm>
  13. #include <cmath>
  14. #include "libslic3r.h"
  15. namespace Slic3r {
  16. /// Handy little spin mutex for the cached meshes.
  17. /// Implements the "Lockable" concept
  18. class SpinMutex
  19. {
  20. std::atomic_flag m_flg;
  21. static const /*constexpr*/ auto MO_ACQ = std::memory_order_acquire;
  22. static const /*constexpr*/ auto MO_REL = std::memory_order_release;
  23. public:
  24. inline SpinMutex() { m_flg.clear(MO_REL); }
  25. inline void lock() { while (m_flg.test_and_set(MO_ACQ)) ; }
  26. inline bool try_lock() { return !m_flg.test_and_set(MO_ACQ); }
  27. inline void unlock() { m_flg.clear(MO_REL); }
  28. };
  29. /// A wrapper class around arbitrary object that needs thread safe caching.
  30. template<class T> class CachedObject
  31. {
  32. public:
  33. // Method type which refreshes the object when it has been invalidated
  34. using Setter = std::function<void(T &)>;
  35. private:
  36. T m_obj; // the object itself
  37. bool m_valid; // invalidation flag
  38. SpinMutex m_lck; // to make the caching thread safe
  39. // the setter will be called just before the object's const value is
  40. // about to be retrieved.
  41. std::function<void(T &)> m_setter;
  42. public:
  43. // Forwarded constructor
  44. template<class... Args>
  45. inline CachedObject(Setter &&fn, Args &&... args)
  46. : m_obj(std::forward<Args>(args)...), m_valid(false), m_setter(fn)
  47. {}
  48. // invalidate the value of the object. The object will be refreshed at
  49. // the next retrieval (Setter will be called). The data that is used in
  50. // the setter function should be guarded as well during modification so
  51. // the modification has to take place in fn.
  52. template<class Fn> void invalidate(Fn &&fn)
  53. {
  54. std::lock_guard<SpinMutex> lck(m_lck);
  55. fn();
  56. m_valid = false;
  57. }
  58. // Get the const object properly updated.
  59. inline const T &get()
  60. {
  61. std::lock_guard<SpinMutex> lck(m_lck);
  62. if (!m_valid) {
  63. m_setter(m_obj);
  64. m_valid = true;
  65. }
  66. return m_obj;
  67. }
  68. };
  69. template<class C> bool all_of(const C &container)
  70. {
  71. return std::all_of(container.begin(),
  72. container.end(),
  73. [](const typename C::value_type &v) {
  74. return static_cast<bool>(v);
  75. });
  76. }
  77. //template<class T>
  78. //using remove_cvref_t = std::remove_reference_t<std::remove_cv_t<T>>;
  79. /// Exactly like Matlab https://www.mathworks.com/help/matlab/ref/linspace.html
  80. template<class T, class I, class = IntegerOnly<I>>
  81. inline std::vector<T> linspace_vector(const ArithmeticOnly<T> &start,
  82. const T &stop,
  83. const I &n)
  84. {
  85. std::vector<T> vals(n, T());
  86. T stride = (stop - start) / n;
  87. size_t i = 0;
  88. std::generate(vals.begin(), vals.end(), [&i, start, stride] {
  89. return start + i++ * stride;
  90. });
  91. return vals;
  92. }
  93. template<size_t N, class T>
  94. inline std::array<ArithmeticOnly<T>, N> linspace_array(const T &start, const T &stop)
  95. {
  96. std::array<T, N> vals = {T()};
  97. T stride = (stop - start) / N;
  98. size_t i = 0;
  99. std::generate(vals.begin(), vals.end(), [&i, start, stride] {
  100. return start + i++ * stride;
  101. });
  102. return vals;
  103. }
  104. /// A set of equidistant values starting from 'start' (inclusive), ending
  105. /// in the closest multiple of 'stride' less than or equal to 'end' and
  106. /// leaving 'stride' space between each value.
  107. /// Very similar to Matlab [start:stride:end] notation.
  108. template<class T>
  109. inline std::vector<ArithmeticOnly<T>> grid(const T &start,
  110. const T &stop,
  111. const T &stride)
  112. {
  113. std::vector<T> vals(size_t(std::ceil((stop - start) / stride)), T());
  114. int i = 0;
  115. std::generate(vals.begin(), vals.end(), [&i, start, stride] {
  116. return start + i++ * stride;
  117. });
  118. return vals;
  119. }
  120. } // namespace Slic3r
  121. #endif // MTUTILS_HPP