1 /**
2  * ae.sys.dataio
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <vladimir@thecybershadow.net>
12  */
13 
14 module ae.sys.dataio;
15 
16 import ae.sys.data;
17 
18 // ************************************************************************
19 
20 static import std.stream;
21 
22 Data readStreamData(std.stream.Stream s)
23 {
24 	auto size = s.size - s.position;
25 	assert(size < size_t.max);
26 	auto data = Data(cast(size_t)size);
27 	s.readExact(data.mptr, data.length);
28 	return data;
29 }
30 
31 Data readData(string filename)
32 {
33 	scope file = new std.stream.File(filename);
34 	scope(exit) file.close();
35 	return readStreamData(file);
36 }
37 
38 // ************************************************************************
39 
40 static import std.stdio;
41 
42 Data readFileData(ref std.stdio.File f)
43 {
44 	Data buf = Data(1024*1024);
45 	Data result;
46 	while (!f.eof())
47 		result ~= f.rawRead(cast(ubyte[])buf.mcontents);
48 	buf.deleteContents();
49 	return result;
50 }
51 
52 // ************************************************************************
53 
54 /// Wrapper for Data class, allowing an object to be swapped to disk
55 /// and automatically retreived as required.
56 
57 final class SwappedData
58 {
59 	import std.file;
60 	import std.string;
61 	debug(SwappedData) import ae.sys.log;
62 
63 private:
64 	Data _data;
65 	string fileName;
66 	const(char)* cFileName;
67 
68 	static const MIN_SIZE = 4096; // minimum size to swap out
69 
70 	debug(SwappedData) static Logger log;
71 
72 public:
73 	this(string fileName)
74 	{
75 		debug(SwappedData) { if (log is null) log = new FileAndConsoleLogger("SwappedData"); log(fileName ~ " - Creating"); }
76 		this.fileName = fileName;
77 		cFileName = fileName.toStringz();
78 		if (exists(fileName))
79 			remove(fileName);
80 	}
81 
82 	void unload()
83 	{
84 		if (!_data.empty && _data.length >= MIN_SIZE)
85 		{
86 			debug(SwappedData) log(fileName ~ " - Unloading");
87 			write(fileName, _data.contents);
88 			_data.clear();
89 		}
90 	}
91 
92 	bool isLoaded()
93 	{
94 		return !exists(fileName);
95 	}
96 
97 	// Getter
98 	Data data()
99 	{
100 		if (!_data.length)
101 		{
102 			debug(SwappedData) log(fileName ~ " - Reloading");
103 			if (!exists(fileName))
104 				return Data();
105 			_data = readData(fileName);
106 			remove(fileName);
107 		}
108 		return _data;
109 	}
110 
111 	// Setter
112 	void data(Data data)
113 	{
114 		debug(SwappedData) log(fileName ~ " - Setting");
115 		if (exists(fileName))
116 			remove(fileName);
117 		_data = data;
118 	}
119 
120 	size_t length()
121 	{
122 		if (!_data.empty)
123 			return _data.length;
124 		else
125 		if (exists(fileName))
126 			return cast(size_t)getSize(fileName);
127 		else
128 			return 0;
129 	}
130 
131 	~this()
132 	{
133 		// Can't allocate in destructors.
134 
135 		//debug(SwappedData) log(fileName ~ " - Destroying");
136 		/*if (exists(fileName))
137 		{
138 			debug(SwappedData) log(fileName ~ " - Deleting");
139 			remove(fileName);
140 		}*/
141 		core.stdc.stdio.remove(cFileName);
142 	}
143 }