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 std.exception : enforce; 17 18 import ae.sys.data; 19 20 // ************************************************************************ 21 22 deprecated("std.stream is deprecated, use readFileData") 23 template readStreamData() 24 { 25 static import std.stream; 26 27 Data readStreamData(std.stream.Stream s) 28 { 29 auto size = s.size - s.position; 30 assert(size < size_t.max); 31 auto data = Data(cast(size_t)size); 32 s.readExact(data.mptr, data.length); 33 return data; 34 } 35 } 36 37 // ************************************************************************ 38 39 static import std.stdio; 40 41 Data readFileData(ref std.stdio.File f) 42 { 43 Data result; 44 auto size = f.size; 45 if (size == ulong.max) 46 { 47 Data buf = Data(1024*1024); 48 while (!f.eof()) 49 result ~= f.rawRead(cast(ubyte[])buf.mcontents); 50 buf.deleteContents(); 51 } 52 else 53 { 54 auto pos = f.tell; 55 ulong remaining = size - pos; 56 if (!remaining) 57 return Data(); 58 enforce(remaining <= ulong(size_t.max), "File does not fit in memory"); 59 result = Data(cast(size_t)remaining); 60 result.length = f.rawRead(cast(ubyte[])result.mcontents).length; 61 } 62 return result; 63 } 64 65 Data readData(string filename) 66 { 67 auto f = std.stdio.File(filename, "rb"); 68 return readFileData(f); 69 } 70 71 // ************************************************************************ 72 73 /// Wrapper for Data class, allowing an object to be swapped to disk 74 /// and automatically retreived as required. 75 76 final class SwappedData 77 { 78 import std.file; 79 import std.string; 80 debug(SwappedData) import ae.sys.log; 81 82 private: 83 Data _data; 84 string fileName; 85 const(char)* cFileName; 86 87 static const MIN_SIZE = 4096; // minimum size to swap out 88 89 debug(SwappedData) static Logger log; 90 91 public: 92 this(string fileName) 93 { 94 debug(SwappedData) { if (log is null) log = new FileAndConsoleLogger("SwappedData"); log(fileName ~ " - Creating"); } 95 this.fileName = fileName; 96 cFileName = fileName.toStringz(); 97 if (exists(fileName)) 98 remove(fileName); 99 } 100 101 void unload() 102 { 103 if (!_data.empty && _data.length >= MIN_SIZE) 104 { 105 debug(SwappedData) log(fileName ~ " - Unloading"); 106 write(fileName, _data.contents); 107 _data.clear(); 108 } 109 } 110 111 bool isLoaded() 112 { 113 return !exists(fileName); 114 } 115 116 // Getter 117 Data data() 118 { 119 if (!_data.length) 120 { 121 debug(SwappedData) log(fileName ~ " - Reloading"); 122 if (!exists(fileName)) 123 return Data(); 124 _data = readData(fileName); 125 remove(fileName); 126 } 127 return _data; 128 } 129 130 // Setter 131 void data(Data data) 132 { 133 debug(SwappedData) log(fileName ~ " - Setting"); 134 if (exists(fileName)) 135 remove(fileName); 136 _data = data; 137 } 138 139 size_t length() 140 { 141 if (!_data.empty) 142 return _data.length; 143 else 144 if (exists(fileName)) 145 return cast(size_t)getSize(fileName); 146 else 147 return 0; 148 } 149 150 ~this() 151 { 152 // Can't allocate in destructors. 153 154 //debug(SwappedData) log(fileName ~ " - Destroying"); 155 /*if (exists(fileName)) 156 { 157 debug(SwappedData) log(fileName ~ " - Deleting"); 158 remove(fileName); 159 }*/ 160 import core.stdc.stdio : remove; 161 remove(cFileName); 162 } 163 }