March 18, 2018
On Sunday, 18 March 2018 at 11:29:47 UTC, Joe wrote:
> On Monday, 12 March 2018 at 03:50:42 UTC, Joe wrote:
>> On Monday, 12 March 2018 at 03:13:08 UTC, Seb wrote:
>>> Out of interest: I wonder what's your usecase for using qsort. Or in other words: why you can't use the high-level std.algorithm.sorting.sort?
>>
>> This is only temporary. I will be using std.algorithm.sorting.sort. I was converting a C program and it annoyed me that I couldn't get the qsort invocation past the D compiler.
>
> Now that I'm trying to use std.algorithm.sorting, I'm again puzzled by what I need to use for the "less" predicate. My first try was:
>
>    sort!((a, b) => to!string((*a).name) < to!string((*b).name))(recs);
>
> This results in the error:
>
> Error: template std.algorithm.sorting.sort cannot deduce function from argument types !((a, b) => to!string((*a).name) < to!string((*b).name))(Record*[10]),

This basically says you have fixed size array, in D they don’t decay to slices/pointers for safety reasons (it’s stack memory that is easy to leak out of scope with disasterous consequences).

Do this to get the usual ptr + length:

sort!((a, b) => to!string((*a).name) < to!string((*b).name))(recs[]);

Also to!string would be computed on each compare anew. May want to use schwartzSort to avoid that, on 10 elements there is no real difference though.

March 18, 2018
On Sunday, 18 March 2018 at 13:10:08 UTC, Dmitry Olshansky wrote:
> Do this to get the usual ptr + length:
>
> sort!((a, b) => to!string((*a).name) < to!string((*b).name))(recs[]);
>
> Also to!string would be computed on each compare anew. May want to use schwartzSort to avoid that, on 10 elements there is no real difference though.

The 10 elements are just because it's a small test program.

What does changing "recs" to "recs[]" as the argument actually do?  Does it duplicate the fixed array on the fly? [I guess I have to study more!]

The change does pass the compiler, but at runtime it causes a segfault.  The next to last frame in the backtrace shows (having changed from to!string to fromStringz and using a string template instead of a lambda):

#6  0x0000555555565760 in std.algorithm.sorting.sort!("fromStringz((*a).name.ptr) < fromStringz((*b).name.ptr)", 0, testd.Record*[]).sort(testd.Record*[]) (r=...)

Then it goes through quickSortImpl, shortSort and sort5, moving on to either std.functional.binaryFun or processing of the lambda, with a and b equal to 0, ending with a segfault in a ?? call from fromStringz or in memcpy called from object._dup (in the to!string case).
March 18, 2018
On Sunday, 18 March 2018 at 16:45:16 UTC, Joe wrote:
> On Sunday, 18 March 2018 at 13:10:08 UTC, Dmitry Olshansky wrote:
>> Do this to get the usual ptr + length:
>>
>> sort!((a, b) => to!string((*a).name) < to!string((*b).name))(recs[]);
>>
>> Also to!string would be computed on each compare anew. May want to use schwartzSort to avoid that, on 10 elements there is no real difference though.
>
> The 10 elements are just because it's a small test program.
>
> What does changing "recs" to "recs[]" as the argument actually do?  Does it duplicate the fixed array on the fly? [I guess I have to study more!]

No it just creates a pair of pointer to recs[0] + length of recs, like this:

struct Array
{
  size_t length;
  Record* ptr;
}

In D it’s typed as Record[] and has a number of nice properties, like not losing its length;)

> The change does pass the compiler, but at runtime it causes a segfault.  The next to last frame in the backtrace shows (having changed from to!string to fromStringz and using a string template instead of a lambda):

Well since recs is array of pointers this looks like a null pointer in your data.

The usual ways to fix that is either print stuff or poke around in debugger to see if a Record* is null or .name is null.

> #6  0x0000555555565760 in std.algorithm.sorting.sort!("fromStringz((*a).name.ptr) < fromStringz((*b).name.ptr)", 0, testd.Record*[]).sort(testd.Record*[]) (r=...)
>

Also you don’t need (*a).name, D understands that . can access data through pointer (what would be an error in C and require ->).

> Then it goes through quickSortImpl, shortSort and sort5, moving on to either std.functional.binaryFun or processing of the lambda, with a and b equal to 0, ending with a segfault in a ?? call from fromStringz or in memcpy called from object._dup (in the to!string case).

March 18, 2018
On Sunday, 18 March 2018 at 18:11:02 UTC, Dmitry Olshansky wrote:
> On Sunday, 18 March 2018 at 16:45:16 UTC, Joe wrote:
>> [...]
>
> No it just creates a pair of pointer to recs[0] + length of recs, like this:
>
> struct Array
> {
>   size_t length;
>   Record* ptr;
> }
>
> In D it’s typed as Record[] and has a number of nice properties, like not losing its length;)
>
>> [...]
>
> Well since recs is array of pointers this looks like a null pointer in your data.

Or rather if 10 is capacity and num_recs is actual length, then:

recs[0..num_recs] is the slice with data that you want to sort.


March 18, 2018
On Sunday, 18 March 2018 at 18:11:02 UTC, Dmitry Olshansky wrote:
> Well since recs is array of pointers this looks like a null pointer in your data.
>
> The usual ways to fix that is either print stuff or poke around in debugger to see if a Record* is null or .name is null.

The problem is that although the "recs" array is declared as having 10 pointers, not all pointers are used.  In the qsort case, the second argument limited the sort to just the first n_recs (valid) pointers. There doesn't seem to be a way to tell std.algorithm.sorting.sort to only look at part of the fixed array.

I managed to get it working by declaring a D dynamic array, appending n_recs pointers to it and using it as argument to sort. Unfortunately, I then had to copy from the dynamic array to the fixed array in order to continue using the latter. Any shortcuts around this?

March 18, 2018
On Sunday, 18 March 2018 at 19:01:11 UTC, Joe wrote:
> I managed to get it working by declaring a D dynamic array, appending n_recs pointers to it and using it as argument to sort. Unfortunately, I then had to copy from the dynamic array to the fixed array in order to continue using the latter. Any shortcuts around this?

I just saw your other reply.  Passing recs[0..n_recs] does the trick. Thanks.
1 2
Next ›   Last »