Static Arrays in Structs/Classes and Dynamic Array Sizes

2016-01-18 Thread Dennis Croft via Digitalmars-d-learn
I'm trying to organize a large amount of simple data into 
manageable parcels of information that I can access efficiently. 
What I want to do is bake a static array into a class but be 
allowed to do the banking at runtime (because I want each array 
to be a different fixed length). Barring that, I'd like a way to 
fix the size of a dynamic array so that it's exactly the size I 
want and no larger behind the scenes.


Anyone know enough about how these things work in D to help me 
out?


Re: Static Arrays in Structs/Classes and Dynamic Array Sizes

2016-01-18 Thread tsbockman via Digitalmars-d-learn

On Monday, 18 January 2016 at 15:15:46 UTC, Dennis Croft wrote:
I'm trying to organize a large amount of simple data into 
manageable parcels of information that I can access 
efficiently. What I want to do is bake a static array into a 
class but be allowed to do the banking at runtime (because I 
want each array to be a different fixed length). Barring that, 
I'd like a way to fix the size of a dynamic array so that it's 
exactly the size I want and no larger behind the scenes.


Anyone know enough about how these things work in D to help me 
out?


Your description is too abstract for me. Can you give a simple 
code example illustrating what you're trying to do?


It doesn't need to actually compile; just write it how you want 
it to work and I'll see if I can translate it into valid D for 
you.


Re: Static Arrays in Structs/Classes and Dynamic Array Sizes

2016-01-18 Thread Marc Schütz via Digitalmars-d-learn

Here's what I suggest:


alias T = int;

class VariableLengthClass {
private:
string someMember;

size_t length_;
T[0] data_;

public:
static make(Args...)(size_t length, Args args) {
static assert(
typeof(this).init.data_.offsetof == 
__traits(classInstanceSize, typeof(this)),

".data_ must be last member");
import core.memory : GC;
import std.conv : emplace;
const size = __traits(classInstanceSize, typeof(this)) + 
length * typeof(this).init.data_[0].sizeof;

auto buffer = GC.malloc(size, 0, typeid(typeof(this)));
auto result = buffer[0 .. 
size].emplace!(typeof(this))(args);

result.length_ = length;
return result;
}

@property length() const { return length_; }
@trusted ref opIndex(size_t index) inout {
assert(index < length, "index out of bounds");
return data_.ptr[index];
}
size_t opDollar() const { return length_; }
@trusted opSlice() inout {
return data_.ptr[0 .. length];
}
@trusted opSlice(size_t lower, size_t upper) inout {
assert(lower >= 0, "negative indices not allowed");
assert(upper >= lower, "upper bound must be >= lower 
bound");
assert(upper <= length, "upper bound must not be larger 
than length");

return data_.ptr[lower .. upper];
}
}

void main() {
import std.stdio;
auto p = VariableLengthClass.make(20);
//p[6 .. $] = 10;   // 
https://issues.dlang.org/show_bug.cgi?id=15582

p[6] = 1;
writeln(p[5 .. $]);
}


Explanation:

We can't use the `new` operator, because the classes size is only 
known at runtime. Instead, we define a static method `make` that 
takes a length as its first argument, and then the remaining args 
for the constructor. It allocates memory from the GC and calls 
`emplace` to construct the object there.


The actual data can be accessed using the operator 
implementations, to provide some encapsulation and memory safety. 
See the `main()` function for usage examples. Slice assignment 
(commented out) currently doesn't work due to a compiler bug.


Depending on your requirements, other solutions are possible. You 
could, for example, make the class a template and the array 
length a template parameter, then have all instances derive from 
one common base class.


Btw, does anyone know whether it's possible to make `emplace` 
call a private constructor? It would be better to make them 
private to prevent a user from accidentally using `new`...