www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Initalizing complex array types or some other problem ;/

reply Prudence <Pursuit Happyness.All> writes:
How does one initialize a tuple type and are arrays initialized 
by default?


The code below doesn't work. I recently converted to use a tuple 
and that seemed to have broke it and I don't know why, when I 
changed the New function to use a ref, that made it worse cause 
now the array is all ways null. Debugging doesn't help much 
because, for some reason, VD won't show object information inside 
the mixin ObjectStore.


	alias StoreType = Tuple!(TValue, SingleStore!(TKey, 
TValue))[][TKey];
	public static StoreType Store;

I thought using the alias would help but it doesn't. Trying to 
init it in the static this doesn't seem to help me, as I can't 
get it to new propertly. e.g., new StoreType(); fails.

Any ideas?






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;


	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);
					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)(k, v);	// GC
		o.Store = s;
		return o;
	}

	private this(TKey k, TValue v)
	{
		Key = k;
		Value = v;
	}
}


// 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 them specifically.
public mixin template ObjectStore(TKey, TValue)
{
	alias StoreType = Tuple!(TValue, SingleStore!(TKey, 
TValue))[][TKey];
	public static StoreType 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);

class MyStore
{
	mixin ObjectStore!(string, dg);
}

void main()
{

	auto k = "x";
	
	dg d1 = (int x) { return x; };
	dg d2 = (int x) { return x; };
	dg d3 = d1;
	dg d4 = (int x) { return 3*x; };

	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);	
	
	s1.Remove();
	writeln(MyStore.Store[k].length);
	s2.Remove();
	writeln(MyStore.Store[k].length);
	s.Remove();
	writeln(MyStore.Store[k].length);
	s3.Remove();
	


	getch();
}
Sep 15 2015
parent reply anonymous <anonymous example.com> writes:
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); } ---- 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.
Sep 15 2015
parent reply Prudence <Pursuit Happyness.All> writes:
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).
Sep 15 2015
next sibling parent anonymous <anonymous example.com> writes:
On Wednesday 16 September 2015 03:46, Prudence wrote:

 In any case, Maybe you are not as smart as you think you are if 
 you can't understand it?
kthxbye
Sep 15 2015
prev sibling parent Andrea Fontana <nospam example.com> writes:
On Wednesday, 16 September 2015 at 01:46:09 UTC, Prudence wrote:
 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.
"Prudence" seems not to fit well as nickname.
Sep 16 2015