www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Cleverness of the compiler

reply "Namespace" <rswhite4 googlemail.com> writes:
I love this feature, but I'm unsure how it works. Can someone 
explain me, how the compiler deduce that he should read 4 bytes 
for each index (the 'at' function)? The type is void*, not int*.

----
import std.stdio;
import core.stdc.stdlib : calloc, realloc, free;
import core.stdc.string : memcpy;

struct Tarray {
	void* ptr;
	size_t length;
	size_t capacity;

	~this() {
		.free(this.ptr);
		this.ptr = null;
	}
}

void push(T)(ref Tarray arr, T elem) {
	if (arr.length == arr.capacity)
		arr.reserve(T.sizeof);

	memcpy(&arr.ptr[arr.length++], &elem, T.sizeof);
}

void reserve(ref Tarray arr, size_t typeOf, size_t cap = 0) {
	if (arr.capacity != 0) {
		arr.capacity = cap == 0 ? (arr.capacity * 2) + 1 : arr.capacity 
+ cap;
		arr.ptr = .realloc(arr.ptr, arr.capacity * typeOf);
	} else {
		arr.capacity = cap == 0 ? 3 : cap;
		arr.ptr = .calloc(arr.capacity, typeOf);
	}
}

void at(T)(ref Tarray arr, size_t index, T* elem) {
	if (index >= arr.length || elem is null)
		return;

	memcpy(elem, &arr.ptr[index], T.sizeof);
}

void main() {
	Tarray arr;
	arr.push(42);
	int a;
	arr.at(0, &a);
	writeln(a, "::", arr.length, "::", arr.capacity);
	arr.push(23);
	arr.at(1, &a);
	writeln(a, "::", arr.length, "::", arr.capacity);
	arr.push(1337);
	arr.at(2, &a);
	writeln(a, "::", arr.length, "::", arr.capacity);
	arr.push(ushort.max + 1);
	arr.at(3, &a);
	writeln(a, "::", arr.length, "::", arr.capacity);
}
----
Nov 24 2013
next sibling parent reply "growler" <growlercab gmail.com> writes:
On Monday, 25 November 2013 at 00:08:52 UTC, Namespace wrote:
 I love this feature, but I'm unsure how it works. Can someone 
 explain me, how the compiler deduce that he should read 4 bytes 
 for each index (the 'at' function)? The type is void*, not int*.

 ----
 import std.stdio;
 import core.stdc.stdlib : calloc, realloc, free;
 import core.stdc.string : memcpy;

 struct Tarray {
 	void* ptr;
 	size_t length;
 	size_t capacity;

 	~this() {
 		.free(this.ptr);
 		this.ptr = null;
 	}
 }

 void push(T)(ref Tarray arr, T elem) {
 	if (arr.length == arr.capacity)
 		arr.reserve(T.sizeof);

 	memcpy(&arr.ptr[arr.length++], &elem, T.sizeof);
 }

 void reserve(ref Tarray arr, size_t typeOf, size_t cap = 0) {
 	if (arr.capacity != 0) {
 		arr.capacity = cap == 0 ? (arr.capacity * 2) + 1 : 
 arr.capacity + cap;
 		arr.ptr = .realloc(arr.ptr, arr.capacity * typeOf);
 	} else {
 		arr.capacity = cap == 0 ? 3 : cap;
 		arr.ptr = .calloc(arr.capacity, typeOf);
 	}
 }

 void at(T)(ref Tarray arr, size_t index, T* elem) {
 	if (index >= arr.length || elem is null)
 		return;

 	memcpy(elem, &arr.ptr[index], T.sizeof);
 }

 void main() {
 	Tarray arr;
 	arr.push(42);
 	int a;
 	arr.at(0, &a);
 	writeln(a, "::", arr.length, "::", arr.capacity);
 	arr.push(23);
 	arr.at(1, &a);
 	writeln(a, "::", arr.length, "::", arr.capacity);
 	arr.push(1337);
 	arr.at(2, &a);
 	writeln(a, "::", arr.length, "::", arr.capacity);
 	arr.push(ushort.max + 1);
 	arr.at(3, &a);
 	writeln(a, "::", arr.length, "::", arr.capacity);
 }
 ----
All the calls to 'at' are using T=int (implied), as far as I can tell. ... int a; ... arr.at(0, &a); // tyepof(a) is int so in 'at' T.sizeof = 4. Is this the call to 'at' you're referring to? Cheers
Nov 24 2013
next sibling parent "growler" <growlercab gmail.com> writes:
On Monday, 25 November 2013 at 00:51:47 UTC, growler wrote:
 On Monday, 25 November 2013 at 00:08:52 UTC, Namespace wrote:
 I love this feature, but I'm unsure how it works. Can someone 
 explain me, how the compiler deduce that he should read 4 
 bytes for each index (the 'at' function)? The type is void*, 
 not int*.

 ----
 import std.stdio;
 import core.stdc.stdlib : calloc, realloc, free;
 import core.stdc.string : memcpy;

 struct Tarray {
 	void* ptr;
 	size_t length;
 	size_t capacity;

 	~this() {
 		.free(this.ptr);
 		this.ptr = null;
 	}
 }

 void push(T)(ref Tarray arr, T elem) {
 	if (arr.length == arr.capacity)
 		arr.reserve(T.sizeof);

 	memcpy(&arr.ptr[arr.length++], &elem, T.sizeof);
 }

 void reserve(ref Tarray arr, size_t typeOf, size_t cap = 0) {
 	if (arr.capacity != 0) {
 		arr.capacity = cap == 0 ? (arr.capacity * 2) + 1 : 
 arr.capacity + cap;
 		arr.ptr = .realloc(arr.ptr, arr.capacity * typeOf);
 	} else {
 		arr.capacity = cap == 0 ? 3 : cap;
 		arr.ptr = .calloc(arr.capacity, typeOf);
 	}
 }

 void at(T)(ref Tarray arr, size_t index, T* elem) {
 	if (index >= arr.length || elem is null)
 		return;

 	memcpy(elem, &arr.ptr[index], T.sizeof);
 }

 void main() {
 	Tarray arr;
 	arr.push(42);
 	int a;
 	arr.at(0, &a);
 	writeln(a, "::", arr.length, "::", arr.capacity);
 	arr.push(23);
 	arr.at(1, &a);
 	writeln(a, "::", arr.length, "::", arr.capacity);
 	arr.push(1337);
 	arr.at(2, &a);
 	writeln(a, "::", arr.length, "::", arr.capacity);
 	arr.push(ushort.max + 1);
 	arr.at(3, &a);
 	writeln(a, "::", arr.length, "::", arr.capacity);
 }
 ----
All the calls to 'at' are using T=int (implied), as far as I can tell. ... int a; ... arr.at(0, &a); // tyepof(a) is int so in 'at' T.sizeof = 4. Is this the call to 'at' you're referring to? Cheers
Sorry, T=int should be T=int*
Nov 24 2013
prev sibling parent "Namespace" <rswhite4 googlemail.com> writes:
I meant the function:
----
void at(T)(ref Tarray arr, size_t index, T* elem) {
  	if (index >= arr.length || elem is null)
  		return;

  	memcpy(elem, &arr.ptr[index], T.sizeof);
}
----
-> arr.ptr[index]
Nov 24 2013
prev sibling parent reply Shammah Chancellor <anonymous coward.com> writes:
On 2013-11-25 00:08:50 +0000, Namespace said:

 I love this feature, but I'm unsure how it works. Can someone explain 
 me, how the compiler deduce that he should read 4 bytes for each index 
 (the 'at' function)? The type is void*, not int*.
It doesn't work. That code is buggy. It's overwriting previous elements with new ones. Indexing a void* only moves up by 1 byte. void main() { pragma(msg, void.sizeof) Tarray arr; arr.push(42); int a; arr.at(0, &a); writeln(a, "::", arr.length, "::", arr.capacity); arr.push(23); arr.at(1, &a); writeln(a, "::", arr.length, "::", arr.capacity); arr.push(1337); arr.at(2, &a); writeln(a, "::", arr.length, "::", arr.capacity); writeln(arr.capacity); arr.push(ushort.max); //Write a ushort to test. arr.at(3, &a); //Only works because we're on a little endian platform writeln(a, "::", arr.length, "::", arr.capacity); arr.at(2, &a); writeln(a, "::", arr.length, "::", arr.capacity); }
Nov 24 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Monday, 25 November 2013 at 03:13:48 UTC, Shammah Chancellor 
wrote:
 On 2013-11-25 00:08:50 +0000, Namespace said:

 I love this feature, but I'm unsure how it works. Can someone 
 explain me, how the compiler deduce that he should read 4 
 bytes for each index (the 'at' function)? The type is void*, 
 not int*.
It doesn't work. That code is buggy. It's overwriting previous elements with new ones. Indexing a void* only moves up by 1 byte. void main() { pragma(msg, void.sizeof) Tarray arr; arr.push(42); int a; arr.at(0, &a); writeln(a, "::", arr.length, "::", arr.capacity); arr.push(23); arr.at(1, &a); writeln(a, "::", arr.length, "::", arr.capacity); arr.push(1337); arr.at(2, &a); writeln(a, "::", arr.length, "::", arr.capacity); writeln(arr.capacity); arr.push(ushort.max); //Write a ushort to test. arr.at(3, &a); //Only works because we're on a little endian platform writeln(a, "::", arr.length, "::", arr.capacity); arr.at(2, &a); writeln(a, "::", arr.length, "::", arr.capacity); }
Ok, that calms me down. Thought I had missed something.
Nov 25 2013
parent Shammah Chancellor <anonymous coward.com> writes:
On 2013-11-25 10:34:39 +0000, Namespace said:

 On Monday, 25 November 2013 at 03:13:48 UTC, Shammah Chancellor wrote:
 On 2013-11-25 00:08:50 +0000, Namespace said:
 
 I love this feature, but I'm unsure how it works. Can someone explain 
 me, how the compiler deduce that he should read 4 bytes for each index 
 (the 'at' function)? The type is void*, not int*.
It doesn't work. That code is buggy. It's overwriting previous elements with new ones. Indexing a void* only moves up by 1 byte. void main() { pragma(msg, void.sizeof) Tarray arr; arr.push(42); int a; arr.at(0, &a); writeln(a, "::", arr.length, "::", arr.capacity); arr.push(23); arr.at(1, &a); writeln(a, "::", arr.length, "::", arr.capacity); arr.push(1337); arr.at(2, &a); writeln(a, "::", arr.length, "::", arr.capacity); writeln(arr.capacity); arr.push(ushort.max); //Write a ushort to test. arr.at(3, &a); //Only works because we're on a little endian platform writeln(a, "::", arr.length, "::", arr.capacity); arr.at(2, &a); writeln(a, "::", arr.length, "::", arr.capacity); }
Ok, that calms me down. Thought I had missed something.
Yeah. You had me confused for a bit too. :) Couldn't figure out why Ushort.max was being re-read correctly. I'm use to big-endian platforms. It certainly would have been miraculous if the compiler knew what kind of elements you put in the array to be able to index to the right location. -Shammah
Nov 25 2013