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 enforce(remaining <= ulong(size_t.max), "File does not fit in memory"); 57 result = Data(cast(size_t)remaining); 58 result.length = f.rawRead(cast(ubyte[])result.mcontents).length; 59 } 60 return result; 61 } 62 63 Data readData(string filename) 64 { 65 auto f = std.stdio.File(filename, "rb"); 66 return readFileData(f); 67 } 68 69 // ************************************************************************ 70 71 /// Wrapper for Data class, allowing an object to be swapped to disk 72 /// and automatically retreived as required. 73 74 final class SwappedData 75 { 76 import std.file; 77 import std.string; 78 debug(SwappedData) import ae.sys.log; 79 80 private: 81 Data _data; 82 string fileName; 83 const(char)* cFileName; 84 85 static const MIN_SIZE = 4096; // minimum size to swap out 86 87 debug(SwappedData) static Logger log; 88 89 public: 90 this(string fileName) 91 { 92 debug(SwappedData) { if (log is null) log = new FileAndConsoleLogger("SwappedData"); log(fileName ~ " - Creating"); } 93 this.fileName = fileName; 94 cFileName = fileName.toStringz(); 95 if (exists(fileName)) 96 remove(fileName); 97 } 98 99 void unload() 100 { 101 if (!_data.empty && _data.length >= MIN_SIZE) 102 { 103 debug(SwappedData) log(fileName ~ " - Unloading"); 104 write(fileName, _data.contents); 105 _data.clear(); 106 } 107 } 108 109 bool isLoaded() 110 { 111 return !exists(fileName); 112 } 113 114 // Getter 115 Data data() 116 { 117 if (!_data.length) 118 { 119 debug(SwappedData) log(fileName ~ " - Reloading"); 120 if (!exists(fileName)) 121 return Data(); 122 _data = readData(fileName); 123 remove(fileName); 124 } 125 return _data; 126 } 127 128 // Setter 129 void data(Data data) 130 { 131 debug(SwappedData) log(fileName ~ " - Setting"); 132 if (exists(fileName)) 133 remove(fileName); 134 _data = data; 135 } 136 137 size_t length() 138 { 139 if (!_data.empty) 140 return _data.length; 141 else 142 if (exists(fileName)) 143 return cast(size_t)getSize(fileName); 144 else 145 return 0; 146 } 147 148 ~this() 149 { 150 // Can't allocate in destructors. 151 152 //debug(SwappedData) log(fileName ~ " - Destroying"); 153 /*if (exists(fileName)) 154 { 155 debug(SwappedData) log(fileName ~ " - Deleting"); 156 remove(fileName); 157 }*/ 158 import core.stdc.stdio : remove; 159 remove(cFileName); 160 } 161 }