std.experimental.perpetual



struct Perpetual(T);
Creates an object mapped to a file. The object is persistent and outlives the parent application. The file may be reopened and the object reused, it's value persists. This might be viewed as kind of binary serialization with the difference that access to the variable is almost as fast as any regular memory. The structure might be also used as memory shared between processes/threads, however, no built-in synchronization is provided.

If the template parameter T is immutable, the created object is also immutable. Note: shared memory is then created in read-only mode, so even cast to mutable and attempt to modify it will cause segmentation fault.

The Perpetual(T) exists in two forms. When T is regular value type (including static arrays), Persistent(T) behaves like reference to the object. In the second form, Persistent(T[]), the class behaves as proxy to dynamic array providing slicing interface. Note, even in this case, elements of the array must be value type, no pointers nor references to process's memory allowed.

The values created are initialized with std.conv.emplace using additional arguments if any. The object remains in valid state until the file is deleted or modified.

Examples:
import std.stdio;
import std.file : remove, exists, deleteme;

// custom data examples
struct A { int x; };
class B {};
enum Color { black, red, green, blue, white };

string[] file;
foreach(i; 0..8) file~=deleteme~to!string(i);
scope(exit) foreach(f; file[]) if(exists(f)) remove(f);

/// Part 1: create mapped variables
{
    // simle int variable initialized with default value
    auto p0=Perpetual!int(file[0]);
    assert(p0 == int.init);
    p0=7;
    assert(p0 == 7);

    // single double value initialized in ctor
    // , would throw if the file did exist.
    auto p1=Perpetual!double(file[1], 2.71828);
    assert(p1 == 2.71828);
    p1=3.14159;

    // struct, initialized in ctor
    auto p2=Perpetual!A(file[2], 22);
    assert(p2.x == 22);
   
    // static array of integers, assignable
    auto p3=Perpetual!(int[5])(file[3]);
    assert(p3[0] == int.init);
    p3=[1,3,5,7,9];
    assert(p3[0] == 1);

    // enum, initialized in ctor
    auto p4=Perpetual!Color(file[4], Color.red);
    assert(p4 == Color.red);
    

    // character string
    auto p5=Perpetual!(char[32])(file[5]);
    p5="hello world";

    // second order static array
    auto p8=Perpetual!(char[3][5])(file[6]);
    p8[]="..."; p8[1]="one"; p8[2]="two";


    /// Compile time errors
    // char* is reference type
    static assert(!is(typeof(Perpetual!(char*)("?"))));
    // B is class, reference type
    static assert(!is(typeof(Perpetual!(B)("?"))));
    // char* is reference type
    static assert(!is(typeof(Perpetual!(char*)("?"))));
    // char*[12] is reference type
    static assert(!is(typeof(Perpetual!(char*[12])("?"))));
    // char[string] is reference type
    static assert(!is(typeof(Perpetual!(char[string])("?"))));
    // char[] is reference type
    static assert(!is(typeof(Perpetual!(char[][])("?"))));
    // char[][3] is reference type
    static assert(!is(typeof(Perpetual!(char[][3])("?"))));
}
/// destroy everything and unmap files



/// Part 2: map again and check the values are preserved
{
    // Was previosly mapped as int and assigned 7
    auto p0=Perpetual!int(file[0]);
    assert(p0 == 7);
    // int cannot be emplaced from a double
    static assert(!is(typeof(Perpetual!int("?", 1.0))));
    /// attempt to initialize immutable array
    static assert(!is(typeof(Perpetual!(immutable(int)[])(3,file[0],34))));
    /// The file was only 4 bytes long
    ///   , immutable storage can't be extended
    assertThrown(Perpetual!(immutable(int)[])(3,file[0]));

    /// This works, extend the storage and 
    ///  init appended tail, but not existing part
    auto p1=Perpetual!(int[])(3,file[0],123);
    assert(p1[0] == 7);
    assert(p1[1] == 123);
    assert(p1.length == 3);

    // Was previousli mapped as double and assigned 3.14159
    auto p2=Perpetual!double(file[1]);
    assert(p2 == 3.14159);

    // struct with int member initialized with 22
    auto p3=Perpetual!A(file[2]);
    assert(p3 == A(22));
    
    // Was mapped as int[5], remap as view only array of shorts
    auto p4=Perpetual!(immutable(short[]))(file[3]);
    assert(p4.length == 10);
    // Assuming LSB
    assert(p4[0] == 1 && p4[2] == 3 && p4[4] == 5);
    // cannot modify immutable expression
    static assert(!is(typeof(p4[1]=111)));

    // enum, was set to Color.red
    auto p5=Perpetual!Color(file[4]);
    assert(p5 == Color.red);

    // view only variant of char[4]
    auto p6=Perpetual!string(4, file[5]);
    assert(p6 == "hell");
    // cannot modify immutable expression
    static assert(!is(typeof(p6[0]='A')));
    // slice is not mutable
    static assert(!is(typeof(p6[]="1234")));

    // remap second order array as plain array
    auto p7=Perpetual!(const(char[]))(file[6]);
    assert(p7.length == 15);
    assert(p7[0..5] == "...on");
    // map again as dynamic array
    auto p8=Perpetual!(char[3][])(file[6]);
    assert(p8.length == 5);
    assert(p8[2] == "two");
    // Array lengths don't match for copy: 4 != 3
    //p8[0]="null";

    // write-protected file
    { File(file[7],"w").write("12345678"); }
    chmod(file[7].toStringz, octal!444);
    // mutable array can't be mapped on read-only file 
    assertThrown(Perpetual!(int[])(file[7]));
    // immutable array can be mapped
    auto p9=Perpetual!(immutable(int)[])(file[7]);
    assert(p9.length == 2);

}


@property Element[] Ref();
Proxy to underlying dynamic array type. Forwards calls to opSlice(), length() etc

const @property void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt);
Convert to string the value, not the class itself

const @property auto initIndex();
Index of uninitialized part of the array

const @property auto master();
If whole or part of the file was created and was initialized in constructor, return true. For scalar types this means, the entire object was constructed. For dynamic arrays initIndex() shows first initialized elsement.

this(Arg...)(string path, Arg arg);
Universal constructor, for both scalar and array types. Opens file and assosiates object with it. The file is extended if required. The object is initialized if file was created or extended.

this(Arg...)(size_t len, string path, Arg arg) if (dynamic);
Open file and map dynamic array to it. Creates array of requested length, file is extended if necessary

ShMem shMem(string path, size_t len, ShMem.Mode mode = ShMem.Mode.readWrite);
class factory function

ShMem shMem(string path, ShMem.Mode mode = ShMem.Mode.readWrite);
class factory function

Examples:
Using of package scoped shared memory allocator
import std.file : remove, deleteme;


string file=deleteme~"1";
scope(exit) remove(file);


{
    auto s1=shMem(file, 8);
    enforce(s1.master);
    enforce(s1.writeable);
    enforce(s1.unplowed == 0);
    enforce(s1.length == 8);

    int[] i=cast(int[]) s1[];
    enforce(i.length == 2);
    i[0]=12;
    i[1]=13;
}
{
    auto s2=shMem(file, 12);
    enforce(s2.master);
    enforce(s2.writeable);
    enforce(s2.unplowed == 8);
    enforce(s2.length == 12);

    int[] i=cast(int[]) s2[];
    enforce(i.length == 3);
    enforce(i[0] == 12);
    enforce(i[1] == 13);
}
{
    auto s3=shMem(file, 4, ShMem.Mode.readOnly);
    enforce(!s3.master);
    enforce(!s3.writeable);
    enforce(s3.unplowed == 4);
    enforce(s3.length == 4);

    int[] i=cast(int[]) s3[];
    enforce(i.length == 1);
    enforce(i[0] == 12);
}
{
    auto s4=shMem(file);
    enforce(!s4.master);
    enforce(s4.writeable);
    enforce(s4.unplowed == 12);
    enforce(s4.length == 12);
}
{
    assertThrown(shMem(file, 24, ShMem.Mode.readOnly));
}
{
    chmod(toStringz(file), octal!444);
    assertThrown(shMem(file, 24));
}



Page generated by Ddoc.