1 module vfile; 2 3 import core.stdc.stdlib; 4 import core.stdc.string : memcpy; 5 import std.stdio; 6 7 /** 8 * Implements the virtual file. 9 */ 10 public struct VFile{ 11 enum Orientation { unknown, narrow, wide } 12 private void[] datastream; 13 private size_t position; 14 private string name; ///mostly a placeholder, but can be set if needed 15 16 /** 17 * Creates a virtual file out from an array. 18 */ 19 public this(T)(ref T[] target, string name = null){ 20 datastream = cast(void[])target; 21 this.name = name; 22 } 23 /** 24 * Creates a virtual file out from a pointer and a length indicator. 25 */ 26 public this(void* ptr, size_t length, string name = null){ 27 datastream = ptr[0..length]; 28 this.name = name; 29 } 30 /** 31 * Indicates if the virtual file is opened. 32 * If the datastream isn't null, it must be open. 33 */ 34 public @safe @property @nogc bool isOpen(){ 35 return datastream !is null; 36 } 37 /** 38 * Closes the datastream. 39 */ 40 public @safe void close(){ 41 datastream = null; 42 } 43 /** 44 * Copies the data into the buffer and moves the file forward the length of the buffer. 45 * Returns null if EOF is reached. 46 */ 47 public T[] rawRead(T)(T[] buffer){ 48 const size_t remaining = datastream.length - position; 49 if(position + buffer.length <= datastream.length){ 50 memcpy(buffer.ptr, datastream.ptr + position, buffer.length * T.sizeof); 51 position += buffer.length * T.sizeof; 52 return buffer; 53 }else{ 54 return null; 55 } 56 } 57 /** 58 * Reads a single element from the stream. 59 * Throws Exception if EOF reached. 60 * Important: Does not provide any complex serialization method, so structs must avoid heap managed fields like dynamic 61 * arrays. They should implement a custom serializer. 62 */ 63 public T read(T)(){ 64 T buffer; 65 if(remaining + T.sizeof <= datastream.length){ 66 memcpy(&buffer, datastream.ptr + position, T.sizeof); 67 position += T.sizeof; 68 return buffer; 69 }else{ 70 throw new Exception("EOF has been reached"); 71 } 72 } 73 /** 74 * Writes data into the datastream. 75 * If the stream is shorter, then it'll be extended. 76 */ 77 public void rawWrite(T)(T[] buffer){ 78 if(position + buffer.length >= datastream.length){ 79 datastream.length = position; 80 datastream.length += buffer.length; 81 } 82 memcpy(datastream.ptr + position, buffer.ptr, buffer.length * T.sizeof); 83 position += buffer.length; 84 assert(position <= datastream.length); 85 } 86 /** 87 * Writes a single element to the stream. 88 * Throws Exception if EOF reached. 89 * Important: Does not provide any complex serialization method, so structs must avoid heap managed fields like dynamic 90 * arrays. They should implement a custom serializer. 91 */ 92 public T write(T)(T buffer){ 93 if(remaining + T.sizeof <= datastream.length){ 94 memcpy(datastream.ptr + position, &buffer, T.sizeof); 95 position += T.sizeof; 96 return buffer; 97 }else{ 98 throw new Exception("EOF has been reached"); 99 } 100 } 101 /** 102 * Jumps to the given location. 103 */ 104 @nogc @property public void seek(long offset, int origin = SEEK_SET) @trusted{ 105 final switch(origin){ 106 case SEEK_SET: 107 position = cast(sizediff_t)offset; 108 break; 109 case SEEK_CUR: 110 position += cast(sizediff_t)offset; 111 break; 112 case SEEK_END: 113 position = datastream.length + cast(sizediff_t)offset; 114 break; 115 } 116 position = position > datastream.length ? datastream.length : position; 117 } 118 /** 119 * Returns the current position. 120 */ 121 @nogc @property public size_t tell(){ 122 return position; 123 } 124 /** 125 * Returns the size of the datastream. 126 */ 127 @nogc @property public size_t size(){ 128 return datastream.length; 129 } 130 131 } 132 unittest{ 133 immutable string a = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum et libero dignissim, porta odio id, 134 sollicitudin quam. Suspendisse ultrices quis erat nec elementum. Phasellus sollicitudin vehicula nunc, vel 135 laoreet magna dictum eget. Pellentesque sit amet tellus ac mauris elementum bibendum sed in eros. Nullam nec ligula 136 id ligula egestas malesuada. Etiam et nulla nec nibh faucibus suscipit non id felis. Integer vulputate lobortis 137 neque, ut congue nisl suscipit at. Nullam ac ante eu orci viverra dapibus. \n"; 138 immutable string b = "Vivamus quis finibus mi. Proin lectus enim, convallis a libero a, condimentum eleifend nisl. Vestibulum 139 luctus malesuada orci a ornare. Curabitur orci dolor, ultricies ut malesuada nec, semper dictum justo. Ut vestibulum 140 nisl id velit congue, tristique porta sapien rutrum. Pellentesque ultricies id arcu non fermentum. Ut at est ex. Sed 141 elementum gravida risus, et cursus magna tincidunt nec. Morbi hendrerit efficitur neque, non ultricies quam maximus 142 in. Sed bibendum bibendum dui, egestas dignissim orci tincidunt porta. Sed nec aliquet leo, eu posuere massa. \n"; 143 string s; 144 VFile file = VFile(s); 145 file.rawWrite(a); 146 file.rawWrite(b); 147 assert(file.size == a.length + b.length); 148 char[] c; 149 c.length = a.length + b.length; 150 file.seek(0); 151 file.rawRead(c); 152 assert(c == a ~ b); 153 file.seek(0); 154 c.length = 5; 155 file.rawRead(c); 156 assert(c == "Lorem"); 157 }