// TODO: Implement fast stack allocation. #ifndef _SCTL_MEM_MGR_HPP_ #define _SCTL_MEM_MGR_HPP_ //#include #include #include #include #include #include #include #include #include #include #include namespace SCTL_NAMESPACE { class MemoryManager; #ifdef SCTL_MEMDEBUG template class ConstIterator { template friend class ConstIterator; template friend class Iterator; void IteratorAssertChecks(Long j = 0) const; public: typedef Long difference_type; typedef ValueType value_type; typedef const ValueType* pointer; typedef const ValueType& reference; typedef std::random_access_iterator_tag iterator_category; protected: char* base; difference_type len, offset; Long alloc_ctr; void* mem_head; static const Long ValueSize = sizeof(ValueType); public: ConstIterator() : base(nullptr), len(0), offset(0), alloc_ctr(0), mem_head(nullptr) {} // template ConstIterator(ValueType (&base_)[LENGTH]) { // DEPRECATED (because mem_head cannot be stored) // SCTL_ASSERT(false); // } ConstIterator(pointer base_, difference_type len_, bool dynamic_alloc = false); template explicit ConstIterator(const ConstIterator& I) { this->base = I.base; this->len = I.len; this->offset = I.offset; SCTL_ASSERT_MSG((uintptr_t)(this->base + this->offset) % alignof(ValueType) == 0, "invalid alignment during pointer type conversion."); this->alloc_ctr = I.alloc_ctr; this->mem_head = I.mem_head; } // value_type* like operators reference operator*() const; pointer operator->() const; reference operator[](difference_type off) const; // Increment / Decrement ConstIterator& operator++() { offset += (Long)sizeof(ValueType); return *this; } ConstIterator operator++(int) { ConstIterator tmp(*this); ++*this; return tmp; } ConstIterator& operator--() { offset -= (Long)sizeof(ValueType); return *this; } ConstIterator operator--(int) { ConstIterator tmp(*this); --*this; return tmp; } // Arithmetic ConstIterator& operator+=(difference_type i) { offset += i * (Long)sizeof(ValueType); return *this; } ConstIterator operator+(difference_type i) const { ConstIterator tmp(*this); tmp.offset += i * (Long)sizeof(ValueType); return tmp; } friend ConstIterator operator+(difference_type i, const ConstIterator& right) { return (right + i); } ConstIterator& operator-=(difference_type i) { offset -= i * (Long)sizeof(ValueType); return *this; } ConstIterator operator-(difference_type i) const { ConstIterator tmp(*this); tmp.offset -= i * (Long)sizeof(ValueType); return tmp; } difference_type operator-(const ConstIterator& I) const { // if (base != I.base) SCTL_WARN("comparing two unrelated memory addresses."); Long diff = ((pointer)(base + offset)) - ((pointer)(I.base + I.offset)); SCTL_ASSERT_MSG(I.base + I.offset + diff * (Long)sizeof(ValueType) == base + offset, "invalid memory address alignment."); return diff; } // Comparison operators bool operator==(const ConstIterator& I) const { return (base + offset == I.base + I.offset); } bool operator!=(const ConstIterator& I) const { return !(*this == I); } bool operator<(const ConstIterator& I) const { // if (base != I.base) SCTL_WARN("comparing two unrelated memory addresses."); return (base + offset) < (I.base + I.offset); } bool operator<=(const ConstIterator& I) const { // if (base != I.base) SCTL_WARN("comparing two unrelated memory addresses."); return (base + offset) <= (I.base + I.offset); } bool operator>(const ConstIterator& I) const { // if (base != I.base) SCTL_WARN("comparing two unrelated memory addresses."); return (base + offset) > (I.base + I.offset); } bool operator>=(const ConstIterator& I) const { // if (base != I.base) SCTL_WARN("comparing two unrelated memory addresses."); return (base + offset) >= (I.base + I.offset); } friend std::ostream& operator<<(std::ostream& out, const ConstIterator& I) { out << "(" << (long long)I.base << "+" << I.offset << ":" << I.len << ")"; return out; } }; template class Iterator : public ConstIterator { public: typedef Long difference_type; typedef ValueType value_type; typedef ValueType* pointer; typedef ValueType& reference; typedef std::random_access_iterator_tag iterator_category; public: Iterator() : ConstIterator() {} //template Iterator(ValueType (&base_)[LENGTH]) : ConstIterator(base_) {} Iterator(pointer base_, difference_type len_, bool dynamic_alloc = false) : ConstIterator(base_, len_, dynamic_alloc) {} template explicit Iterator(const ConstIterator& I) : ConstIterator(I) {} // value_type* like operators reference operator*() const; value_type* operator->() const; reference operator[](difference_type off) const; // Increment / Decrement Iterator& operator++() { this->offset += (Long)sizeof(ValueType); return *this; } Iterator operator++(int) { Iterator tmp(*this); ++*this; return tmp; } Iterator& operator--() { this->offset -= (Long)sizeof(ValueType); return *this; } Iterator operator--(int) { Iterator tmp(*this); --*this; return tmp; } // Arithmetic Iterator& operator+=(difference_type i) { this->offset += i * (Long)sizeof(ValueType); return *this; } Iterator operator+(difference_type i) const { Iterator tmp(*this); tmp.offset += i * (Long)sizeof(ValueType); return tmp; } friend Iterator operator+(difference_type i, const Iterator& right) { return (right + i); } Iterator& operator-=(difference_type i) { this->offset -= i * (Long)sizeof(ValueType); return *this; } Iterator operator-(difference_type i) const { Iterator tmp(*this); tmp.offset -= i * (Long)sizeof(ValueType); return tmp; } difference_type operator-(const ConstIterator& I) const { return static_cast&>(*this) - I; } }; template class StaticArray { typedef Long difference_type; public: StaticArray() = default; StaticArray(const StaticArray&) = default; StaticArray& operator=(const StaticArray&) = default; explicit StaticArray(std::initializer_list arr_) : StaticArray() { // static_assert(arr_.size() <= DIM, "too many initializer values"); // allowed in C++14 SCTL_ASSERT_MSG(arr_.size() <= DIM, "too many initializer values"); for (Long i = 0; i < (Long)arr_.size(); i++) (*this)[i] = arr_.begin()[i]; } ~StaticArray() = default; // value_type* like operators const ValueType& operator*() const { return (*this)[0]; } ValueType& operator*() { return (*this)[0]; } const ValueType* operator->() const { return (ConstIterator)*this; } ValueType* operator->() { return (Iterator)*this; } const ValueType& operator[](difference_type off) const { return ((ConstIterator)*this)[off]; } ValueType& operator[](difference_type off) { return ((Iterator)*this)[off]; } operator ConstIterator() const { return ConstIterator(arr_, DIM); } operator Iterator() { return Iterator(arr_, DIM); } // Arithmetic ConstIterator operator+(difference_type i) const { return (ConstIterator)*this + i; } Iterator operator+(difference_type i) { return (Iterator)*this + i; } friend ConstIterator operator+(difference_type i, const StaticArray& right) { return i + (ConstIterator)right; } friend Iterator operator+(difference_type i, StaticArray& right) { return i + (Iterator)right; } ConstIterator operator-(difference_type i) const { return (ConstIterator)*this - i; } Iterator operator-(difference_type i) { return (Iterator)*this - i; } difference_type operator-(const ConstIterator& I) const { return (ConstIterator)*this - (ConstIterator)I; } // Comparison operators bool operator==(const ConstIterator& I) const { return (ConstIterator)*this == I; } bool operator!=(const ConstIterator& I) const { return (ConstIterator)*this != I; } bool operator< (const ConstIterator& I) const { return (ConstIterator)*this < I; } bool operator<=(const ConstIterator& I) const { return (ConstIterator)*this <= I; } bool operator> (const ConstIterator& I) const { return (ConstIterator)*this > I; } bool operator>=(const ConstIterator& I) const { return (ConstIterator)*this >= I; } private: ValueType arr_[DIM]; }; template Iterator Ptr2Itr(void* ptr, Long len) { return Iterator((ValueType*)ptr, len); } template ConstIterator Ptr2ConstItr(const void* ptr, Long len) { return ConstIterator((ValueType*)ptr, len); } #else // StaticArray - forward declared in common.hpp template Iterator Ptr2Itr(void* ptr, Long len) { return (Iterator) ptr; } template ConstIterator Ptr2ConstItr(const void* ptr, Long len) { return (ConstIterator) ptr; } #endif template Iterator NullIterator() { return Ptr2Itr(nullptr, 0); } /** * \brief MemoryManager class declaration. */ class MemoryManager { public: static constexpr char init_mem_val = 42; static constexpr Long end_padding = 64; /** * \brief Header data for each memory block. */ struct MemHead { typedef decltype(typeid(char).hash_code()) TypeID; Long n_indx; Long n_elem; Long type_size; Long alloc_ctr; TypeID type_id; #ifdef SCTL_MEMDEBUG unsigned char check_sum; #endif }; /** * \brief Constructor for MemoryManager. */ explicit MemoryManager(Long N); /** * \brief Constructor for MemoryManager. */ ~MemoryManager(); static MemHead& GetMemHead(char* p); static void CheckMemHead(const MemHead& p); Iterator malloc(const Long n_elem, const Long type_size = sizeof(char), const MemHead::TypeID type_id = typeid(char).hash_code()) const; void free(Iterator p) const; void print() const; static void test(); // Check all free memory equals init_mem_val void Check() const; // A global MemoryManager object. This is the default for aligned_new and aligned_free static MemoryManager& glbMemMgr() { static MemoryManager m(SCTL_GLOBAL_MEM_BUFF * 1024LL * 1024LL); return m; } private: // Private constructor MemoryManager(); // Private copy constructor MemoryManager(const MemoryManager& m); /** * \brief Node structure for a doubly linked list, representing free and * occupied memory blocks. Blocks are split, merged or state is changed * between free and occupied in O(1) time given the pointer to the MemNode. */ struct MemNode { bool free; Long size; char* mem_ptr; Long prev, next; std::multimap::iterator it; }; /** * \brief Return index of one of the available MemNodes from node_stack or * create new MemNode by resizing node_buff. */ Long new_node() const; /** * \brief Add node index for now available MemNode to node_stack. */ void delete_node(Long indx) const; char* buff; // pointer to memory buffer. Long buff_size; // total buffer size in bytes. Long n_dummy_indx; // index of first (dummy) MemNode in link list. mutable std::vector node_buff; // storage for MemNode objects, this can only grow. mutable std::stack node_stack; // stack of available free MemNodes from node_buff. mutable std::multimap free_map; // pair (MemNode.size, MemNode_id) for all free MemNodes. //mutable omp_lock_t omp_lock; // openmp lock to prevent concurrent changes. //mutable std::mutex mutex_lock; mutable std::set system_malloc; // track pointers allocated using system malloc. }; inline uintptr_t align_ptr(uintptr_t ptr) { const uintptr_t ALIGN_MINUS_ONE = SCTL_MEM_ALIGN - 1; const uintptr_t NOT_ALIGN_MINUS_ONE = ~ALIGN_MINUS_ONE; return ((ptr + ALIGN_MINUS_ONE) & NOT_ALIGN_MINUS_ONE); } /** * \brief Aligned allocation as an alternative to new. Uses placement new to * construct objects. */ template Iterator aligned_new(Long n_elem = 1, const MemoryManager* mem_mgr = &MemoryManager::glbMemMgr()); /** * \brief Aligned de-allocation as an alternative to delete. Calls the object * destructor. */ template void aligned_delete(Iterator A, const MemoryManager* mem_mgr = &MemoryManager::glbMemMgr()); /** * \brief Wrapper to memcpy. Also checks if source and destination pointers are * the same. */ template Iterator memcopy(Iterator destination, ConstIterator source, Long num); template Iterator memset(Iterator ptr, int value, Long num); } // end namespace SCTL_NAMESPACE #include SCTL_INCLUDE(mem_mgr.txx) #endif //_SCTL_MEM_MGR_HPP_