/************************************************************************** * * Copyright 2015 Alexander Trukhin * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #pragma once #include #include #include #include #include #ifdef __unix__ #include #include #include #include #include #include #define ALLOC_CHUNK_SIZE 64 * 1024 * 1024L /* * Allocator that backs up memory with mmaped file * File is grown by ALLOC_CHUNK_SIZE, this new region is mmaped then * Nothing is deallocated */ class MmapedFileBuffer { private: int fd; off_t curChunkSize; const size_t chunkSize; std::list mmaps; void* vptr; MmapedFileBuffer(MmapedFileBuffer const&) = delete; void operator=(MmapedFileBuffer const&) = delete; void newMmap() { int ret = ftruncate(fd, chunkSize * (mmaps.size() + 1)); if (ret < 0) { abort(); } vptr = mmap(NULL, chunkSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, chunkSize * mmaps.size()); mmaps.push_front(vptr); curChunkSize = 0; } public: MmapedFileBuffer() : curChunkSize(0), chunkSize(ALLOC_CHUNK_SIZE & ~(sysconf(_SC_PAGE_SIZE) - 1)) { char templ[] = ".pbtmpXXXXXX"; fd = mkstemp(templ); unlink(templ); newMmap(); } ~MmapedFileBuffer() { close(fd); for (auto &m : mmaps) { munmap(m, chunkSize); } } void* allocate(size_t size) { if ((curChunkSize + size) > chunkSize) { newMmap(); } void* addr = static_cast(vptr) + curChunkSize; curChunkSize += size; return addr; } }; template class MmapAllocator { private: std::shared_ptr file; void* vptr; template friend class MmapAllocator; public: typedef T value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; MmapAllocator() { file = std::make_shared(); }; ~MmapAllocator() { }; template MmapAllocator(const MmapAllocator& other) : file(other.file), vptr(other.vptr) { }; T* allocate(std::size_t n) { return reinterpret_cast(file->allocate(n * sizeof(T))); }; void deallocate(T* p, std::size_t n) {}; template void construct(U* p, Args&&... args) {::new (static_cast(p) ) U (std::forward (args)...);} template void destroy(U* p) {p->~U();} size_type max_size() const { return ALLOC_CHUNK_SIZE / sizeof(T); } template struct rebind { typedef MmapAllocator other; }; }; template bool operator==(const MmapAllocator&, const MmapAllocator&) { return true; } template bool operator!=(const MmapAllocator& a, const MmapAllocator& b) { return !(a==b); } #else // default allocator template using MmapAllocator = std::allocator; #endif