#ifndef MTUTILS_HPP #define MTUTILS_HPP #include // for std::atomic_flag and memory orders #include // for std::lock_guard #include // for std::function #include // for std::forward namespace Slic3r { /// Handy little spin mutex for the cached meshes. /// Implements the "Lockable" concept class SpinMutex { std::atomic_flag m_flg; static const /*constexpr*/ auto MO_ACQ = std::memory_order_acquire; static const /*constexpr*/ auto MO_REL = std::memory_order_release; public: inline SpinMutex() { m_flg.clear(MO_REL); } inline void lock() { while(m_flg.test_and_set(MO_ACQ)); } inline bool try_lock() { return !m_flg.test_and_set(MO_ACQ); } inline void unlock() { m_flg.clear(MO_REL); } }; /// A wrapper class around arbitrary object that needs thread safe caching. template class CachedObject { public: // Method type which refreshes the object when it has been invalidated using Setter = std::function; private: T m_obj; // the object itself bool m_valid; // invalidation flag SpinMutex m_lck; // to make the caching thread safe // the setter will be called just before the object's const value is about // to be retrieved. std::function m_setter; public: // Forwarded constructor template inline CachedObject(Setter fn, Args&&...args): m_obj(std::forward(args)...), m_valid(false), m_setter(fn) {} // invalidate the value of the object. The object will be refreshed at the // next retrieval (Setter will be called). The data that is used in // the setter function should be guarded as well during modification so the // modification has to take place in fn. inline void invalidate(std::function fn) { std::lock_guard lck(m_lck); fn(); m_valid = false; } // Get the const object properly updated. inline const T& get() { std::lock_guard lck(m_lck); if(!m_valid) { m_setter(m_obj); m_valid = true; } return m_obj; } }; template class IndexBasedIterator { static const size_t NONE = size_t(-1); std::reference_wrapper m_index_ref; size_t m_idx = NONE; public: using value_type = Value; using pointer = Value *; using reference = Value &; using difference_type = long; using iterator_category = std::random_access_iterator_tag; inline explicit IndexBasedIterator(Vector& index, size_t idx): m_index_ref(index), m_idx(idx) {} // Post increment inline IndexBasedIterator operator++(int) { IndexBasedIterator cpy(*this); ++m_idx; return cpy; } inline IndexBasedIterator operator--(int) { IndexBasedIterator cpy(*this); --m_idx; return cpy; } inline IndexBasedIterator& operator++() { ++m_idx; return *this; } inline IndexBasedIterator& operator--() { --m_idx; return *this; } inline IndexBasedIterator& operator+=(difference_type l) { m_idx += size_t(l); return *this; } inline IndexBasedIterator operator+(difference_type l) { auto cpy = *this; cpy += l; return cpy; } inline IndexBasedIterator& operator-=(difference_type l) { m_idx -= size_t(l); return *this; } inline IndexBasedIterator operator-(difference_type l) { auto cpy = *this; cpy -= l; return cpy; } operator difference_type() { return difference_type(m_idx); } inline bool is_end() const { return m_idx >= m_index_ref.get().size();} inline Value & operator*() const { assert(m_idx < m_index_ref.get().size()); return m_index_ref.get().operator[](m_idx); } inline Value * operator->() const { assert(m_idx < m_index_ref.get().size()); return &m_index_ref.get().operator[](m_idx); } inline bool operator ==(const IndexBasedIterator& other) { size_t e = m_index_ref.get().size(); return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e); } inline bool operator !=(const IndexBasedIterator& other) { return !(*this == other); } inline bool operator <=(const IndexBasedIterator& other) { return (m_idx < other.m_idx) || (*this == other); } inline bool operator <(const IndexBasedIterator& other) { return m_idx < other.m_idx && (*this != other); } inline bool operator >=(const IndexBasedIterator& other) { return m_idx > other.m_idx || *this == other; } inline bool operator >(const IndexBasedIterator& other) { return m_idx > other.m_idx && *this != other; } }; template class Range { It from, to; public: It begin() const { return from; } It end() const { return to; } using Type = It; Range() = default; Range(It &&b, It &&e): from(std::forward(b)), to(std::forward(e)) {} inline size_t size() const { return end() - begin(); } inline bool empty() const { return size() == 0; } }; } #endif // MTUTILS_HPP