/* * Copyright (c) 2002 * David Maisonave (david@axter.com) * * This material is provided "as is", with absolutely no warranty expressed * or implied. Any use is at your own risk. * * Permission to use or copy this software for any purpose is hereby granted * without fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * * DESCRIPTION: file_vector is a class that is similar to std::vector. * The major difference between std::vector and file_vector, * is that file_vector points to memory to a mapped file. * For information on mapped files see MapViewOfFile for WIN32, * or mmap & munmap for Unix/Linux/POSIX * * * Feel free to email bugs, suggestions, or questions to me at (david@axter.com) */ #if !defined(HEADER_GAURD_FOR_FILE_VECTOR_H_) #define HEADER_GAURD_FOR_FILE_VECTOR_H_ #include #include #include namespace std_axter { class report_error_method { public: virtual void ReportError(int ErrNo, const char* ErrMsg = NULL) = 0; }; class report_error_by_throwing_exception : public report_error_method { public: void ReportError(int ErrNo, const char* ErrMsg) { m_ErrNo = ErrNo; m_ErrMsg = (ErrMsg)?ErrMsg:""; //printf("Error (%i) : %s", ErrNo, m_ErrMsg.c_str()); throw(*this); } int m_ErrNo; std::string m_ErrMsg; }; enum mapped_file_openmode{mapped_file_read = 0, mapped_file_read_write = 1, mapped_file_truncate = 2, mapped_file_dont_grow = 4}; class mapped_file_imp_specific; class mapped_file_generic { public: mapped_file_generic(size_t InitialCapacity, const char* FileName, mapped_file_openmode mode, report_error_method*); ~mapped_file_generic(); void* GetBuffer(); bool ReSize(size_t NewSize); size_t GetSize(); mapped_file_imp_specific *mapped_file; }; template class file_read_write { public: typedef T value_type; typedef value_type* pointer; typedef value_type* iterator; typedef value_type& reference; enum {mapped_file_openmode_value = mapped_file_read_write}; }; template class file_read_only { public: typedef T value_type; typedef const value_type* pointer; typedef const value_type* iterator; typedef const value_type& reference; enum {mapped_file_openmode_value = mapped_file_read}; }; class file_do_truncate { public: enum {mapped_file_openmode_value = mapped_file_truncate}; }; class file_dont_truncate { public: enum {mapped_file_openmode_value = 0}; }; class file_can_grow { public: enum {mapped_file_openmode_value = mapped_file_dont_grow}; }; class file_dont_grow { public: enum {mapped_file_openmode_value = 0}; }; template, class TruncatePolicy_T = file_dont_truncate, class FileGrowPolicy_T = file_can_grow, class ErrRptPolicy_T = report_error_by_throwing_exception, class mapped_file_TYPE = mapped_file_generic> class file_vector { public: typedef ReadWritePolicy_T::value_type value_type; typedef ReadWritePolicy_T::pointer pointer; typedef ReadWritePolicy_T::iterator iterator; typedef ReadWritePolicy_T::reference reference; typedef const value_type* const_pointer; typedef const value_type* const_iterator; typedef const value_type& const_reference; typedef ptrdiff_t difference_type; typedef std::reverse_iterator::value_type> const_reverse_iterator; enum {my_mapped_file_openmode_value = (ReadWritePolicy_T::mapped_file_openmode_value | ReadWritePolicy_T::mapped_file_openmode_value | FileGrowPolicy_T::mapped_file_openmode_value)}; enum {SizeOfType = sizeof(T)}; public: //Example: //file_vector my_file_vector1(1024, "c:\\test_foofoo1.txt"); //file_vector my_file_vector2(256, "/home/bin/test_foofoo1.txt"); ~file_vector(){delete m_report_error_method;} file_vector(const char* FileName, size_t IniCapacity = 16) : m_report_error_method(new ErrRptPolicy_T), MappedFile(IniCapacity*SizeOfType, FileName, (mapped_file_openmode)my_mapped_file_openmode_value, m_report_error_method), MainPtr((iterator)MappedFile.GetBuffer()), Size(0), CurrentCapacity((MappedFile.GetBuffer())?MappedFile.GetSize()/SizeOfType:0) #ifdef DEBUG ,m_InitCapacity(IniCapacity); #endif { static const struct { union only_pod_objects_are_compatible_with_file_vector { char c; T t; // invalid if T is non-POD }; }pod_only_instance; } iterator begin() {return MainPtr;} const_iterator begin() const{return MainPtr;} iterator end() {return MainPtr + Size;} const_iterator end() const{return MainPtr + Size;} reference operator[](size_t n) { return *(begin() + n); } const_reference operator[](size_t n) const { return *(begin() + n); } reference front() { return *begin(); } const_reference front() const { return *begin(); } reference back() { return *(end() - 1); } const_reference back() const { return *(end() - 1); } reference at(size_t n) { return (*this)[n]; } const_reference at(size_t n) const {return (*this)[n]; } std::reverse_iterator rbegin() { return std::reverse_iterator(end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } std::reverse_iterator rend() { return std::reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } size_t size() const { return Size;} size_t max_size() const { return size_t(-1) / sizeof(T); } size_t capacity() const { return CurrentCapacity; } bool empty() const { return (Size == 0);} void reserve(size_t n) { if (!MappedFile.ReSize(n)) { ResetToZero(); } } void pop_back() { MainPtr[Size]->~T(); --Size; } void push_back(const T& Src) { if (!CanAdd()) return; new ((void*)(MainPtr + Size)) T(Src); ++Size; } void clear() { while(begin() != end()) pop_back(); } iterator erase(iterator position) { if (position < end()) { position->~T(); std::copy(position+1, end(), position); --Size; } return end(); } iterator erase(iterator first, iterator last) { if (first < end()) { if (last > end()) last = end(); size_t QtyToRemove = 0; for (iterator i = first;i != last;++i) { i->~T(); ++QtyToRemove; } std::copy(last, end(), first); Size-=QtyToRemove; } return end(); } void resize(size_t n, T x = T()) { if (Size == n) return; if (Size > n) { erase(end() - (Size - n), end()); return; } if (n > CurrentCapacity) { if (!MappedFile.ReSize(n)) { ResetToZero(); return; } } while(Size < n && MainPtr) push_back(x); } iterator insert(iterator it, const T& x = T()) { if (!CanAdd()) return end(); std::copy_backward(it, end(), end()+1); ++Size; new ((void*)(it)) T(x); return it; } void insert(iterator it, size_t n, const T& x) { if (!CanAdd(n)) return; std::copy_backward(it, end(), end()+n); Size+=n; for (iterator i = it;i < it+n;++i) { new ((void*)(i)) T(x); } } void insert(iterator it,const_iterator first, const_iterator last) { size_t QtyToInsert = last-first; if (!CanAdd(QtyToInsert)) return; std::copy_backward(it, end(), end()+QtyToInsert); Size+=QtyToInsert; const_iterator ci = first; for (iterator i = it;i < it+QtyToInsert;++i) { new ((void*)(i)) T(*ci); ++ci; } } void assign(const_iterator first, const_iterator last) { clear(); for (const_iterator i = first;i != last;++i) { push_back(*i); } } void assign(size_t n, const T& x = T()) { clear(); for (size_t i = 0;i < n;++i) { push_back(x); } } void swap(file_vector& Inp) {//Unlike vector::swap, this function does NOT lower capacity std::vector Tmp(Inp.begin(), Inp.end()); Inp.assign(begin(), end()); assign(Tmp.begin(), Tmp.end()); } private: //Don't allow copy constructor file_vector(const file_vector&); //Don't allow assignment operator=(const file_vector&); //Incomplete function get_allocator();// No implimentation for this function void ResetToZero(void) { MainPtr = NULL; Size = 0; CurrentCapacity = 0; } bool CanAdd(int QtyToAdd = 1) { if (Size+QtyToAdd > CurrentCapacity) { if (FileGrowPolicy_T::mapped_file_openmode_value) return false; double NewMaxSize = (CurrentCapacity+QtyToAdd)*2; if (NewMaxSize > max_size()/SizeOfType) { NewMaxSize = max_size()/SizeOfType; } if (NewMaxSize == CurrentCapacity) return false; bool Failed = (!MappedFile.ReSize((size_t)(NewMaxSize*SizeOfType))); if (!Failed) { CurrentCapacity = (size_t)NewMaxSize; } if (Failed || Size+QtyToAdd > CurrentCapacity) { ResetToZero(); return false; } } return true; } report_error_method *m_report_error_method; mapped_file_TYPE MappedFile; iterator MainPtr; size_t Size; size_t CurrentCapacity; #ifdef DEBUG size_t m_InitCapacity; #endif }; template inline typename container_type::iterator insert_to_sorted_container(container_type& c, const typename container_type::value_type& e) { return c.insert( std::upper_bound(c.begin(), c.end(), e) ,e); } } #endif // !defined(HEADER_GAURD_FOR_FILE_VECTOR_H_)