Thread overview | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
November 25, 2013 Cleverness of the compiler | ||||
---|---|---|---|---|
| ||||
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); } ---- |
November 25, 2013 Re: Cleverness of the compiler | ||||
---|---|---|---|---|
| ||||
Posted in reply to Namespace | 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
|
November 25, 2013 Re: Cleverness of the compiler | ||||
---|---|---|---|---|
| ||||
Posted in reply to growler | 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*
|
November 25, 2013 Re: Cleverness of the compiler | ||||
---|---|---|---|---|
| ||||
Posted in reply to growler | 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] |
November 25, 2013 Re: Cleverness of the compiler | ||||
---|---|---|---|---|
| ||||
Posted in reply to Namespace | 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);
}
|
November 25, 2013 Re: Cleverness of the compiler | ||||
---|---|---|---|---|
| ||||
Posted in reply to Shammah Chancellor | 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.
|
November 25, 2013 Re: Cleverness of the compiler | ||||
---|---|---|---|---|
| ||||
Posted in reply to Namespace | 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
|
Copyright © 1999-2021 by the D Language Foundation