commit d2f557455d923afee3d64937784460376c552e32
parent 3e28e92b15b2eb8e8e1953fd2753c64131e8f0bd
Author: Dominik Schmidt <das1993@hotmail.com>
Date: Mon, 22 Feb 2016 23:10:29 +0100
Add a src/-subdirectory
Diffstat:
Makefile | | | 2 | +- |
dfortune.d | | | 318 | ------------------------------------------------------------------------------- |
src/dfortune.d | | | 318 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 319 insertions(+), 319 deletions(-)
diff --git a/Makefile b/Makefile
@@ -2,7 +2,7 @@ DMD=dmd
DFLAGS?=-O
DebugFLAGS?=-g
LIB=dfortune
-SOURCES=dfortune.d
+SOURCES=src/dfortune.d
OBJECTS:=$(patsubst %.d,%.o,$(SOURCES))
DOBJECTS:=$(patsubst %.o,%-debug.o,$(OBJECTS))
diff --git a/dfortune.d b/dfortune.d
@@ -1,318 +0,0 @@
-module dfortune;
-import std.stdio : File;
-import std.bitmanip : bigEndianToNative;
-import std.algorithm : map;
-import core.exception : RangeError;
-import std.range;
-
-/**
- * A struct for retrieving single cookies from a cookiefile
- *
- * Examples:
- * --------
- * Fortune f;
- * f.open("file");
- * scope(exit) f.close();
- * writeln(f.strings[0]);
- * --------
- */
-struct Fortune{
- private static struct Header{
- uint version_;
- uint numstr;
- uint longlen;
- uint shortlen;
- uint flags;
- char delim;
- void read(File f){
- f.seek(0);
- ubyte[getOffset()] off;
- auto red=f.rawRead(off);
- version_=bigEndianToNative!(uint,uint.sizeof)(red[0*uint.sizeof..1*uint.sizeof]);
- numstr=bigEndianToNative!(uint,uint.sizeof)(red[1*uint.sizeof..2*uint.sizeof]);
- longlen=bigEndianToNative!(uint,uint.sizeof)(red[2*uint.sizeof..3*uint.sizeof]);
- shortlen=bigEndianToNative!(uint,uint.sizeof)(red[3*uint.sizeof..4*uint.sizeof]);
- flags=bigEndianToNative!(uint,uint.sizeof)(red[4*uint.sizeof..5*uint.sizeof]);
- delim=red[getOffset()-char.sizeof];
- }
- static size_t getOffset(){
- return 5*uint.sizeof+char.sizeof;
- }
- }
-
- invariant{
- assert(!(table.isOpen ^ content.isOpen));
- }
-
- /**
- * A struct containing Information of a cookie inside a cookiefile
- */
- static struct Cookie{
- ///The absolute position inside the textfile
- size_t pos;
- ///The length of the cookie in bytes
- size_t size;
- }
-
- private Header header;
- private File table,content;
-
- /**
- * Returns a random access range iterating over all cookies inside
- * the cookiefile
- *
- * Returns: A random access Range iterating over all Cookie structures
- */
- @property auto range(){
- return iota(0,header.numstr).map!(a=>getCookie(a));
- }
- unittest{
- static assert(isRandomAccessRange!(typeof(Fortune.range)));
- }
-
- /**
- * Returns a random access range iterating over the text of all cookies inside
- * the cookiefile
- *
- * Returns: A random access Range iterating over all cookies
- */
- @property auto strings(){
- return range.map!(a=>read(a));
- }
- unittest{
- static assert(isRandomAccessRange!(typeof(Fortune.strings)));
- }
-
- /**
- * Initializes the cookiefile pointing to the path file.
- *
- * file and file.dat have to exist!
- *
- * Params:
- * file: The file to open.
- */
- this(string file){
- open(file);
- }
-
- /**
- * Reads and caches the header of the opened dat-file
- */
- public void initialize(){
- header.read(table);
- }
-
- /**
- * Opens "file" and "file.dat", and reads the header.
- *
- * Params:
- * basename: The basename of the files to open
- */
- public void open(string basename){
- table.open(basename~".dat","r");
- content.open(basename,"r");
- initialize();
- }
-
- /**
- * Gets the start of the i-th fortunecookie, or the end(=the size) of
- * the file, if i is one out of bound.
- * This ensures, that we can get the end of the last cookie.
- *
- * Params:
- * i: The number of the cookie
- * Returns: The offset of the i-th fortunecookie
- * Throws: RangeError, if i is out of range
- */
- private size_t getOffset(uint i){
- if(i>header.numstr){
- throw new RangeError("Range violation");
- }
- if(i==header.numstr){
- return cast(uint)content.size;
- }
- table.seek(Header.getOffset()+(i+1)*4-1);
- assert(table.isOpen);
- ubyte[uint.sizeof] b;
- table.rawRead(b);
- return bigEndianToNative!(uint,uint.sizeof)(b);
- }
-
- /**
- * Gets the content from the opened file (See open) from pos to end.
- *
- * Params:
- * pos: The start position to read
- * end: The position to read to.
- * Returns: A GC-Allocated char-array containing the specified slice
- * of the opened cookiefile
- */
- public char[] sliceFile(size_t pos, size_t end)
- in{
- assertOpen();
- }
- body{
- if(pos==end){
- return null;
- }
- content.seek(pos);
- ubyte[] buf=new ubyte[end-pos];
- content.rawRead(buf);
- return cast(char[])buf;
- }
-
- /**
- * Reads the i-th cookie
- * Params:
- * i: The cookie-index
- * Returns: A GC-Allocated char[] buffer.
- */
- public char[] read(uint i){
- Cookie c=getCookie(i);
- return sliceFile(c.pos,c.pos+c.size);
- }
-
- /**
- * Reads the boundaries of the i-th cookie.
- *
- * Params:
- * i: THe cookie-index
- * Returns: A Cookie struct denoting the position of the i-th cookie
- * inside the cookiefile
- */
- public Cookie getCookie(uint i)
- in{
- assertOpen();
- }
- body{
- if(i>=header.numstr){
- throw new RangeError("Range violation");
- }
- size_t pos=getOffset(i);
- size_t end=getOffset(i+1)-1; //-1 to exclude \n
- if(end>pos+2){
- end-=2; //to exclude the following %\n
- }
- return Cookie(pos, end-pos);
- }
-
- /**
- * Reads the boundaries of the i-th cookie.
- *
- * Params:
- * i: THe cookie-index
- * Returns: A Cookie struct denoting the position of the i-th cookie
- * inside the cookiefile
- */
- public char[] read(in ref Cookie c){
- return sliceFile(c.pos,c.pos+c.size);
- }
-
- /**
- * Closes all opened files
- *
- * file and file.dat from the previous call to open, that is.
- */
- public void close(){
- table.close();
- content.close();
- }
-
- /**
- * Wether the files are opened
- */
- @property private bool isOpen(){
- return table.isOpen && content.isOpen;
- }
- ///Ditto
- private void assertOpen(){
- assert(isOpen, "Fortune must be opened before reading");
- }
-}
-
-private auto rajoiner(Range)(Range r)if(isInputRange!(Range) && isRandomAccessRange!(ElementType!(Range))){
- static auto get(Range r, size_t index){
- while(index>=r.front.length){
- index-=r.front.length;
- r.popFront();
- }
-
- return r.front[index];
- }
- size_t length;
- foreach(rr;r){
- length+=rr.length;
- }
- return iota(0,length).map!(a=>get(r,a));
-}
-
-/**
- * An Fortune aggregate type
- *
- * Allows to load multiple fortunefiles and treat it as one.
- *
- * Examples:
- * --------
- * Fortunes f;
- * f~=Fortune("./fvl");
- * f~=Fortune("./bofh_excuses");
- * f.strings.take(10).joiner("\n");
- * f.close();
- * --------
- */
-struct Fortunes{
- Fortune[] fortunes;
-
- alias put=add;
- /**
- * Adds a new Fortunefile by struct
- */
- void add(Fortune f){
- fortunes~=f;
- }
-
- /**
- * Adds a new Fortunefile by file-string
- */
- void add(string f){
- add(Fortune(f));
- }
-
- /**
- * Adds a range of new fortunes
- */
- void add(T)(T r) if(isInputRange!(T) && (is(ElementType!(T)==string) || is(ElementType!(T)==Fortune) )){
- while(!r.empty){
- add(r.front);
- r.popFront();
- }
- }
-
- ref Fortunes opOpAssign(string op)(Fortune f) if(op=="~"){
- add(f);
- return this;
- }
-
-
- /**
- * Returns the aggregate cookie-struct range
- */
- @property auto range(){
- return fortunes.map!((ref a)=>a.range).rajoiner;
- }
- /**
- * Returns the aggregate cookie-string range
- */
- @property auto strings(){
- return fortunes.map!((ref a)=>a.strings).rajoiner;
- }
-
- /**
- * Closes all the fortunefiles
- */
- void close(){
- foreach(f;fortunes){
- f.close();
- }
- }
-}
diff --git a/src/dfortune.d b/src/dfortune.d
@@ -0,0 +1,318 @@
+module dfortune;
+import std.stdio : File;
+import std.bitmanip : bigEndianToNative;
+import std.algorithm : map;
+import core.exception : RangeError;
+import std.range;
+
+/**
+ * A struct for retrieving single cookies from a cookiefile
+ *
+ * Examples:
+ * --------
+ * Fortune f;
+ * f.open("file");
+ * scope(exit) f.close();
+ * writeln(f.strings[0]);
+ * --------
+ */
+struct Fortune{
+ private static struct Header{
+ uint version_;
+ uint numstr;
+ uint longlen;
+ uint shortlen;
+ uint flags;
+ char delim;
+ void read(File f){
+ f.seek(0);
+ ubyte[getOffset()] off;
+ auto red=f.rawRead(off);
+ version_=bigEndianToNative!(uint,uint.sizeof)(red[0*uint.sizeof..1*uint.sizeof]);
+ numstr=bigEndianToNative!(uint,uint.sizeof)(red[1*uint.sizeof..2*uint.sizeof]);
+ longlen=bigEndianToNative!(uint,uint.sizeof)(red[2*uint.sizeof..3*uint.sizeof]);
+ shortlen=bigEndianToNative!(uint,uint.sizeof)(red[3*uint.sizeof..4*uint.sizeof]);
+ flags=bigEndianToNative!(uint,uint.sizeof)(red[4*uint.sizeof..5*uint.sizeof]);
+ delim=red[getOffset()-char.sizeof];
+ }
+ static size_t getOffset(){
+ return 5*uint.sizeof+char.sizeof;
+ }
+ }
+
+ invariant{
+ assert(!(table.isOpen ^ content.isOpen));
+ }
+
+ /**
+ * A struct containing Information of a cookie inside a cookiefile
+ */
+ static struct Cookie{
+ ///The absolute position inside the textfile
+ size_t pos;
+ ///The length of the cookie in bytes
+ size_t size;
+ }
+
+ private Header header;
+ private File table,content;
+
+ /**
+ * Returns a random access range iterating over all cookies inside
+ * the cookiefile
+ *
+ * Returns: A random access Range iterating over all Cookie structures
+ */
+ @property auto range(){
+ return iota(0,header.numstr).map!(a=>getCookie(a));
+ }
+ unittest{
+ static assert(isRandomAccessRange!(typeof(Fortune.range)));
+ }
+
+ /**
+ * Returns a random access range iterating over the text of all cookies inside
+ * the cookiefile
+ *
+ * Returns: A random access Range iterating over all cookies
+ */
+ @property auto strings(){
+ return range.map!(a=>read(a));
+ }
+ unittest{
+ static assert(isRandomAccessRange!(typeof(Fortune.strings)));
+ }
+
+ /**
+ * Initializes the cookiefile pointing to the path file.
+ *
+ * file and file.dat have to exist!
+ *
+ * Params:
+ * file: The file to open.
+ */
+ this(string file){
+ open(file);
+ }
+
+ /**
+ * Reads and caches the header of the opened dat-file
+ */
+ public void initialize(){
+ header.read(table);
+ }
+
+ /**
+ * Opens "file" and "file.dat", and reads the header.
+ *
+ * Params:
+ * basename: The basename of the files to open
+ */
+ public void open(string basename){
+ table.open(basename~".dat","r");
+ content.open(basename,"r");
+ initialize();
+ }
+
+ /**
+ * Gets the start of the i-th fortunecookie, or the end(=the size) of
+ * the file, if i is one out of bound.
+ * This ensures, that we can get the end of the last cookie.
+ *
+ * Params:
+ * i: The number of the cookie
+ * Returns: The offset of the i-th fortunecookie
+ * Throws: RangeError, if i is out of range
+ */
+ private size_t getOffset(uint i){
+ if(i>header.numstr){
+ throw new RangeError("Range violation");
+ }
+ if(i==header.numstr){
+ return cast(uint)content.size;
+ }
+ table.seek(Header.getOffset()+(i+1)*4-1);
+ assert(table.isOpen);
+ ubyte[uint.sizeof] b;
+ table.rawRead(b);
+ return bigEndianToNative!(uint,uint.sizeof)(b);
+ }
+
+ /**
+ * Gets the content from the opened file (See open) from pos to end.
+ *
+ * Params:
+ * pos: The start position to read
+ * end: The position to read to.
+ * Returns: A GC-Allocated char-array containing the specified slice
+ * of the opened cookiefile
+ */
+ public char[] sliceFile(size_t pos, size_t end)
+ in{
+ assertOpen();
+ }
+ body{
+ if(pos==end){
+ return null;
+ }
+ content.seek(pos);
+ ubyte[] buf=new ubyte[end-pos];
+ content.rawRead(buf);
+ return cast(char[])buf;
+ }
+
+ /**
+ * Reads the i-th cookie
+ * Params:
+ * i: The cookie-index
+ * Returns: A GC-Allocated char[] buffer.
+ */
+ public char[] read(uint i){
+ Cookie c=getCookie(i);
+ return sliceFile(c.pos,c.pos+c.size);
+ }
+
+ /**
+ * Reads the boundaries of the i-th cookie.
+ *
+ * Params:
+ * i: THe cookie-index
+ * Returns: A Cookie struct denoting the position of the i-th cookie
+ * inside the cookiefile
+ */
+ public Cookie getCookie(uint i)
+ in{
+ assertOpen();
+ }
+ body{
+ if(i>=header.numstr){
+ throw new RangeError("Range violation");
+ }
+ size_t pos=getOffset(i);
+ size_t end=getOffset(i+1)-1; //-1 to exclude \n
+ if(end>pos+2){
+ end-=2; //to exclude the following %\n
+ }
+ return Cookie(pos, end-pos);
+ }
+
+ /**
+ * Reads the boundaries of the i-th cookie.
+ *
+ * Params:
+ * i: THe cookie-index
+ * Returns: A Cookie struct denoting the position of the i-th cookie
+ * inside the cookiefile
+ */
+ public char[] read(in ref Cookie c){
+ return sliceFile(c.pos,c.pos+c.size);
+ }
+
+ /**
+ * Closes all opened files
+ *
+ * file and file.dat from the previous call to open, that is.
+ */
+ public void close(){
+ table.close();
+ content.close();
+ }
+
+ /**
+ * Wether the files are opened
+ */
+ @property private bool isOpen(){
+ return table.isOpen && content.isOpen;
+ }
+ ///Ditto
+ private void assertOpen(){
+ assert(isOpen, "Fortune must be opened before reading");
+ }
+}
+
+private auto rajoiner(Range)(Range r)if(isInputRange!(Range) && isRandomAccessRange!(ElementType!(Range))){
+ static auto get(Range r, size_t index){
+ while(index>=r.front.length){
+ index-=r.front.length;
+ r.popFront();
+ }
+
+ return r.front[index];
+ }
+ size_t length;
+ foreach(rr;r){
+ length+=rr.length;
+ }
+ return iota(0,length).map!(a=>get(r,a));
+}
+
+/**
+ * An Fortune aggregate type
+ *
+ * Allows to load multiple fortunefiles and treat it as one.
+ *
+ * Examples:
+ * --------
+ * Fortunes f;
+ * f~=Fortune("./fvl");
+ * f~=Fortune("./bofh_excuses");
+ * f.strings.take(10).joiner("\n");
+ * f.close();
+ * --------
+ */
+struct Fortunes{
+ Fortune[] fortunes;
+
+ alias put=add;
+ /**
+ * Adds a new Fortunefile by struct
+ */
+ void add(Fortune f){
+ fortunes~=f;
+ }
+
+ /**
+ * Adds a new Fortunefile by file-string
+ */
+ void add(string f){
+ add(Fortune(f));
+ }
+
+ /**
+ * Adds a range of new fortunes
+ */
+ void add(T)(T r) if(isInputRange!(T) && (is(ElementType!(T)==string) || is(ElementType!(T)==Fortune) )){
+ while(!r.empty){
+ add(r.front);
+ r.popFront();
+ }
+ }
+
+ ref Fortunes opOpAssign(string op)(Fortune f) if(op=="~"){
+ add(f);
+ return this;
+ }
+
+
+ /**
+ * Returns the aggregate cookie-struct range
+ */
+ @property auto range(){
+ return fortunes.map!((ref a)=>a.range).rajoiner;
+ }
+ /**
+ * Returns the aggregate cookie-string range
+ */
+ @property auto strings(){
+ return fortunes.map!((ref a)=>a.strings).rajoiner;
+ }
+
+ /**
+ * Closes all the fortunefiles
+ */
+ void close(){
+ foreach(f;fortunes){
+ f.close();
+ }
+ }
+}