c++虚拟内存

可以通过调用vmemalloc类型对象的括号运算符(len, name)分配大小为len,文件名为name的虚拟内存。
返回首地址的迭代器。
无需delete,程序结束后会自动清空文件,但是保留文件名
模板 vmemalloc 可以对特定类型分配空间,但是要求类型为POD,当类型不为POD时结果未定义

#warning Unsafe content. Deprecated.

/**
 * -O1
 * (SSD DRIVE, LEAST)
 * 1s for 5e5 random access.
 * 1s for 1.3e8 cont access.
 * 1s for 6e4 stable_sort
 * 1s for 2.5e4 sort
 * 1s for 8e3 insection_sort
*/
#include<bits/stdc++.h>
using namespace std;
namespace virtual_memory{
	/** 
	 * small functions to be called by filename.
	*/
	void file_reset(const string& fname, size_t siz){
		ofstream f(fname.c_str(), ios::binary| ios::out | ios::trunc);
		int i = 0;
		// cerr << 1.0 * clock() / CLOCKS_PER_SEC << endl;
		static char buf1[32768 + 10] = {};
		for(; i + 32768 < siz; i += 32768){
			f.write(buf1, 32768);
		}
		static char buf2[128] = {};
		for(; i + 128 < siz; i += 128){
			f.write(buf2, 128);
		}
		char val = 0;
		for(; i < siz; ++i) f.write(&val, 1);
		f.close();
	}
	void file_clear(const string& fname){
		file_reset(fname, 0);
	}
	/**
	 * proxy of a file.
	 * fixed file size.
	 * if a file was opened, the name won't be change.
	 * only opened by a file.
	 * safe write/read
	*/
	struct proxy_file{
		string fname;
		fstream f;
		long long fsize;
		using pos_type = fstream :: pos_type;
		using off_type = fstream :: off_type;
		using seekdir = fstream :: seekdir;
		proxy_file(){
			fsize = 0;
		}
		proxy_file(const string& str, size_t siz) : proxy_file(){
			open(str, siz);
		}
		~proxy_file(){
			file_clear(fname);
		}
		void open(const string& str, size_t siz){
			assert(fname.empty() || str == fname);
			fname = str;
			fsize = siz;
			file_reset(str, siz);
			f.open(fname, ios :: binary | ios::out | ios::in);
			assert(f.good());
		}
		void write_at(const char* str, size_t siz, off_type pos){
			assert(0 <= pos && pos + siz <= fsize);
			// cerr << "bef = " << f.tellp() << endl;
			f.seekp(pos, ios :: beg);
			// cerr << "fat = " << f.tellp() << endl;
			f.write(str, siz);
		}
		void read_at(char * str, size_t siz, off_type pos){
			assert(0 <= pos && pos + siz <= fsize);
			f.seekg(pos, ios :: beg);
			f.read(str, siz);
		}
	};
	/**
	 * a pointer with a full information to read/write the file.
	 * with operator +, -, and so on.
	 * only check whether in the same file. uncheck the range.
	*/
	struct file_pointer{
		proxy_file* file;
		proxy_file :: off_type pos; 
		file_pointer()   {
			file = nullptr;
			pos = 0;
		}
		file_pointer(proxy_file* file_, proxy_file :: off_type pos_) : file(file_), pos(pos_){}
		friend int operator - (const file_pointer& x, const file_pointer& y){
			assert(x.file == y.file);
			return int(x.pos - y.pos);
		}
		friend file_pointer operator + (file_pointer x, ptrdiff_t len){
			x.pos += len;
			return x;
		}
		friend file_pointer operator - (file_pointer x, ptrdiff_t len){
			x.pos -= len;
			return x;
		}
		friend bool operator == (const file_pointer& x, const file_pointer& y){
			return x.file == y.file && x.pos == y.pos;
		}
		friend bool operator < (const file_pointer& x, const file_pointer& y){
			assert(x.file == y.file);
			return x.pos < y.pos;
		}
	};
	/**
	 * a proxy to the proxy_file
	 * because random access is very slow, we have to accelerate it by buffer
	 * safe read/write
	 * safe bounds
	 * FBUF_SIZE MUST BE EVEN.
	*/
	const int FBUF_SIZE = 1e8 * 2;
	struct file_buf{
		char buf[FBUF_SIZE];
		file_pointer first; ptrdiff_t len;
		file_buf(){
			len = 0;
			memset(buf,0, sizeof(buf));
		}
		~file_buf(){
			write_through();
		}
		bool check_in(const file_pointer& p){
			assert(p.file != nullptr);
			return first.file == p.file && first.pos <= p.pos && p.pos < first.pos + len;
		}
		void write_through(){
			if(first.file == nullptr) return;
			first.file->write_at(buf, len, first.pos);
		}
		void read_through(){
			if(first.file == nullptr) return;
			first.file->read_at(buf, len, first.pos);
		}
		void init_buf(const file_pointer& p){
			if(check_in(p)) return;
			write_through();
			assert(0 <= p.pos && p.pos < (p.file->fsize));
			first.file = p.file;
			first.pos = p.pos - FBUF_SIZE / 2 <  0 ? 0 : p.pos - FBUF_SIZE / 2;
			len = min(FBUF_SIZE, int(p.file->fsize - first.pos));
			read_through();
		}
		size_t get_pos(const file_pointer& p){
			init_buf(p);
			return p.pos - first.pos;
		}
		void read(const file_pointer& p, char& val){
			size_t pos = get_pos(p);
			val = buf[pos];
		}
		void write(const file_pointer& p, char val){
			size_t pos = get_pos(p);
			buf[pos] = val;
		}
	};

	struct file_view{
		file_buf * buf;
		file_pointer pos;
		file_view(){
			buf = nullptr;
		}
		file_view(file_buf * buf_, file_pointer pos_) : buf(buf_), pos(pos_) {};
		file_view(const file_view& rhs){
			buf = rhs.buf;
			pos = rhs.pos;
		}
		void read(char &val){
			assert(buf != nullptr);
			buf->read(pos, val);
		}
		void write(char val){
			assert(buf != nullptr);
			buf->write(pos, val);
		}
		friend auto operator - (const file_view& x, const file_view& y){
			assert(x.buf == y.buf);
			return x.pos - y.pos;
		}
		friend file_view operator + (file_view x, ptrdiff_t len){
			x.pos = x.pos +  len;
			return x;
		}
		friend file_view operator - (file_view x, ptrdiff_t len){
			x.pos = x.pos - len;
			return x;
		}
		friend bool operator == (const file_view& x, const file_view& y){
			return x.buf == y.buf && x.pos == y.pos;
		}
		friend bool operator < (const file_view& x, const file_view& y){
			return x.pos < y.pos;
		}
	};
	struct proxy_char{
		file_view f;
		proxy_char(file_view f_) : f(f_){}
		proxy_char& operator = (char val){
			f.write(val);
			return *this;
		}
		operator char(){
			char val;
			f.read(val);
			return val;
		}
	};
	struct file_iterator{
		file_view f;
		file_iterator(file_view f_) : f(f_){}
		file_iterator(file_buf * buf_, file_pointer pos_) : file_iterator(file_view(buf_, pos_)) {
		}
		file_iterator(const file_iterator& it_){
			f = it_.f;
		}
		using iterator_category = random_access_iterator_tag;
		using difference_type = ptrdiff_t;
		using value_type = char;
		using pointer = proxy_char*;
		using reference = proxy_char;
		friend auto operator - (const file_iterator& x, const file_iterator& y){
			return x.f - y.f;
		}
		friend file_iterator operator + (file_iterator x, ptrdiff_t len) {
			x.f = x.f + len;
			return x;
		}
		friend file_iterator operator - (file_iterator x, ptrdiff_t len) {
			x.f = x.f- len;
			return x;
		}
		file_iterator& operator += (ptrdiff_t len){
			*this = *this + len;
			return *this;
		}
		file_iterator& operator -= (ptrdiff_t len){
			*this = *this - len;
			return *this;
		}
		bool friend operator ==(const file_iterator& x, const file_iterator& y){
			return x.f == y.f;
		}
		void operator ++(){
			*this = *this + 1;
		}
		void operator --(){
			*this = *this - 1;
		}
		proxy_char operator *(){
			return proxy_char(f);
		}
		friend bool operator < (const file_iterator& x, const file_iterator& y){
			return x.f < y.f;
		}
	};
	struct proxy_file_pool{
		map<string, proxy_file> data;
		~proxy_file_pool(){
			data = decltype(data)();
		}
		proxy_file* get_file(string name){
			assert(data.count(name));
			return &data[name];
		}
		void create_file(string name, size_t siz){
			assert(data.count(name) == false);
			data[name].open(name, siz);
		}
		bool check_file(string name){
			return data.count(name);
		}
		void erase_file(string name){
			data.erase(name);
		}
	};
	struct vmemalloc_base{
		proxy_file_pool	pool;
		file_buf buf;
		~vmemalloc_base(){
			buf.~file_buf();
			pool.~proxy_file_pool();
		}
		file_iterator operator ()(size_t len,const string& name){
			pool.create_file(name, len);
			return file_iterator(&buf, file_pointer(pool.get_file(name), 0));
		}
	};
	template<typename T>
	struct proxy_type{
		virtual_memory :: file_iterator it;
		proxy_type(file_iterator it_) : it(it_){}
		operator T()const{
			static char buf[sizeof(T)];
			for(int i = 0; i < sizeof(T); ++i) buf[i] = *(it + i);
			return *((T*)(buf));
		}
		proxy_type& operator = (T val){
			const char* buf = (const char*)(&val);
			for(int i = 0; i < sizeof(T); ++i) *(it + i) = buf[i];
			return *this;
		}
		friend void swap(proxy_type lhs, proxy_type rhs){
			T tmp = lhs;
			lhs = T(rhs);
			rhs = tmp;
		}
	};
	template<typename T>
	struct type_iterator{
		file_iterator it;
		type_iterator(const type_iterator<T>& ano) : it(ano.it) {}
		type_iterator(file_iterator it_) : it(it_){}
		type_iterator(file_buf * buf_, file_pointer pos_) : type_iterator(file_iterator(buf_, pos_)) {
		}
		using iterator_category = random_access_iterator_tag;
		using difference_type = ptrdiff_t;
		using value_type = T;
		using pointer = proxy_type<T>*;
		using reference = proxy_type<T>;
		friend int operator - (const type_iterator& x, const type_iterator& y){
			// cout << typeid(x.it - y.it).name() << endl;
			return (x.it - y.it) / sizeof(T);
		}
		friend type_iterator operator + (type_iterator x, ptrdiff_t len) {
			x.it = x.it + len * sizeof(T);
			return x;
		}
		friend type_iterator operator - (type_iterator x, ptrdiff_t len) {
			x.it = x.it - len * sizeof(T);
			return x;
		}
		type_iterator& operator += (ptrdiff_t len){
			*this = *this + len;
			return *this;
		}
		type_iterator& operator -= (ptrdiff_t len){
			*this = *this - len;
			return *this;
		}
		friend bool operator ==(const type_iterator&x, const type_iterator& y){
			return x.it == y.it;
		}
		friend bool operator !=(const type_iterator&x, const type_iterator& y){
			return !(x == y);
		}
		type_iterator& operator ++(){
			*this = *this + 1;
			return *this;
		}
		type_iterator& operator --(){
			*this = *this - 1;
			return *this;
		}
		proxy_type<T> operator *()const{
			return proxy_type<T>(it);
		}
		proxy_type<T> operator [](int x)const{
			return *(*this + x);
		}
		friend bool operator < (const type_iterator& x, const type_iterator& y){
			return x.it < y.it;
		}
	};
	template<typename T>
	struct vmemalloc : vmemalloc_base{
		type_iterator<T> operator ()(size_t count,const string& name){
			pool.create_file(name, count * sizeof(T));
			return type_iterator<T>(file_iterator(&buf, file_pointer(pool.get_file(name), 0)));
		}
	};
}
int main(){
}
posted @ 2023-02-03 21:38  CDsidi  阅读(219)  评论(0编辑  收藏  举报