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 * Throws exception if EOF reached. 46 */ 47 public T[] rawRead(T)(T[] buffer){ 48 //const size_t remaining = datastream.length - position; 49 if(position + (buffer.length * T.sizeof) <= 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 import std.conv : to; 55 throw new Exception("EOF reached at position " ~ to!string(position)); 56 } 57 } 58 /** 59 * Reads a single element from the stream. 60 * Throws Exception if EOF reached. 61 * Important: Does not provide any complex serialization method, so structs must avoid heap managed fields like dynamic 62 * arrays. They should implement a custom serializer. 63 */ 64 public T read(T)(){ 65 T buffer; 66 if(remaining + T.sizeof <= datastream.length){ 67 memcpy(&buffer, datastream.ptr + position, T.sizeof); 68 position += T.sizeof; 69 return buffer; 70 }else{ 71 throw new Exception("EOF has been reached"); 72 } 73 } 74 /** 75 * Writes data into the datastream. 76 * If the stream is shorter, then it'll be extended. 77 */ 78 public void rawWrite(T)(T[] buffer){ 79 if(buffer.length + position >= datastream.length){ 80 datastream.length = position; 81 datastream.length += buffer.length * T.sizeof; 82 //datastream ~= cast(void[])buffer; 83 }//else{ 84 memcpy(datastream.ptr + position, buffer.ptr, buffer.length * T.sizeof); 85 //} 86 position += buffer.length * T.sizeof; 87 assert(position <= datastream.length); 88 } 89 /** 90 * Writes a single element to the stream. 91 * Throws Exception if EOF reached. 92 * Important: Does not provide any complex serialization method, so structs must avoid heap managed fields like dynamic 93 * arrays. They should implement a custom serializer. 94 */ 95 public T write(T)(T buffer){ 96 if(remaining + T.sizeof <= datastream.length){ 97 memcpy(datastream.ptr + position, &buffer, T.sizeof); 98 position += T.sizeof; 99 return buffer; 100 }else{ 101 throw new Exception("EOF has been reached"); 102 } 103 } 104 /** 105 * Jumps to the given location. 106 */ 107 @nogc @property public void seek(long offset, int origin = SEEK_SET) @trusted{ 108 assert(position <= datastream.length); 109 final switch(origin){ 110 case SEEK_SET: 111 position = cast(sizediff_t)offset; 112 break; 113 case SEEK_CUR: 114 position += cast(sizediff_t)offset; 115 break; 116 case SEEK_END: 117 position = datastream.length + cast(sizediff_t)offset; 118 break; 119 } 120 position = position > datastream.length ? datastream.length : position; 121 } 122 /** 123 * Returns the current position. 124 */ 125 @nogc @property public size_t tell(){ 126 return position; 127 } 128 /** 129 * Returns the size of the datastream. 130 */ 131 @nogc @property public size_t size(){ 132 return datastream.length; 133 } 134 135 } 136 unittest{ 137 immutable string a = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum et libero dignissim, porta odio id, 138 sollicitudin quam. Suspendisse ultrices quis erat nec elementum. Phasellus sollicitudin vehicula nunc, vel 139 laoreet magna dictum eget. Pellentesque sit amet tellus ac mauris elementum bibendum sed in eros. Nullam nec ligula 140 id ligula egestas malesuada. Etiam et nulla nec nibh faucibus suscipit non id felis. Integer vulputate lobortis 141 neque, ut congue nisl suscipit at. Nullam ac ante eu orci viverra dapibus. \n"; 142 immutable string b = "Vivamus quis finibus mi. Proin lectus enim, convallis a libero a, condimentum eleifend nisl. Vestibulum 143 luctus malesuada orci a ornare. Curabitur orci dolor, ultricies ut malesuada nec, semper dictum justo. Ut vestibulum 144 nisl id velit congue, tristique porta sapien rutrum. Pellentesque ultricies id arcu non fermentum. Ut at est ex. Sed 145 elementum gravida risus, et cursus magna tincidunt nec. Morbi hendrerit efficitur neque, non ultricies quam maximus 146 in. Sed bibendum bibendum dui, egestas dignissim orci tincidunt porta. Sed nec aliquet leo, eu posuere massa. \n"; 147 string s; 148 VFile file = VFile(s); 149 file.rawWrite(a); 150 file.rawWrite(b); 151 assert(file.size == a.length + b.length); 152 char[] c; 153 c.length = a.length + b.length; 154 file.seek(0); 155 file.rawRead(c); 156 assert(c == a ~ b); 157 file.seek(0); 158 c.length = 5; 159 file.rawRead(c); 160 assert(c == "Lorem"); 161 }