On Tuesday, 15 September 2015 at 20:54:49 UTC, anonymous wrote:
On Tuesday 15 September 2015 22:09, Prudence wrote:
The code below doesn't work.
Please be more specific in how it doesn't work. Mention the
error message if there is one, or say how the code behaves
differently from what you'd expect.
Trying to compile the code (after kicking getch out), I get
this error:
core.exception.RangeError@test.d(103): Range violation
Line 103 is: writeln(MyStore.Store[k].length);
I can't find where you set Store[k]. Maybe you forgot that or
deleted it accidentally?
I made a guess and added this line in SingleStore.New:
o.Store[k] ~= tuple(v, o);
It still throws a range error with this. That's because
associative arrays are a little weird, unfortunately.
An AA is effectively initialized on the first assignment. So
(with my addition) the first SingleStore.New call initializes
the AA. But it only initializes o.Store, not the original
variable s (i.e. ObjectStore.Store). s is left empty.
Possible solutions/workarounds:
* Append to s[k], then assign s to o.Store.
* Initialize ObjectStore.Store in a static constructor:
----
static this()
{
Store[TKey.init] = [];
Store.remove(TKey.init);
}
Maybe. Seems to work without it. The code below should compile on
your system and work(and prints 1 2 3 4, 4 3 2 1). The getch is
required on windows if I want to see the output, so I don't know
why you even bothered mention replacing it.
import std.stdio;
import std.concurrency;
extern (C) int getch();
import std.string;
import std.concurrency;
import core.time;
import core.thread;
import std.container.array;
import std.typecons;
public class SingleStore(TKey, TValue)
{
public TValue Value;
public TKey Key;
public Tuple!(TValue, SingleStore!(TKey, TValue))[][TKey] Store;
// Duplicate entries will be removed together as there is no way
to distinguish them
public auto Remove()
{
import std.algorithm;
if (Value == null || Key == null) return;
int count = 0;
for(int i = 0; i < Store[Key].length; i++)
{
if (Store[Key][i][0] == Value && Store[Key][i][1] ==
this)
{
count++;
Store[Key][i] = tuple(null, null); // Set to null to release
any references if necessary
swap(Store[Key][i], Store[Key][max(0, Store[Key].length -
count)]);
i = i - 1;
}
}
if (count == 1 && Store[Key].length == 1)
{
Store[Key] = null;
Store.remove(Key);
} else
//Store[Key] =
Store[Key][0..max(0,Store[Key].length-count)];
Store[Key].length = Store[Key].length - count;
Value = null;
Key = null;
}
public static auto New(TKey k, TValue v, ref Tuple!(TValue,
SingleStore!(TKey, TValue))[][TKey] s)
{
auto o = new SingleStore!(TKey, TValue)(); // GC
o.Key = k;
o.Value = v;
s[k] ~= tuple(v, o);
o.Store = s;
return o;
}
}
// Creates a static Associative Array that stores multiple values
per key. The object returned by New can then be used to remove
the key/value without having to remember specifically them.
public mixin template ObjectStore(TKey, TValue)
{
// The object store. It is static. Mixin the template into it's
different types to create different types of stores. All objects
of that type are then in the same store.
public static Tuple!(TValue, SingleStore!(TKey, TValue))[][TKey]
Store;
public static auto New(TKey k, TValue v)
{
auto r = SingleStore!(TKey, TValue).New(k, v, Store);
return r;
}
}
//alias dg = int delegate(int);
alias dg = string;
public class cMyStore(TKey, TValue)
{
//mixin ObjectStore!(string, dg);
mixin ObjectStore!(string, string);
}
void main()
{
alias MyStore = cMyStore!(string, string);
auto k = "x";
auto r = &MyStore.Store;
/*
dg d1 = (int x) { return x; };
dg d2 = (int x) { return x; };
dg d3 = d1;
dg d4 = (int x) { return 3*x; };
*/
dg d1 = "a1";
dg d2 = "a2";
dg d3 = "a3";
dg d4 = "a4";
auto s = MyStore.New(k, d1);
writeln(MyStore.Store[k].length);
auto s1 = MyStore.New(k, d2);
writeln(MyStore.Store[k].length);
auto s2 = MyStore.New(k, d3);
writeln(MyStore.Store[k].length);
auto s3 = MyStore.New(k, d4);
writeln(MyStore.Store[k].length);
//auto x = MyStore.Store[k][0](3);
//writeln("-" ~ x);
s1.Remove();
writeln(MyStore.Store[k].length);
s2.Remove();
writeln(MyStore.Store[k].length);
s.Remove();
writeln(MyStore.Store[k].length);
s3.Remove();
getch();
}
I went and cleaned it up and somehow the issue miraculously
resolved itself. It must have been from using the static this and
such. The code I pasted had a partial changes trying to get it to
work in the first place.
Aside: I have no idea what you're doing there, but it looks
pretty complicated, to the point that I'd guess that it's more
complicated than necessary.
In any case, Maybe you are not as smart as you think you are if
you can't understand it? Maybe next time you shouldn't assume you
are the oracle of all knowledge and if you can't understand it
then it's bad/wrong.
In fact, it's quite simple to understand for anyone with half a
brain.
Seriously. Don't guess. It's not that complex and it would take
you 5 mins to understand if you wanted. No reason to try and
through your ego in it.
1. AA's can't have multiple values added to a single key(except
with tuple, which becomes bulky to use). Hence the ObjectStore is
a store(a dictionary/AA) that allows one to store multiple values
per key.
e.g.,
Store["x"] ~= "y";
Store["x"] ~= "z";
Store["x"] ~= "q";
2. Because we might store things like delegates/lambda's in the
ObjectStore, or other elements(pointers), the values in the store
under some key may not be unique.
alias d = {int x} { return x; };
Store["x"] ~= d;
Store["x"] ~= d;
Store["x"] ~= d;
Here we have 3 copies of the same element, but the Store allows
non-unique values.
Also, storing a delegate(or any value) requires us to "remember"
it if we ever want to remove it from the store(else how could we
know which one to remove?).
3. Hence, SingleStore wraps the value and in a Singleton(more or
less). When a SingleStore is created(should never be by a user),
it keeps the key, the value inside it(so we don't have to). The
user then keeps around the SingeStore(much easier than a
delegate) and can remove it from the ObjectStore
easily(s.remove()). It is sort of like a momento.
4. But because we have to worry about uniqueness, we store the
values as tuples, the actual value and the SingleStore the value
is associated with. Since there should be a one to one
correspondence. If the value is not unique the SingleStore will
be, which we use as a way to disambiguate values that look the
same.
e.g., what's kinda going on is
Store["x"] ~= tuple(d, uniqueId1);
Store["x"] ~= tuple(d, uniqueId2);
Store["x"] ~= tuple(d, uniqueId3);
Now, regardless if d is unique, the uniqueId's are unique(as they
are just the ptr's to the different SingleStores that are
created... and they all have different addresses).
5. So, as you can see, it's pretty easy. ObjectStore is just a
store of objects by a key. It allows for multiple values and each
value is unique. It also makes removing the values easy(not as
easy for simple types but easier for complex types like
delegates).
6. Sure there maybe a better way. That isn't the point. I've done
this several times before in .NET and it takes about 5 mins. In D
it has taken 2 days or so(well, only a few hours of work but
still way to long). Partly because D's error messages are crap,
Partly because I'm just getting back into D, and partly because
Visual D doesn't show those static variables which makes it hard
to know what's going on when debugging(since the ObjectStore is
static, VD won't display whats going on with it).
I'm still unsure if the code is safe(I'll have to add checks and
all that) as I do not allocate the value array(every value in the
AA is really an [] of tuples), yet I don't allocate anything(not
the AA, not the [], or the tuple). Seems to work, maybe cause I'm
doing s[k] ~= tuple(v, o); and ~ does the allocation for [] just
like it does for the AA array?
The reason for the mixin should be obvious. It allows one to
create different ObjectStores(since static AA's are used, we have
to use them in different classes. In heritence would just create
one global store, which is probably not what one wants. Obviously
there are other ways but I like the one line code to create a new
store(e.g., how MyStore looks).